Index: 3rdParty_sources/versions.txt =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/versions.txt,v diff -u -r1.11.2.11 -r1.11.2.12 --- 3rdParty_sources/versions.txt 25 Nov 2014 10:47:02 -0000 1.11.2.11 +++ 3rdParty_sources/versions.txt 15 Dec 2014 10:09:55 -0000 1.11.2.12 @@ -38,7 +38,7 @@ openws 1.5.0 -Quartz 1.5.2 +Quartz 2.2.1 Servlet API 3.1 Index: 3rdParty_sources/quartz/org/quartz/Calendar.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/Calendar.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/Calendar.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/Calendar.java 15 Dec 2014 10:09:46 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,24 +16,29 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ - - package org.quartz; /** - *

- * An interface to be implemented by objects that define spaces of time that - * should be included or excluded from a {@link Trigger}'s - * normal 'firing' schedule. - *

+ * An interface to be implemented by objects that define spaces of time during + * which an associated {@link Trigger} may (not) fire. Calendars + * do not define actual fire times, but rather are used to limit a + * Trigger from firing on its normal schedule if necessary. Most + * Calendars include all times by default and allow the user to specify times + * to exclude. * + *

As such, it is often useful to think of Calendars as being used to exclude a block + * of time - as opposed to include a block of time. (i.e. the + * schedule "fire every five minutes except on Sundays" could be + * implemented with a SimpleTrigger and a + * WeeklyCalendar which excludes Sundays)

+ * + *

Implementations MUST take care of being properly Cloneable + * and Serializable.

+ * * @author James House * @author Juergen Donnerstag */ -public interface Calendar extends java.io.Serializable { +public interface Calendar extends java.io.Serializable, java.lang.Cloneable { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -58,30 +63,30 @@ * Set a new base calendar or remove the existing one. *

*/ - public void setBaseCalendar(Calendar baseCalendar); + void setBaseCalendar(Calendar baseCalendar); /** *

* Get the base calendar. Will be null, if not set. *

*/ - public Calendar getBaseCalendar(); + Calendar getBaseCalendar(); /** *

* Determine whether the given time (in milliseconds) is 'included' by the * Calendar. *

*/ - public boolean isTimeIncluded(long timeStamp); + boolean isTimeIncluded(long timeStamp); /** *

* Determine the next time (in milliseconds) that is 'included' by the * Calendar after the given time. *

*/ - public long getNextIncludedTime(long timeStamp); + long getNextIncludedTime(long timeStamp); /** *

@@ -91,7 +96,7 @@ * * @return null if no description was set. */ - public String getDescription(); + String getDescription(); /** *

@@ -100,5 +105,7 @@ * the description has no meaning to Quartz. *

*/ - public void setDescription(String description); + void setDescription(String description); + + Object clone(); } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/CalendarIntervalScheduleBuilder.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/CalendarIntervalTrigger.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/CriticalSchedulerException.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/CronExpression.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/CronExpression.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/CronExpression.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/CronExpression.java 15 Dec 2014 10:09:46 -0000 1.1.2.1 @@ -1,3 +1,20 @@ +/* + * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + */ + package org.quartz; import java.io.Serializable; @@ -56,7 +73,7 @@ *   * 1-31 *   - * , - * ? / L W C + * , - * ? / L W * * * Month @@ -75,7 +92,7 @@ * * Year (Optional) *   - * empty, 1970-2099 + * empty, 1970-2199 *   * , - * / * @@ -86,7 +103,7 @@ *

* The '?' character is allowed for the day-of-month and day-of-week fields. It * is used to specify 'no specific value'. This is useful when you need to - * specify something in one of the two fileds, but not the other. + * specify something in one of the two fields, but not the other. *

* The '-' character is used to specify ranges For example "10-12" in * the hour field means "the hours 10, 11 and 12". @@ -115,9 +132,10 @@ * day-of-week field by itself, it simply means "7" or * "SAT". But if used in the day-of-week field after another value, it * means "the last xxx day of the month" - for example "6L" - * means "the last friday of the month". When using the 'L' option, it - * is important not to specify lists, or ranges of values, as you'll get - * confusing results. + * means "the last friday of the month". You can also specify an offset + * from the last day of the month, such as "L-3" which would mean the third-to-last + * day of the calendar month. When using the 'L' option, it is important not to + * specify lists, or ranges of values, as you'll get confusing/unexpected results. *

* The 'W' character is allowed for the day-of-month field. This character * is used to specify the weekday (Monday-Friday) nearest the given day. As an @@ -142,15 +160,17 @@ * Other examples: "2#1" = the first Monday of the month and * "4#5" = the fifth Wednesday of the month. Note that if you specify * "#5" and there is not 5 of the given day-of-week in the month, then - * no firing will occur that month. + * no firing will occur that month. If the '#' character is used, there can + * only be one expression in the day-of-week field ("3#1,6#3" is + * not valid, since there are two expressions). *

* + * means "the first day included by the calendar on or after Sunday".--> *

* The legal characters and the names of months and days of the week are not * case sensitive. @@ -159,8 +179,15 @@ * NOTES: *

*

* @@ -169,11 +196,11 @@ * @author Contributions from Mads Henderson * @author Refactoring from CronTrigger to CronExpression by Aaron Craven */ -public class CronExpression implements Serializable, Cloneable { +public final class CronExpression implements Serializable, Cloneable { - private static final long serialVersionUID = 12423409423L; - - protected static final int SECOND = 0; + private static final long serialVersionUID = 12423409423L; + + protected static final int SECOND = 0; protected static final int MINUTE = 1; protected static final int HOUR = 2; protected static final int DAY_OF_MONTH = 3; @@ -182,158 +209,225 @@ protected static final int YEAR = 6; protected static final int ALL_SPEC_INT = 99; // '*' protected static final int NO_SPEC_INT = 98; // '?' - protected static final Integer ALL_SPEC = new Integer(ALL_SPEC_INT); - protected static final Integer NO_SPEC = new Integer(NO_SPEC_INT); + protected static final Integer ALL_SPEC = ALL_SPEC_INT; + protected static final Integer NO_SPEC = NO_SPEC_INT; - protected static Map monthMap = new HashMap(20); - protected static Map dayMap = new HashMap(60); + protected static final Map monthMap = new HashMap(20); + protected static final Map dayMap = new HashMap(60); static { - monthMap.put("JAN", new Integer(0)); - monthMap.put("FEB", new Integer(1)); - monthMap.put("MAR", new Integer(2)); - monthMap.put("APR", new Integer(3)); - monthMap.put("MAY", new Integer(4)); - monthMap.put("JUN", new Integer(5)); - monthMap.put("JUL", new Integer(6)); - monthMap.put("AUG", new Integer(7)); - monthMap.put("SEP", new Integer(8)); - monthMap.put("OCT", new Integer(9)); - monthMap.put("NOV", new Integer(10)); - monthMap.put("DEC", new Integer(11)); + monthMap.put("JAN", 0); + monthMap.put("FEB", 1); + monthMap.put("MAR", 2); + monthMap.put("APR", 3); + monthMap.put("MAY", 4); + monthMap.put("JUN", 5); + monthMap.put("JUL", 6); + monthMap.put("AUG", 7); + monthMap.put("SEP", 8); + monthMap.put("OCT", 9); + monthMap.put("NOV", 10); + monthMap.put("DEC", 11); - dayMap.put("SUN", new Integer(1)); - dayMap.put("MON", new Integer(2)); - dayMap.put("TUE", new Integer(3)); - dayMap.put("WED", new Integer(4)); - dayMap.put("THU", new Integer(5)); - dayMap.put("FRI", new Integer(6)); - dayMap.put("SAT", new Integer(7)); + dayMap.put("SUN", 1); + dayMap.put("MON", 2); + dayMap.put("TUE", 3); + dayMap.put("WED", 4); + dayMap.put("THU", 5); + dayMap.put("FRI", 6); + dayMap.put("SAT", 7); } - private String cronExpression = null; + private final String cronExpression; private TimeZone timeZone = null; - protected transient TreeSet seconds; - protected transient TreeSet minutes; - protected transient TreeSet hours; - protected transient TreeSet daysOfMonth; - protected transient TreeSet months; - protected transient TreeSet daysOfWeek; - protected transient TreeSet years; + protected transient TreeSet seconds; + protected transient TreeSet minutes; + protected transient TreeSet hours; + protected transient TreeSet daysOfMonth; + protected transient TreeSet months; + protected transient TreeSet daysOfWeek; + protected transient TreeSet years; protected transient boolean lastdayOfWeek = false; protected transient int nthdayOfWeek = 0; protected transient boolean lastdayOfMonth = false; protected transient boolean nearestWeekday = false; - protected transient boolean calendardayOfWeek = false; - protected transient boolean calendardayOfMonth = false; + protected transient int lastdayOffset = 0; protected transient boolean expressionParsed = false; - + + public static final int MAX_YEAR = Calendar.getInstance().get(Calendar.YEAR) + 100; + /** - * Constructs a new CronExpression based on the specified - * parameter. - * - * @param cronExpression String representation of the cron expression the - * new object should represent - * @throws java.text.ParseException - * if the string expression cannot be parsed into a valid - * CronExpression - */ - public CronExpression(String cronExpression) throws ParseException { - if (cronExpression == null) { - throw new IllegalArgumentException("cronExpression cannot be null"); - } - - this.cronExpression = cronExpression; - - buildExpression(cronExpression.toUpperCase(Locale.US)); - } - - /** - * Indicates whether the given date satisfies the cron expression. Note that - * milliseconds are ignored, so two Dates falling on different milliseconds - * of the same second will always have the same result here. - * - * @param date the date to evaluate - * @return a boolean indicating whether the given date satisfies the cron - * expression - */ - public boolean isSatisfiedBy(Date date) { - Calendar testDateCal = Calendar.getInstance(); - testDateCal.setTime(date); - testDateCal.set(Calendar.MILLISECOND, 0); - Date originalDate = testDateCal.getTime(); - - testDateCal.add(Calendar.SECOND, -1); - - if (getTimeAfter(testDateCal.getTime()).equals(originalDate)) { - return true; - } else { - return false; - } - } - - /** - * Returns the next date/time after the given date/time which - * satisfies the cron expression. - * - * @param date the date/time at which to begin the search for the next valid - * date/time - * @return the next valid date/time - */ - public Date getNextValidTimeAfter(Date date) { - return getTimeAfter(date); - } - + * Constructs a new CronExpression based on the specified + * parameter. + * + * @param cronExpression String representation of the cron expression the + * new object should represent + * @throws java.text.ParseException + * if the string expression cannot be parsed into a valid + * CronExpression + */ + public CronExpression(String cronExpression) throws ParseException { + if (cronExpression == null) { + throw new IllegalArgumentException("cronExpression cannot be null"); + } + + this.cronExpression = cronExpression.toUpperCase(Locale.US); + + buildExpression(this.cronExpression); + } + /** - *

- * Returns the time zone for which the cronExpression of - * this CronTrigger will be resolved. - *

+ * Constructs a new {@code CronExpression} as a copy of an existing + * instance. + * + * @param expression + * The existing cron expression to be copied */ + public CronExpression(CronExpression expression) { + /* + * We don't call the other constructor here since we need to swallow the + * ParseException. We also elide some of the sanity checking as it is + * not logically trippable. + */ + this.cronExpression = expression.getCronExpression(); + try { + buildExpression(cronExpression); + } catch (ParseException ex) { + throw new AssertionError(); + } + if (expression.getTimeZone() != null) { + setTimeZone((TimeZone) expression.getTimeZone().clone()); + } + } + + /** + * Indicates whether the given date satisfies the cron expression. Note that + * milliseconds are ignored, so two Dates falling on different milliseconds + * of the same second will always have the same result here. + * + * @param date the date to evaluate + * @return a boolean indicating whether the given date satisfies the cron + * expression + */ + public boolean isSatisfiedBy(Date date) { + Calendar testDateCal = Calendar.getInstance(getTimeZone()); + testDateCal.setTime(date); + testDateCal.set(Calendar.MILLISECOND, 0); + Date originalDate = testDateCal.getTime(); + + testDateCal.add(Calendar.SECOND, -1); + + Date timeAfter = getTimeAfter(testDateCal.getTime()); + + return ((timeAfter != null) && (timeAfter.equals(originalDate))); + } + + /** + * Returns the next date/time after the given date/time which + * satisfies the cron expression. + * + * @param date the date/time at which to begin the search for the next valid + * date/time + * @return the next valid date/time + */ + public Date getNextValidTimeAfter(Date date) { + return getTimeAfter(date); + } + + /** + * Returns the next date/time after the given date/time which does + * not satisfy the expression + * + * @param date the date/time at which to begin the search for the next + * invalid date/time + * @return the next valid date/time + */ + public Date getNextInvalidTimeAfter(Date date) { + long difference = 1000; + + //move back to the nearest second so differences will be accurate + Calendar adjustCal = Calendar.getInstance(getTimeZone()); + adjustCal.setTime(date); + adjustCal.set(Calendar.MILLISECOND, 0); + Date lastDate = adjustCal.getTime(); + + Date newDate; + + //FUTURE_TODO: (QUARTZ-481) IMPROVE THIS! The following is a BAD solution to this problem. Performance will be very bad here, depending on the cron expression. It is, however A solution. + + //keep getting the next included time until it's farther than one second + // apart. At that point, lastDate is the last valid fire time. We return + // the second immediately following it. + while (difference == 1000) { + newDate = getTimeAfter(lastDate); + if(newDate == null) + break; + + difference = newDate.getTime() - lastDate.getTime(); + + if (difference == 1000) { + lastDate = newDate; + } + } + + return new Date(lastDate.getTime() + 1000); + } + + /** + * Returns the time zone for which this CronExpression + * will be resolved. + */ public TimeZone getTimeZone() { - if (timeZone == null) timeZone = TimeZone.getDefault(); + if (timeZone == null) { + timeZone = TimeZone.getDefault(); + } return timeZone; } /** - *

- * Sets the time zone for which the cronExpression of this - * CronTrigger will be resolved. - *

+ * Sets the time zone for which this CronExpression + * will be resolved. */ public void setTimeZone(TimeZone timeZone) { this.timeZone = timeZone; } - - /** - * Returns the string representation of the CronExpression - * - * @return a string representation of the CronExpression - */ - public String toString() { - return cronExpression; - } - - /** - * Indicates whether the specified cron expression can be parsed into a - * valid cron expression - * - * @param cronExpression the expression to evaluate - * @return a boolean indicating whether the given expression is a valid cron - * expression - */ - public static boolean isValidExpression(String cronExpression) { - - try { - new CronExpression(cronExpression); - } catch (ParseException pe) { - return false; - } - - return true; - } - + + /** + * Returns the string representation of the CronExpression + * + * @return a string representation of the CronExpression + */ + @Override + public String toString() { + return cronExpression; + } + + /** + * Indicates whether the specified cron expression can be parsed into a + * valid cron expression + * + * @param cronExpression the expression to evaluate + * @return a boolean indicating whether the given expression is a valid cron + * expression + */ + public static boolean isValidExpression(String cronExpression) { + + try { + new CronExpression(cronExpression); + } catch (ParseException pe) { + return false; + } + + return true; + } + + public static void validateExpression(String cronExpression) throws ParseException { + + new CronExpression(cronExpression); + } + + //////////////////////////////////////////////////////////////////////////// // // Expression Parsing Functions @@ -345,13 +439,27 @@ try { - if (seconds == null) seconds = new TreeSet(); - if (minutes == null) minutes = new TreeSet(); - if (hours == null) hours = new TreeSet(); - if (daysOfMonth == null) daysOfMonth = new TreeSet(); - if (months == null) months = new TreeSet(); - if (daysOfWeek == null) daysOfWeek = new TreeSet(); - if (years == null) years = new TreeSet(); + if (seconds == null) { + seconds = new TreeSet(); + } + if (minutes == null) { + minutes = new TreeSet(); + } + if (hours == null) { + hours = new TreeSet(); + } + if (daysOfMonth == null) { + daysOfMonth = new TreeSet(); + } + if (months == null) { + months = new TreeSet(); + } + if (daysOfWeek == null) { + daysOfWeek = new TreeSet(); + } + if (years == null) { + years = new TreeSet(); + } int exprOn = SECOND; @@ -360,6 +468,19 @@ while (exprsTok.hasMoreTokens() && exprOn <= YEAR) { String expr = exprsTok.nextToken().trim(); + + // throw an exception if L is used with other days of the month + if(exprOn == DAY_OF_MONTH && expr.indexOf('L') != -1 && expr.length() > 1 && expr.contains(",")) { + throw new ParseException("Support for specifying 'L' and 'LW' with other days of the month is not implemented", -1); + } + // throw an exception if L is used with other days of the week + if(exprOn == DAY_OF_WEEK && expr.indexOf('L') != -1 && expr.length() > 1 && expr.contains(",")) { + throw new ParseException("Support for specifying 'L' with other days of the week is not implemented", -1); + } + if(exprOn == DAY_OF_WEEK && expr.indexOf('#') != -1 && expr.indexOf('#', expr.indexOf('#') +1) != -1) { + throw new ParseException("Support for specifying multiple \"nth\" days is not implemented.", -1); + } + StringTokenizer vTok = new StringTokenizer(expr, ","); while (vTok.hasMoreTokens()) { String v = vTok.nextToken(); @@ -369,12 +490,28 @@ exprOn++; } - if (exprOn <= DAY_OF_WEEK) - throw new ParseException("Unexpected end of expression.", + if (exprOn <= DAY_OF_WEEK) { + throw new ParseException("Unexpected end of expression.", expression.length()); + } - if (exprOn <= YEAR) storeExpressionVals(0, "*", YEAR); + if (exprOn <= YEAR) { + storeExpressionVals(0, "*", YEAR); + } + TreeSet dow = getSet(DAY_OF_WEEK); + TreeSet dom = getSet(DAY_OF_MONTH); + + // Copying the logic from the UnsupportedOperationException below + boolean dayOfMSpec = !dom.contains(NO_SPEC); + boolean dayOfWSpec = !dow.contains(NO_SPEC); + + if (!dayOfMSpec || dayOfWSpec) { + if (!dayOfWSpec || dayOfMSpec) { + throw new ParseException( + "Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.", 0); + } + } } catch (ParseException pe) { throw pe; } catch (Exception e) { @@ -384,57 +521,58 @@ } protected int storeExpressionVals(int pos, String s, int type) - throws ParseException { + throws ParseException { + int incr = 0; int i = skipWhiteSpace(pos, s); - if (i >= s.length()) return i; + if (i >= s.length()) { + return i; + } char c = s.charAt(i); - if ((c >= 'A') && (c <= 'Z') && (!s.equals("L")) && (!s.equals("LW"))) { + if ((c >= 'A') && (c <= 'Z') && (!s.equals("L")) && (!s.equals("LW")) && (!s.matches("^L-[0-9]*[W]?"))) { String sub = s.substring(i, i + 3); int sval = -1; int eval = -1; if (type == MONTH) { sval = getMonthNumber(sub) + 1; - if (sval < 0) - throw new ParseException("Invalid Month value: '" + sub - + "'", i); + if (sval <= 0) { + throw new ParseException("Invalid Month value: '" + sub + "'", i); + } if (s.length() > i + 3) { c = s.charAt(i + 3); if (c == '-') { i += 4; sub = s.substring(i, i + 3); eval = getMonthNumber(sub) + 1; - if (eval < 0) - throw new ParseException( - "Invalid Month value: '" + sub + "'", i); + if (eval <= 0) { + throw new ParseException("Invalid Month value: '" + sub + "'", i); + } } } } else if (type == DAY_OF_WEEK) { sval = getDayOfWeekNumber(sub); - if (sval < 0) - throw new ParseException("Invalid Day-of-Week value: '" + if (sval < 0) { + throw new ParseException("Invalid Day-of-Week value: '" + sub + "'", i); + } if (s.length() > i + 3) { c = s.charAt(i + 3); if (c == '-') { i += 4; sub = s.substring(i, i + 3); eval = getDayOfWeekNumber(sub); - if (eval < 0) + if (eval < 0) { throw new ParseException( "Invalid Day-of-Week value: '" + sub + "'", i); - if (sval > eval) - throw new ParseException( - "Invalid Day-of-Week sequence: " + sval - + " > " + eval, i); - + } } else if (c == '#') { try { i += 4; nthdayOfWeek = Integer.parseInt(s.substring(i)); - if (nthdayOfWeek < 1 || nthdayOfWeek > 5) - throw new Exception(); + if (nthdayOfWeek < 1 || nthdayOfWeek > 5) { + throw new Exception(); + } } catch (Exception e) { throw new ParseException( "A numeric value between 1 and 5 must follow the '#' option", @@ -451,27 +589,32 @@ "Illegal characters for this position: '" + sub + "'", i); } - if (eval != -1) incr = 1; + if (eval != -1) { + incr = 1; + } addToSet(sval, eval, incr, type); return (i + 3); } if (c == '?') { i++; - if ((i + 1) < s.length() - && (s.charAt(i) != ' ' && s.charAt(i + 1) != '\t')) - throw new ParseException("Illegal character after '?': " + if ((i + 1) < s.length() + && (s.charAt(i) != ' ' && s.charAt(i + 1) != '\t')) { + throw new ParseException("Illegal character after '?': " + s.charAt(i), i); - if (type != DAY_OF_WEEK && type != DAY_OF_MONTH) - throw new ParseException( + } + if (type != DAY_OF_WEEK && type != DAY_OF_MONTH) { + throw new ParseException( "'?' can only be specfied for Day-of-Month or Day-of-Week.", i); + } if (type == DAY_OF_WEEK && !lastdayOfMonth) { - int val = ((Integer) daysOfMonth.last()).intValue(); - if (val == NO_SPEC_INT) - throw new ParseException( + int val = daysOfMonth.last(); + if (val == NO_SPEC_INT) { + throw new ParseException( "'?' can only be specfied for Day-of-Month -OR- Day-of-Week.", i); + } } addToSet(NO_SPEC_INT, -1, 0, type); @@ -484,51 +627,73 @@ return i + 1; } else if (c == '/' && ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s - .charAt(i + 1) == '\t')) throw new ParseException( - "'/' must be followed by an integer.", i); - else if (c == '*') i++; + .charAt(i + 1) == '\t')) { + throw new ParseException("'/' must be followed by an integer.", i); + } else if (c == '*') { + i++; + } c = s.charAt(i); if (c == '/') { // is an increment specified? i++; - if (i >= s.length()) - throw new ParseException("Unexpected end of string.", i); + if (i >= s.length()) { + throw new ParseException("Unexpected end of string.", i); + } incr = getNumericValue(s, i); i++; - if (incr > 10) i++; - if (incr > 59 && (type == SECOND || type == MINUTE)) throw new ParseException( - "Increment > 60 : " + incr, i); - else if (incr > 23 && (type == HOUR)) throw new ParseException( - "Increment > 24 : " + incr, i); - else if (incr > 31 && (type == DAY_OF_MONTH)) throw new ParseException( - "Increment > 31 : " + incr, i); - else if (incr > 7 && (type == DAY_OF_WEEK)) throw new ParseException( - "Increment > 7 : " + incr, i); - else if (incr > 12 && (type == MONTH)) - throw new ParseException("Increment > 12 : " + incr, i); - } else + if (incr > 10) { + i++; + } + if (incr > 59 && (type == SECOND || type == MINUTE)) { + throw new ParseException("Increment > 60 : " + incr, i); + } else if (incr > 23 && (type == HOUR)) { + throw new ParseException("Increment > 24 : " + incr, i); + } else if (incr > 31 && (type == DAY_OF_MONTH)) { + throw new ParseException("Increment > 31 : " + incr, i); + } else if (incr > 7 && (type == DAY_OF_WEEK)) { + throw new ParseException("Increment > 7 : " + incr, i); + } else if (incr > 12 && (type == MONTH)) { + throw new ParseException("Increment > 12 : " + incr, i); + } + } else { incr = 1; + } addToSet(ALL_SPEC_INT, -1, incr, type); return i; } else if (c == 'L') { i++; - if (type == DAY_OF_MONTH) lastdayOfMonth = true; - if (type == DAY_OF_WEEK) addToSet(7, 7, 0, type); + if (type == DAY_OF_MONTH) { + lastdayOfMonth = true; + } + if (type == DAY_OF_WEEK) { + addToSet(7, 7, 0, type); + } if(type == DAY_OF_MONTH && s.length() > i) { c = s.charAt(i); - if(c == 'W') { - nearestWeekday = true; - i++; + if(c == '-') { + ValueSet vs = getValue(0, s, i+1); + lastdayOffset = vs.value; + if(lastdayOffset > 30) + throw new ParseException("Offset from last day must be <= 30", i+1); + i = vs.pos; + } + if(s.length() > i) { + c = s.charAt(i); + if(c == 'W') { + nearestWeekday = true; + i++; + } } } return i; } else if (c >= '0' && c <= '9') { int val = Integer.parseInt(String.valueOf(c)); i++; - if (i >= s.length()) addToSet(val, -1, -1, type); - else { + if (i >= s.length()) { + addToSet(val, -1, -1, type); + } else { c = s.charAt(i); if (c >= '0' && c <= '9') { ValueSet vs = getValue(val, s, i); @@ -538,14 +703,16 @@ i = checkNext(i, s, val, type); return i; } - } else + } else { throw new ParseException("Unexpected character: " + c, i); + } return i; } protected int checkNext(int pos, String s, int val, int type) - throws ParseException { + throws ParseException { + int end = -1; int i = pos; @@ -557,60 +724,55 @@ char c = s.charAt(pos); if (c == 'L') { - if (type == DAY_OF_WEEK) lastdayOfWeek = true; - else - throw new ParseException("'L' option is not valid here. (pos=" - + i + ")", i); - TreeSet set = getSet(type); - set.add(new Integer(val)); + if (type == DAY_OF_WEEK) { + if(val < 1 || val > 7) + throw new ParseException("Day-of-Week values must be between 1 and 7", -1); + lastdayOfWeek = true; + } else { + throw new ParseException("'L' option is not valid here. (pos=" + i + ")", i); + } + TreeSet set = getSet(type); + set.add(val); i++; return i; } if (c == 'W') { - if(type == DAY_OF_MONTH) nearestWeekday = true; - else - throw new ParseException("'W' option is not valid here. (pos=" - + i + ")", i); - TreeSet set = getSet(type); - set.add(new Integer(val)); + if (type == DAY_OF_MONTH) { + nearestWeekday = true; + } else { + throw new ParseException("'W' option is not valid here. (pos=" + i + ")", i); + } + if(val > 31) + throw new ParseException("The 'W' option does not make sense with values larger than 31 (max number of days in a month)", i); + TreeSet set = getSet(type); + set.add(val); i++; return i; } if (c == '#') { - if (type != DAY_OF_WEEK) - throw new ParseException( - "'#' option is not valid here. (pos=" + i + ")", i); + if (type != DAY_OF_WEEK) { + throw new ParseException("'#' option is not valid here. (pos=" + i + ")", i); + } i++; try { nthdayOfWeek = Integer.parseInt(s.substring(i)); - if (nthdayOfWeek < 1 || nthdayOfWeek > 5) - throw new Exception(); + if (nthdayOfWeek < 1 || nthdayOfWeek > 5) { + throw new Exception(); + } } catch (Exception e) { throw new ParseException( "A numeric value between 1 and 5 must follow the '#' option", i); } - TreeSet set = getSet(type); - set.add(new Integer(val)); + TreeSet set = getSet(type); + set.add(val); i++; return i; } - if (c == 'C') { - if (type == DAY_OF_WEEK) calendardayOfWeek = true; - else if (type == DAY_OF_MONTH) calendardayOfMonth = true; - else - throw new ParseException("'C' option is not valid here. (pos=" - + i + ")", i); - TreeSet set = getSet(type); - set.add(new Integer(val)); - i++; - return i; - } - if (c == '-') { i++; c = s.charAt(i); @@ -624,8 +786,7 @@ c = s.charAt(i); if (c >= '0' && c <= '9') { ValueSet vs = getValue(v, s, i); - int v1 = vs.value; - end = v1; + end = vs.value; i = vs.pos; } if (i < s.length() && ((c = s.charAt(i)) == '/')) { @@ -670,9 +831,9 @@ addToSet(val, end, v3, type); i = vs.pos; return i; - } else - throw new ParseException("Unexpected character '" + c - + "' after '/'", i); + } else { + throw new ParseException("Unexpected character '" + c + "' after '/'", i); + } } addToSet(val, end, 0, type); @@ -681,11 +842,11 @@ } public String getCronExpression() { - return cronExpression; + return cronExpression; } public String getExpressionSummary() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append("seconds: "); buf.append(getExpressionSetSummary(seconds)); @@ -717,52 +878,58 @@ buf.append("lastdayOfMonth: "); buf.append(lastdayOfMonth); buf.append("\n"); - buf.append("calendardayOfWeek: "); - buf.append(calendardayOfWeek); - buf.append("\n"); - buf.append("calendardayOfMonth: "); - buf.append(calendardayOfMonth); - buf.append("\n"); buf.append("years: "); buf.append(getExpressionSetSummary(years)); buf.append("\n"); return buf.toString(); } - protected String getExpressionSetSummary(java.util.Set set) { + protected String getExpressionSetSummary(java.util.Set set) { - if (set.contains(NO_SPEC)) return "?"; - if (set.contains(ALL_SPEC)) return "*"; + if (set.contains(NO_SPEC)) { + return "?"; + } + if (set.contains(ALL_SPEC)) { + return "*"; + } - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); - Iterator itr = set.iterator(); + Iterator itr = set.iterator(); boolean first = true; while (itr.hasNext()) { - Integer iVal = (Integer) itr.next(); + Integer iVal = itr.next(); String val = iVal.toString(); - if (!first) buf.append(","); + if (!first) { + buf.append(","); + } buf.append(val); first = false; } return buf.toString(); } - protected String getExpressionSetSummary(java.util.ArrayList list) { + protected String getExpressionSetSummary(java.util.ArrayList list) { - if (list.contains(NO_SPEC)) return "?"; - if (list.contains(ALL_SPEC)) return "*"; + if (list.contains(NO_SPEC)) { + return "?"; + } + if (list.contains(ALL_SPEC)) { + return "*"; + } - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); - Iterator itr = list.iterator(); + Iterator itr = list.iterator(); boolean first = true; while (itr.hasNext()) { - Integer iVal = (Integer) itr.next(); + Integer iVal = itr.next(); String val = iVal.toString(); - if (!first) buf.append(","); + if (!first) { + buf.append(","); + } buf.append(val); first = false; } @@ -771,52 +938,63 @@ } protected int skipWhiteSpace(int i, String s) { - for (; i < s.length() && (s.charAt(i) == ' ' || s.charAt(i) == '\t'); i++) + for (; i < s.length() && (s.charAt(i) == ' ' || s.charAt(i) == '\t'); i++) { ; + } return i; } protected int findNextWhiteSpace(int i, String s) { - for (; i < s.length() && (s.charAt(i) != ' ' || s.charAt(i) != '\t'); i++) + for (; i < s.length() && (s.charAt(i) != ' ' || s.charAt(i) != '\t'); i++) { ; + } return i; } protected void addToSet(int val, int end, int incr, int type) - throws ParseException { - TreeSet set = getSet(type); + throws ParseException { + + TreeSet set = getSet(type); if (type == SECOND || type == MINUTE) { - if ((val < 0 || val > 59 || end > 59) && (val != ALL_SPEC_INT)) - throw new ParseException( - "Minute and Second values must be between 0 and 59", - -1); + if ((val < 0 || val > 59 || end > 59) && (val != ALL_SPEC_INT)) { + throw new ParseException( + "Minute and Second values must be between 0 and 59", + -1); + } } else if (type == HOUR) { - if ((val < 0 || val > 23 || end > 23) && (val != ALL_SPEC_INT)) - throw new ParseException( - "Hour values must be between 0 and 23", -1); + if ((val < 0 || val > 23 || end > 23) && (val != ALL_SPEC_INT)) { + throw new ParseException( + "Hour values must be between 0 and 23", -1); + } } else if (type == DAY_OF_MONTH) { - if ((val < 1 || val > 31 || end > 31) && (val != ALL_SPEC_INT) - && (val != NO_SPEC_INT)) - throw new ParseException( - "Day of month values must be between 1 and 31", -1); + if ((val < 1 || val > 31 || end > 31) && (val != ALL_SPEC_INT) + && (val != NO_SPEC_INT)) { + throw new ParseException( + "Day of month values must be between 1 and 31", -1); + } } else if (type == MONTH) { - if ((val < 1 || val > 12 || end > 12) && (val != ALL_SPEC_INT)) - throw new ParseException( - "Month values must be between 1 and 12", -1); + if ((val < 1 || val > 12 || end > 12) && (val != ALL_SPEC_INT)) { + throw new ParseException( + "Month values must be between 1 and 12", -1); + } } else if (type == DAY_OF_WEEK) { if ((val == 0 || val > 7 || end > 7) && (val != ALL_SPEC_INT) - && (val != NO_SPEC_INT)) - throw new ParseException( - "Day-of-Week values must be between 1 and 7", -1); + && (val != NO_SPEC_INT)) { + throw new ParseException( + "Day-of-Week values must be between 1 and 7", -1); + } } if ((incr == 0 || incr == -1) && val != ALL_SPEC_INT) { - if (val != -1) set.add(new Integer(val)); - else + if (val != -1) { + set.add(val); + } else { set.add(NO_SPEC); + } + return; } @@ -829,64 +1007,121 @@ } if (type == SECOND || type == MINUTE) { - if (stopAt == -1) stopAt = 59; - if (startAt == -1 || startAt == ALL_SPEC_INT) startAt = 0; + if (stopAt == -1) { + stopAt = 59; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 0; + } } else if (type == HOUR) { - if (stopAt == -1) stopAt = 23; - if (startAt == -1 || startAt == ALL_SPEC_INT) startAt = 0; + if (stopAt == -1) { + stopAt = 23; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 0; + } } else if (type == DAY_OF_MONTH) { - if (stopAt == -1) stopAt = 31; - if (startAt == -1 || startAt == ALL_SPEC_INT) startAt = 1; + if (stopAt == -1) { + stopAt = 31; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 1; + } } else if (type == MONTH) { - if (stopAt == -1) stopAt = 12; - if (startAt == -1 || startAt == ALL_SPEC_INT) startAt = 1; + if (stopAt == -1) { + stopAt = 12; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 1; + } } else if (type == DAY_OF_WEEK) { - if (stopAt == -1) stopAt = 7; - if (startAt == -1 || startAt == ALL_SPEC_INT) startAt = 1; + if (stopAt == -1) { + stopAt = 7; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 1; + } } else if (type == YEAR) { - if (stopAt == -1) stopAt = 2099; - if (startAt == -1 || startAt == ALL_SPEC_INT) startAt = 1970; + if (stopAt == -1) { + stopAt = MAX_YEAR; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 1970; + } } - for (int i = startAt; i <= stopAt; i += incr) - set.add(new Integer(i)); + // if the end of the range is before the start, then we need to overflow into + // the next day, month etc. This is done by adding the maximum amount for that + // type, and using modulus max to determine the value being added. + int max = -1; + if (stopAt < startAt) { + switch (type) { + case SECOND : max = 60; break; + case MINUTE : max = 60; break; + case HOUR : max = 24; break; + case MONTH : max = 12; break; + case DAY_OF_WEEK : max = 7; break; + case DAY_OF_MONTH : max = 31; break; + case YEAR : throw new IllegalArgumentException("Start year must be less than stop year"); + default : throw new IllegalArgumentException("Unexpected type encountered"); + } + stopAt += max; + } + + for (int i = startAt; i <= stopAt; i += incr) { + if (max == -1) { + // ie: there's no max to overflow over + set.add(i); + } else { + // take the modulus to get the real value + int i2 = i % max; + + // 1-indexed ranges should not include 0, and should include their max + if (i2 == 0 && (type == MONTH || type == DAY_OF_WEEK || type == DAY_OF_MONTH) ) { + i2 = max; + } + + set.add(i2); + } + } } - protected TreeSet getSet(int type) { + TreeSet getSet(int type) { switch (type) { - case SECOND: - return seconds; - case MINUTE: - return minutes; - case HOUR: - return hours; - case DAY_OF_MONTH: - return daysOfMonth; - case MONTH: - return months; - case DAY_OF_WEEK: - return daysOfWeek; - case YEAR: - return years; - default: - return null; + case SECOND: + return seconds; + case MINUTE: + return minutes; + case HOUR: + return hours; + case DAY_OF_MONTH: + return daysOfMonth; + case MONTH: + return months; + case DAY_OF_WEEK: + return daysOfWeek; + case YEAR: + return years; + default: + return null; } } protected ValueSet getValue(int v, String s, int i) { char c = s.charAt(i); - String s1 = String.valueOf(v); + StringBuilder s1 = new StringBuilder(String.valueOf(v)); while (c >= '0' && c <= '9') { - s1 += c; + s1.append(c); i++; - if (i >= s.length()) break; + if (i >= s.length()) { + break; + } c = s.charAt(i); } ValueSet val = new ValueSet(); - if (i < s.length()) val.pos = i; - else - val.pos = i + 1; - val.value = Integer.parseInt(s1); + + val.pos = (i < s.length()) ? i : i + 1; + val.value = Integer.parseInt(s1.toString()); return val; } @@ -897,48 +1132,35 @@ } protected int getMonthNumber(String s) { - Integer integer = (Integer) monthMap.get(s); + Integer integer = monthMap.get(s); - if (integer == null) return -1; + if (integer == null) { + return -1; + } - return integer.intValue(); + return integer; } protected int getDayOfWeekNumber(String s) { - Integer integer = (Integer) dayMap.get(s); + Integer integer = dayMap.get(s); - if (integer == null) return -1; + if (integer == null) { + return -1; + } - return integer.intValue(); + return integer; } - protected Date getTime(int sc, int mn, int hr, int dayofmn, int mon) { - try { - Calendar cl = Calendar.getInstance(getTimeZone()); - //cl.add(Calendar.DAY_OF_MONTH,); - if (hr >= 0 && hr <= 12) cl.set(Calendar.AM_PM, Calendar.AM); - if (hr >= 13 && hr <= 23) cl.set(Calendar.AM_PM, Calendar.PM); - cl.setLenient(false); - if (sc != -1) cl.set(Calendar.SECOND, sc); - if (mn != -1) cl.set(Calendar.MINUTE, mn); - if (hr != -1) cl.set(Calendar.HOUR_OF_DAY, hr); - if (dayofmn != -1) cl.set(Calendar.DAY_OF_MONTH, dayofmn); - if (mon != -1) cl.set(Calendar.MONTH, mon); - return cl.getTime(); - } catch (Exception e) { - return null; - } - } - //////////////////////////////////////////////////////////////////////////// // // Computation Functions // //////////////////////////////////////////////////////////////////////////// - protected Date getTimeAfter(Date afterTime) { + public Date getTimeAfter(Date afterTime) { - Calendar cl = Calendar.getInstance(getTimeZone()); + // Computation is based on Gregorian year only. + Calendar cl = new java.util.GregorianCalendar(getTimeZone()); // move ahead one second, since we're computing the time *after* the // given time @@ -952,19 +1174,22 @@ while (!gotOne) { //if (endTime != null && cl.getTime().after(endTime)) return null; + if(cl.get(Calendar.YEAR) > 2999) { // prevent endless loop... + return null; + } - SortedSet st = null; + SortedSet st = null; int t = 0; int sec = cl.get(Calendar.SECOND); int min = cl.get(Calendar.MINUTE); // get second................................................. - st = seconds.tailSet(new Integer(sec)); + st = seconds.tailSet(sec); if (st != null && st.size() != 0) { - sec = ((Integer) st.first()).intValue(); + sec = st.first(); } else { - sec = ((Integer) seconds.first()).intValue(); + sec = seconds.first(); min++; cl.set(Calendar.MINUTE, min); } @@ -975,12 +1200,12 @@ t = -1; // get minute................................................. - st = minutes.tailSet(new Integer(min)); + st = minutes.tailSet(min); if (st != null && st.size() != 0) { t = min; - min = ((Integer) st.first()).intValue(); + min = st.first(); } else { - min = ((Integer) minutes.first()).intValue(); + min = minutes.first(); hr++; } if (min != t) { @@ -996,12 +1221,12 @@ t = -1; // get hour................................................... - st = hours.tailSet(new Integer(hr)); + st = hours.tailSet(hr); if (st != null && st.size() != 0) { t = hr; - hr = ((Integer) st.first()).intValue(); + hr = st.first(); } else { - hr = ((Integer) hours.first()).intValue(); + hr = hours.first(); day++; } if (hr != t) { @@ -1024,17 +1249,27 @@ boolean dayOfMSpec = !daysOfMonth.contains(NO_SPEC); boolean dayOfWSpec = !daysOfWeek.contains(NO_SPEC); if (dayOfMSpec && !dayOfWSpec) { // get day by day of month rule - st = daysOfMonth.tailSet(new Integer(day)); + st = daysOfMonth.tailSet(day); if (lastdayOfMonth) { if(!nearestWeekday) { t = day; day = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); - } - else { + day -= lastdayOffset; + if(t > day) { + mon++; + if(mon > 12) { + mon = 1; + tmon = 3333; // ensure test of mon != tmon further below fails + cl.add(Calendar.YEAR, 1); + } + day = 1; + } + } else { t = day; day = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + day -= lastdayOffset; - java.util.Calendar tcal = java.util.Calendar.getInstance(); + java.util.Calendar tcal = java.util.Calendar.getInstance(getTimeZone()); tcal.set(Calendar.SECOND, 0); tcal.set(Calendar.MINUTE, 0); tcal.set(Calendar.HOUR_OF_DAY, 0); @@ -1045,14 +1280,15 @@ int ldom = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); int dow = tcal.get(Calendar.DAY_OF_WEEK); - if(dow == Calendar.SATURDAY && day == 1) + if(dow == Calendar.SATURDAY && day == 1) { day += 2; - else if(dow == Calendar.SATURDAY) + } else if(dow == Calendar.SATURDAY) { day -= 1; - else if(dow == Calendar.SUNDAY && day == ldom) + } else if(dow == Calendar.SUNDAY && day == ldom) { day -= 2; - else if(dow == Calendar.SUNDAY) + } else if(dow == Calendar.SUNDAY) { day += 1; + } tcal.set(Calendar.SECOND, sec); tcal.set(Calendar.MINUTE, min); @@ -1067,9 +1303,9 @@ } } else if(nearestWeekday) { t = day; - day = ((Integer) daysOfMonth.first()).intValue(); + day = daysOfMonth.first(); - java.util.Calendar tcal = java.util.Calendar.getInstance(); + java.util.Calendar tcal = java.util.Calendar.getInstance(getTimeZone()); tcal.set(Calendar.SECOND, 0); tcal.set(Calendar.MINUTE, 0); tcal.set(Calendar.HOUR_OF_DAY, 0); @@ -1080,14 +1316,15 @@ int ldom = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); int dow = tcal.get(Calendar.DAY_OF_WEEK); - if(dow == Calendar.SATURDAY && day == 1) + if(dow == Calendar.SATURDAY && day == 1) { day += 2; - else if(dow == Calendar.SATURDAY) + } else if(dow == Calendar.SATURDAY) { day -= 1; - else if(dow == Calendar.SUNDAY && day == ldom) + } else if(dow == Calendar.SUNDAY && day == ldom) { day -= 2; - else if(dow == Calendar.SUNDAY) + } else if(dow == Calendar.SUNDAY) { day += 1; + } tcal.set(Calendar.SECOND, sec); @@ -1097,15 +1334,20 @@ tcal.set(Calendar.MONTH, mon - 1); Date nTime = tcal.getTime(); if(nTime.before(afterTime)) { - day = ((Integer) daysOfMonth.first()).intValue();; + day = daysOfMonth.first(); mon++; } - } - else if (st != null && st.size() != 0) { + } else if (st != null && st.size() != 0) { t = day; - day = ((Integer) st.first()).intValue(); + day = st.first(); + // make sure we don't over-run a short month, such as february + int lastDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + if (day > lastDay) { + day = daysOfMonth.first(); + mon++; + } } else { - day = ((Integer) daysOfMonth.first()).intValue(); + day = daysOfMonth.first(); mon++; } @@ -1122,12 +1364,16 @@ } else if (dayOfWSpec && !dayOfMSpec) { // get day by day of week rule if (lastdayOfWeek) { // are we looking for the last XXX day of // the month? - int dow = ((Integer) daysOfWeek.first()).intValue(); // desired + int dow = daysOfWeek.first(); // desired // d-o-w int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w int daysToAdd = 0; - if (cDow < dow) daysToAdd = dow - cDow; - if (cDow > dow) daysToAdd = dow + (7 - cDow); + if (cDow < dow) { + daysToAdd = dow - cDow; + } + if (cDow > dow) { + daysToAdd = dow + (7 - cDow); + } int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); @@ -1142,9 +1388,10 @@ continue; } - // find date of last occurance of this day in this month... - while ((day + daysToAdd + 7) <= lDay) + // find date of last occurrence of this day in this month... + while ((day + daysToAdd + 7) <= lDay) { daysToAdd += 7; + } day += daysToAdd; @@ -1160,19 +1407,26 @@ } else if (nthdayOfWeek != 0) { // are we looking for the Nth XXX day in the month? - int dow = ((Integer) daysOfWeek.first()).intValue(); // desired + int dow = daysOfWeek.first(); // desired // d-o-w int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w int daysToAdd = 0; - if (cDow < dow) daysToAdd = dow - cDow; - else if (cDow > dow) daysToAdd = dow + (7 - cDow); + if (cDow < dow) { + daysToAdd = dow - cDow; + } else if (cDow > dow) { + daysToAdd = dow + (7 - cDow); + } boolean dayShifted = false; - if (daysToAdd > 0) dayShifted = true; + if (daysToAdd > 0) { + dayShifted = true; + } day += daysToAdd; int weekOfMonth = day / 7; - if (day % 7 > 0) weekOfMonth++; + if (day % 7 > 0) { + weekOfMonth++; + } daysToAdd = (nthdayOfWeek - weekOfMonth) * 7; day += daysToAdd; @@ -1197,16 +1451,20 @@ } } else { int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w - int dow = ((Integer) daysOfWeek.first()).intValue(); // desired + int dow = daysOfWeek.first(); // desired // d-o-w - st = daysOfWeek.tailSet(new Integer(cDow)); + st = daysOfWeek.tailSet(cDow); if (st != null && st.size() > 0) { - dow = ((Integer) st.first()).intValue(); + dow = st.first(); } int daysToAdd = 0; - if (cDow < dow) daysToAdd = dow - cDow; - if (cDow > dow) daysToAdd = dow + (7 - cDow); + if (cDow < dow) { + daysToAdd = dow - cDow; + } + if (cDow > dow) { + daysToAdd = dow + (7 - cDow); + } int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); @@ -1233,7 +1491,6 @@ } else { // dayOfWSpec && !dayOfMSpec throw new UnsupportedOperationException( "Support for specifying both a day-of-week AND a day-of-month parameter is not implemented."); - // TODO: } cl.set(Calendar.DAY_OF_MONTH, day); @@ -1245,15 +1502,17 @@ // test for expressions that never generate a valid fire date, // but keep looping... - if (year > 2099) return null; + if (year > MAX_YEAR) { + return null; + } // get month................................................... - st = months.tailSet(new Integer(mon)); + st = months.tailSet(mon); if (st != null && st.size() != 0) { t = mon; - mon = ((Integer) st.first()).intValue(); + mon = st.first(); } else { - mon = ((Integer) months.first()).intValue(); + mon = months.first(); year++; } if (mon != t) { @@ -1275,12 +1534,13 @@ t = -1; // get year................................................... - st = years.tailSet(new Integer(year)); + st = years.tailSet(year); if (st != null && st.size() != 0) { t = year; - year = ((Integer) st.first()).intValue(); - } else + year = st.first(); + } else { return null; // ran out of years... + } if (year != t) { cl.set(Calendar.SECOND, 0); @@ -1305,8 +1565,8 @@ * Advance the calendar to the particular hour paying particular attention * to daylight saving problems. * - * @param cal - * @param hour + * @param cal the calendar to operate on + * @param hour the hour to set */ protected void setCalendarHour(Calendar cal, int hour) { cal.set(java.util.Calendar.HOUR_OF_DAY, hour); @@ -1315,74 +1575,81 @@ } } - protected Date getTimeBefore(Date endTime) // TODO: implement - { + /** + * NOT YET IMPLEMENTED: Returns the time before the given time + * that the CronExpression matches. + */ + public Date getTimeBefore(Date endTime) { + // FUTURE_TODO: implement QUARTZ-423 return null; } + /** + * NOT YET IMPLEMENTED: Returns the final time that the + * CronExpression will match. + */ + public Date getFinalFireTime() { + // FUTURE_TODO: implement QUARTZ-423 + return null; + } + protected boolean isLeapYear(int year) { - if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) return true; - else - return false; + return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)); } protected int getLastDayOfMonth(int monthNum, int year) { switch (monthNum) { - case 1: - return 31; - case 2: - return (isLeapYear(year)) ? 29 : 28; - case 3: - return 31; - case 4: - return 30; - case 5: - return 31; - case 6: - return 30; - case 7: - return 31; - case 8: - return 31; - case 9: - return 30; - case 10: - return 31; - case 11: - return 30; - case 12: - return 31; - default: - throw new IllegalArgumentException("Illegal month number: " - + monthNum); + case 1: + return 31; + case 2: + return (isLeapYear(year)) ? 29 : 28; + case 3: + return 31; + case 4: + return 30; + case 5: + return 31; + case 6: + return 30; + case 7: + return 31; + case 8: + return 31; + case 9: + return 30; + case 10: + return 31; + case 11: + return 30; + case 12: + return 31; + default: + throw new IllegalArgumentException("Illegal month number: " + + monthNum); } } private void readObject(java.io.ObjectInputStream stream) - throws java.io.IOException, ClassNotFoundException { + throws java.io.IOException, ClassNotFoundException { + stream.defaultReadObject(); try { buildExpression(cronExpression); } catch (Exception ignore) { } // never happens } + @Override + @Deprecated public Object clone() { - CronExpression copy = null; - try { - copy = new CronExpression(getCronExpression()); - copy.setTimeZone(getTimeZone()); - } catch (ParseException ex) { // never happens since the source is valid... - throw new IncompatibleClassChangeError("Not Cloneable."); - } - return copy; - } + return new CronExpression(this); + } } class ValueSet { public int value; public int pos; -} \ No newline at end of file +} Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/CronScheduleBuilder.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/CronTrigger.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/CronTrigger.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/CronTrigger.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/CronTrigger.java 15 Dec 2014 10:09:47 -0000 1.1.2.1 @@ -1,5 +1,5 @@ -/* - * Copyright 2004-2005 OpenSymphony +/* + * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,22 +15,15 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; -import java.text.ParseException; import java.util.Calendar; -import java.util.Date; import java.util.TimeZone; - /** - *

- * A concrete {@link Trigger} that is used to fire a {@link org.quartz.JobDetail} - * at given moments in time, defined with Unix 'cron-like' definitions. - *

+ * The public interface for inspecting settings specific to a CronTrigger, . + * which is used to fire a {@link org.quartz.Job} + * at given moments in time, defined with Unix 'cron-like' schedule definitions. * *

* For those unfamiliar with "cron", this means being able to create a firing @@ -139,7 +132,7 @@ * * "0 15 10 ? * 6L 2002-2005" *   - * Fire at 10:15am on every last friday of every month during the years 2002, 2003, 2004 and 2005 + * Fire at 10:15am on every last Friday of every month during the years 2002, 2003, 2004 and 2005 * * * @@ -168,23 +161,16 @@ * *

* - * @see Trigger - * @see SimpleTrigger - * @see TriggerUtils + * @see CronScheduleBuilder + * @see TriggerBuilder * - * @author Sharada Jambula, James House + * @author jhouse * @author Contributions from Mads Henderson */ -public class CronTrigger extends Trigger { +public interface CronTrigger extends Trigger { - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Constants. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - + public static final long serialVersionUID = -8644953146451592766L; + /** *

* Instructs the {@link Scheduler} that upon a mis-fire @@ -193,7 +179,7 @@ *

*/ public static final int MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1; - + /** *

* Instructs the {@link Scheduler} that upon a mis-fire @@ -205,765 +191,17 @@ */ public static final int MISFIRE_INSTRUCTION_DO_NOTHING = 2; - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Data members. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ + public String getCronExpression(); - private CronExpression cronEx = null; - private Date startTime = null; - private Date endTime = null; - private Date nextFireTime = null; - private Date previousFireTime = null; - private transient TimeZone timeZone = null; - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Constructors. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - /** *

- * Create a CronTrigger with no settings. - *

- * - *

- * The start-time will also be set to the current time, and the time zone - * will be set the the system's default time zone. - *

- */ - public CronTrigger() { - super(); - setStartTime(new Date()); - setTimeZone(TimeZone.getDefault()); - } - - /** - *

- * Create a CronTrigger with the given name and group. - *

- * - *

- * The start-time will also be set to the current time, and the time zone - * will be set the the system's default time zone. - *

- */ - public CronTrigger(String name, String group) { - super(name, group); - setStartTime(new Date()); - setTimeZone(TimeZone.getDefault()); - } - - /** - *

- * Create a CronTrigger with the given name, group and - * expression. - *

- * - *

- * The start-time will also be set to the current time, and the time zone - * will be set the the system's default time zone. - *

- */ - public CronTrigger(String name, String group, String cronExpression) - throws ParseException { - super(name, group); - - setCronExpression(cronExpression); - - setStartTime(new Date()); - setTimeZone(TimeZone.getDefault()); - } - - /** - *

- * Create a CronTrigger with the given name and group, and - * associated with the identified {@link org.quartz.JobDetail}. - *

- * - *

- * The start-time will also be set to the current time, and the time zone - * will be set the the system's default time zone. - *

- */ - public CronTrigger(String name, String group, String jobName, - String jobGroup) { - super(name, group, jobName, jobGroup); - setStartTime(new Date()); - setTimeZone(TimeZone.getDefault()); - } - - /** - *

- * Create a CronTrigger with the given name and group, - * associated with the identified {@link org.quartz.JobDetail}, - * and with the given "cron" expression. - *

- * - *

- * The start-time will also be set to the current time, and the time zone - * will be set the the system's default time zone. - *

- */ - public CronTrigger(String name, String group, String jobName, - String jobGroup, String cronExpression) throws ParseException { - this(name, group, jobName, jobGroup, null, null, cronExpression, - TimeZone.getDefault()); - } - - /** - *

- * Create a CronTrigger with the given name and group, - * associated with the identified {@link org.quartz.JobDetail}, - * and with the given "cron" expression resolved with respect to the TimeZone. - *

- */ - public CronTrigger(String name, String group, String jobName, - String jobGroup, String cronExpression, TimeZone timeZone) - throws ParseException { - this(name, group, jobName, jobGroup, null, null, cronExpression, - timeZone); - } - - /** - *

- * Create a CronTrigger that will occur at the given time, - * until the given end time. - *

- * - *

- * If null, the start-time will also be set to the current time, the time - * zone will be set the the system's default. - *

- * - * @param startTime - * A Date set to the time for the Trigger - * to fire. - * @param endTime - * A Date set to the time for the Trigger - * to quit repeat firing. - */ - public CronTrigger(String name, String group, String jobName, - String jobGroup, Date startTime, Date endTime, String cronExpression) - throws ParseException { - super(name, group, jobName, jobGroup); - - setCronExpression(cronExpression); - - if (startTime == null) startTime = new Date(); - setStartTime(startTime); - if (endTime != null) setEndTime(endTime); - setTimeZone(TimeZone.getDefault()); - - } - - /** - *

- * Create a CronTrigger with fire time dictated by the - * cronExpression resolved with respect to the specified - * timeZone occuring from the startTime until - * the given endTime. - *

- * - *

- * If null, the start-time will also be set to the current time. If null, - * the time zone will be set to the system's default. - *

- * - * @param name - * of the Trigger - * @param group - * of the Trigger - * @param jobName, - * name of the {@link org.quartz.JobDetail} - * executed on firetime - * @param jobGroup, - * group of the {@link org.quartz.JobDetail} - * executed on firetime - * @param startTime - * A Date set to the earliest time for the Trigger - * to start firing. - * @param endTime - * A Date set to the time for the Trigger - * to quit repeat firing. - * @param cronExpression, - * A cron expression dictating the firing sequence of the Trigger - * @param timeZone, - * Specifies for which time zone the cronExpression - * should be interprted, i.e. the expression 0 0 10 * * ?, is - * resolved to 10:00 am in this time zone. - * @throws ParseException - * if the cronExpression is invalid. - */ - public CronTrigger(String name, String group, String jobName, - String jobGroup, Date startTime, Date endTime, - String cronExpression, TimeZone timeZone) throws ParseException { - super(name, group, jobName, jobGroup); - - setCronExpression(cronExpression); - - if (startTime == null) startTime = new Date(); - setStartTime(startTime); - if (endTime != null) setEndTime(endTime); - if (timeZone == null) { - setTimeZone(TimeZone.getDefault()); - } else { - setTimeZone(timeZone); - } - } - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Interface. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - public Object clone() { - CronTrigger copy = (CronTrigger) super.clone(); - copy.setCronExpression((CronExpression)cronEx.clone()); - return copy; - } - - public void setCronExpression(String cronExpression) throws ParseException { - this.cronEx = new CronExpression(cronExpression); - this.cronEx.setTimeZone(getTimeZone()); - } - - public String getCronExpression() { - return cronEx == null ? null : cronEx.getCronExpression(); - } - - public void setCronExpression(CronExpression cronExpression) { - this.cronEx = cronExpression; - this.timeZone = cronExpression.getTimeZone(); - } - - /** - *

- * Get the time at which the CronTrigger should occur. - *

- */ - public Date getStartTime() { - return this.startTime; - } - - public void setStartTime(Date startTime) { - if (startTime == null) - throw new IllegalArgumentException("Start time cannot be null"); - - Date eTime = getEndTime(); - if (eTime != null && startTime != null && eTime.before(startTime)) - throw new IllegalArgumentException( - "End time cannot be before start time"); - - // round off millisecond... - // Note timeZone is not needed here as parameter for - // Calendar.getInstance(), - // since time zone is implicit when using a Date in the setTime method. - Calendar cl = Calendar.getInstance(); - cl.setTime(startTime); - cl.set(Calendar.MILLISECOND, 0); - - this.startTime = cl.getTime(); - } - - /** - *

- * Get the time at which the CronTrigger should quit - * repeating - even if repeastCount isn't yet satisfied. - *

- * - * @see #getFinalFireTime() - */ - public Date getEndTime() { - return this.endTime; - } - - public void setEndTime(Date endTime) { - Date sTime = getStartTime(); - if (sTime != null && endTime != null && sTime.after(endTime)) - throw new IllegalArgumentException( - "End time cannot be before start time"); - - this.endTime = endTime; - } - - /** - *

- * Returns the next time at which the CronTrigger will fire. - * If the trigger will not fire again, null will be - * returned. The value returned is not guaranteed to be valid until after - * the Trigger has been added to the scheduler. - *

- */ - public Date getNextFireTime() { - return this.nextFireTime; - } - - /** - *

- * Returns the previous time at which the CronTrigger will - * fire. If the trigger has not yet fired, null will be - * returned. - */ - public Date getPreviousFireTime() { - return this.previousFireTime; - } - - /** - *

- * Sets the next time at which the CronTrigger will fire. - * This method should not be invoked by client code. - *

- */ - public void setNextFireTime(Date nextFireTime) { - this.nextFireTime = nextFireTime; - } - - /** - *

- * Set the previous time at which the SimpleTrigger fired. - *

- * - *

- * This method should not be invoked by client code. - *

- */ - public void setPreviousFireTime(Date previousFireTime) { - this.previousFireTime = previousFireTime; - } - - /** - *

* Returns the time zone for which the cronExpression of * this CronTrigger will be resolved. *

*/ - public TimeZone getTimeZone() { - - if(cronEx != null) return cronEx.getTimeZone(); - - if (timeZone == null) timeZone = TimeZone.getDefault(); - return timeZone; - } + public TimeZone getTimeZone(); - /** - *

- * Sets the time zone for which the cronExpression of this - * CronTrigger will be resolved. - *

- */ - public void setTimeZone(TimeZone timeZone) { - if(cronEx != null) cronEx.setTimeZone(timeZone); - this.timeZone = timeZone; - } + public String getExpressionSummary(); - /** - *

- * Returns the next time at which the CronTrigger will fire, - * after the given time. If the trigger will not fire after the given time, - * null will be returned. - *

- * - *

- * Note that the date returned is NOT validated against the related - * org.quartz.Calendar (if any) - *

- */ - public Date getFireTimeAfter(Date afterTime) { - if (afterTime == null) afterTime = new Date(); - - if (startTime.after(afterTime)) - afterTime = new Date(startTime.getTime() - 1000l); - - Date pot = getTimeAfter(afterTime); - if (endTime != null && pot != null && pot.after(endTime)) return null; - - return pot; - } - - /** - *

- * Returns the final time at which the CronTrigger will - * fire. - *

- * - *

- * Note that the return time *may* be in the past. and the date returned is - * not validated against org.quartz.calendar - *

- */ - public Date getFinalFireTime() { - if (this.endTime != null) return getTimeBefore(this.endTime); - else - return null; - } - - /** - *

- * Determines whether or not the CronTrigger will occur - * again. - *

- */ - public boolean mayFireAgain() { - return (getNextFireTime() != null); - } - - protected boolean validateMisfireInstruction(int misfireInstruction) { - if (misfireInstruction < MISFIRE_INSTRUCTION_SMART_POLICY) - return false; - - if (misfireInstruction > MISFIRE_INSTRUCTION_DO_NOTHING) return false; - - return true; - } - - /** - *

- * Updates the CronTrigger's state based on the - * MISFIRE_INSTRUCTION_XXX that was selected when the SimpleTrigger - * was created. - *

- * - *

- * If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY, - * then the following scheme will be used:
- *

    - *
  • The instruction will be interpreted as MISFIRE_INSTRUCTION_FIRE_ONCE_NOW - *
- *

- */ - public void updateAfterMisfire(org.quartz.Calendar cal) { - int instr = getMisfireInstruction(); - - if (instr == MISFIRE_INSTRUCTION_SMART_POLICY) - instr = MISFIRE_INSTRUCTION_FIRE_ONCE_NOW; - - if (instr == MISFIRE_INSTRUCTION_DO_NOTHING) { - Date newFireTime = getFireTimeAfter(new Date()); - while (newFireTime != null && cal != null - && !cal.isTimeIncluded(newFireTime.getTime())) { - newFireTime = getFireTimeAfter(newFireTime); - } - setNextFireTime(newFireTime); - } else if (instr == MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) { - setNextFireTime(new Date()); - } - } - - /** - *

- * Determines whether the date and (optionally) time of the given Calendar - * instance falls on a scheduled fire-time of this trigger. - *

- * - *

- * Equivalent to calling willFireOn(cal, false). - *

- * - * @param test the date to compare - * - * @see #willFireOn(Calendar, boolean) - */ - public boolean willFireOn(Calendar test) { - return willFireOn(test, false); - } - - /** - *

- * Determines whether the date and (optionally) time of the given Calendar - * instance falls on a scheduled fire-time of this trigger. - *

- * - *

- * Note that the value returned is NOT validated against the related - * org.quartz.Calendar (if any) - *

- * - * @param test the date to compare - * @param dayOnly if set to true, the method will only determine if the - * trigger will fire during the day represented by the given Calendar - * (hours, minutes and seconds will be ignored). - * @see #willFireOn(Calendar) - */ - public boolean willFireOn(Calendar test, boolean dayOnly) { - - test = (Calendar) test.clone(); - - test.set(Calendar.MILLISECOND, 0); // don't compare millis. - - if(dayOnly) { - test.set(Calendar.HOUR, 0); - test.set(Calendar.MINUTE, 0); - test.set(Calendar.SECOND, 0); - } - - Date testTime = test.getTime(); - - Date fta = getFireTimeAfter(new Date(test.getTime().getTime() - 1000)); - - Calendar p = Calendar.getInstance(test.getTimeZone()); - p.setTime(fta); - - int year = p.get(Calendar.YEAR); - int month = p.get(Calendar.MONTH); - int day = p.get(Calendar.DATE); - - if(dayOnly) { - return (year == test.get(Calendar.YEAR) - && month == test.get(Calendar.MONTH) - && day == test.get(Calendar.DATE)); - } - - while(fta.before(testTime)) { - fta = getFireTimeAfter(fta); - } - - if(fta.equals(testTime)) - return true; - - return false; - } - - /** - *

- * Called after the {@link Scheduler} has executed the - * {@link org.quartz.JobDetail} associated with the Trigger - * in order to get the final instruction code from the trigger. - *

- * - * @param context - * is the JobExecutionContext that was used by the - * Job'sexecute(xx) method. - * @param result - * is the JobExecutionException thrown by the - * Job, if any (may be null). - * @return one of the Trigger.INSTRUCTION_XXX constants. - * - * @see #INSTRUCTION_NOOP - * @see #INSTRUCTION_RE_EXECUTE_JOB - * @see #INSTRUCTION_DELETE_TRIGGER - * @see #INSTRUCTION_SET_TRIGGER_COMPLETE - * @see #triggered(Calendar) - */ - public int executionComplete(JobExecutionContext context, - JobExecutionException result) { - if (result != null && result.refireImmediately()) - return INSTRUCTION_RE_EXECUTE_JOB; - - if (result != null && result.unscheduleFiringTrigger()) - return INSTRUCTION_SET_TRIGGER_COMPLETE; - - if (result != null && result.unscheduleAllTriggers()) - return INSTRUCTION_SET_ALL_JOB_TRIGGERS_COMPLETE; - - if (!mayFireAgain()) return INSTRUCTION_DELETE_TRIGGER; - - return INSTRUCTION_NOOP; - } - - /** - *

- * Called when the {@link Scheduler} has decided to 'fire' - * the trigger (execute the associated Job), in order to - * give the Trigger a chance to update itself for its next - * triggering (if any). - *

- * - * @see #executionComplete(JobExecutionContext, JobExecutionException) - */ - public void triggered(org.quartz.Calendar calendar) { - previousFireTime = nextFireTime; - nextFireTime = getFireTimeAfter(nextFireTime); - - while (nextFireTime != null && calendar != null - && !calendar.isTimeIncluded(nextFireTime.getTime())) { - nextFireTime = getFireTimeAfter(nextFireTime); - } - } - - /** - * - * @see org.quartz.Trigger#updateWithNewCalendar(org.quartz.Calendar, long) - */ - public void updateWithNewCalendar(org.quartz.Calendar calendar, long misfireThreshold) - { - nextFireTime = getFireTimeAfter(previousFireTime); - - Date now = new Date(); - do { - while (nextFireTime != null && calendar != null - && !calendar.isTimeIncluded(nextFireTime.getTime())) { - nextFireTime = getFireTimeAfter(nextFireTime); - } - - if(nextFireTime != null && nextFireTime.before(now)) { - long diff = now.getTime() - nextFireTime.getTime(); - if(diff >= misfireThreshold) { - nextFireTime = getFireTimeAfter(nextFireTime); - continue; - } - } - }while(false); - } - - /** - *

- * Called by the scheduler at the time a Trigger is first - * added to the scheduler, in order to have the Trigger - * compute its first fire time, based on any associated calendar. - *

- * - *

- * After this method has been called, getNextFireTime() - * should return a valid answer. - *

- * - * @return the first time at which the Trigger will be fired - * by the scheduler, which is also the same value getNextFireTime() - * will return (until after the first firing of the Trigger). - *

- */ - public Date computeFirstFireTime(org.quartz.Calendar calendar) { - nextFireTime = getFireTimeAfter(new Date(startTime.getTime() - 1000l)); - - while (nextFireTime != null && calendar != null - && !calendar.isTimeIncluded(nextFireTime.getTime())) { - nextFireTime = getFireTimeAfter(nextFireTime); - } - - return nextFireTime; - } - - public String getExpressionSummary() { - return cronEx == null ? null : cronEx.getExpressionSummary(); - } - - //////////////////////////////////////////////////////////////////////////// - // - // Computation Functions - // - //////////////////////////////////////////////////////////////////////////// - - protected Date getTimeAfter(Date afterTime) { - return cronEx.getTimeAfter(afterTime); - } - - protected Date getTimeBefore(Date endTime) - { - return null; - } - - public static void main(String[] args) // TODO: remove method after good - // unit testing - throws Exception { - - String expr = "15 10 0/4 * * ?"; - if(args != null && args.length > 0 && args[0] != null) - expr = args[0]; - - CronTrigger ct = new CronTrigger("t", "g", "j", "g", new Date(), null, expr); - ct.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); - System.err.println(ct.getExpressionSummary()); - System.err.println("tz=" + ct.getTimeZone().getID()); - System.err.println(); - - java.util.List times = TriggerUtils.computeFireTimes(ct, null, 25); - - for (int i = 0; i < times.size(); i++) { - System.err.println("firetime = " + times.get(i)); - } - - Calendar tt = Calendar.getInstance(); - tt.set(Calendar.DATE, 17); - tt.set(Calendar.MONTH, 5 - 1); - tt.set(Calendar.HOUR, 11); - tt.set(Calendar.MINUTE, 0); - tt.set(Calendar.SECOND, 7); - - System.err.println("\nWill fire on: " + tt.getTime() + " -- " + ct.willFireOn(tt, false)); - - -// CRON Expression: 0 0 9 * * ? -// -// TimeZone.getDefault().getDisplayName() = Central African Time -// TimeZone.getDefault().getID() = Africa/Harare - // -//// System.err.println(); -//// System.err.println(); -//// System.err.println(); -//// System.err.println("Daylight test:"); -//// -//// CronTrigger trigger = new CronTrigger(); -//// -//// TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles"); -//// // TimeZone timeZone = TimeZone.getDefault(); -//// -//// trigger.setTimeZone(timeZone); -//// trigger.setCronExpression("0 0 1 ? 4 *"); -//// -//// Date start = new Date(1056319200000L); -//// Date end = new Date(1087682399000L); -//// -//// trigger.setStartTime(start); -//// trigger.setEndTime(end); -//// -//// Date next = new Date(1056232800000L); -//// while (next != null) { -//// next = trigger.getFireTimeAfter(next); -//// if (next != null) { -//// Calendar cal = Calendar.getInstance(); -//// cal.setTimeZone(timeZone); -//// cal.setTime(next); -//// System.err.println(cal.get(Calendar.MONTH) + "/" -//// + cal.get(Calendar.DATE) + "/" + cal.get(Calendar.YEAR) -//// + " - " + cal.get(Calendar.HOUR_OF_DAY) + ":" -//// + cal.get(Calendar.MINUTE)); -//// } -//// } -//// -//// System.err.println(); -//// System.err.println(); -//// System.err.println(); -//// System.err.println("Midnight test:"); -//// -//// trigger = new CronTrigger(); -//// -//// timeZone = TimeZone.getTimeZone("Asia/Jerusalem"); -//// // timeZone = TimeZone.getTimeZone("America/Los_Angeles"); -//// // TimeZone timeZone = TimeZone.getDefault(); -//// -//// trigger.setTimeZone(timeZone); -//// trigger.setCronExpression("0 /15 * ? 4 *"); -//// -//// start = new Date(1056319200000L); -//// end = new Date(1087682399000L); -//// -//// trigger.setStartTime(start); -//// trigger.setEndTime(end); -//// -//// next = new Date(1056232800000L); -//// while (next != null) { -//// next = trigger.getFireTimeAfter(next); -//// if (next != null) { -//// Calendar cal = Calendar.getInstance(); -//// cal.setTimeZone(timeZone); -//// cal.setTime(next); -//// System.err.println(cal.get(Calendar.MONTH) + "/" -//// + cal.get(Calendar.DATE) + "/" + cal.get(Calendar.YEAR) -//// + " - " + cal.get(Calendar.HOUR_OF_DAY) + ":" -//// + cal.get(Calendar.MINUTE)); -//// } -//// } - - } + TriggerBuilder getTriggerBuilder(); } - Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/DailyTimeIntervalScheduleBuilder.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/DailyTimeIntervalTrigger.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/DateBuilder.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/DisallowConcurrentExecution.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/ExecuteInJTATransaction.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/InterruptableJob.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/InterruptableJob.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/InterruptableJob.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/InterruptableJob.java 15 Dec 2014 10:09:47 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,19 +16,17 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; /** - *

* The interface to be implemented by {@link Job}s that provide a - * mechanism for having their execution interrupted. It is NOT a requirment + * mechanism for having their execution interrupted. It is NOT a requirement * for jobs to implement this interface - in fact, for most people, none of * their jobs will. - *

* + *

Interrupting a Job is very analogous in concept and + * challenge to normal interruption of a Thread in Java. + * *

* The means of actually interrupting the Job must be implemented within the * Job itself (the interrupt() method of this @@ -51,18 +49,22 @@ * If the Job performs some form of blocking I/O or similar functions, you may * want to consider having the Job.execute(..) method store a * reference to the calling Thread as a member variable. Then the - * impplementation of this interfaces interrupt() method can call + * Implementation of this interfaces interrupt() method can call * interrupt() on that Thread. Before attempting this, make * sure that you fully understand what java.lang.Thread.interrupt() * does and doesn't do. Also make sure that you clear the Job's member - * reference to the Thread when the execute(..) method exits (preferrably in a + * reference to the Thread when the execute(..) method exits (preferably in a * finally block. *

* + *

+ * See Example 7 (org.quartz.examples.example7.DumbInterruptableJob) for a simple + * implementation demonstration. + *

* @see Job * @see StatefulJob - * @see Scheduler#interrupt(String, String) - * @see org.quartz.examples.example7.DumbInterruptableJob + * @see Scheduler#interrupt(JobKey) + * @see Scheduler#interrupt(String) * * @author James House */ @@ -82,12 +84,9 @@ * interrupts the Job. *

* - * @return void (nothing) if job interrupt is successful. * @throws UnableToInterruptJobException * if there is an exception while interrupting the job. */ - public void interrupt() - throws UnableToInterruptJobException; - - + void interrupt() + throws UnableToInterruptJobException; } Index: 3rdParty_sources/quartz/org/quartz/Job.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/Job.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/Job.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/Job.java 15 Dec 2014 10:09:47 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,9 +16,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; /** @@ -38,7 +35,10 @@ *

* * @see JobDetail - * @see StatefulJob + * @see JobBuilder + * @see ExecuteInJTATransaction + * @see DisallowConcurrentExecution + * @see PersistJobDataAfterExecution * @see Trigger * @see Scheduler * @@ -70,11 +70,10 @@ * execution. *

* - * @return void (nothing) if job is successful. * @throws JobExecutionException * if there is an exception while executing the job. */ - public void execute(JobExecutionContext context) - throws JobExecutionException; + void execute(JobExecutionContext context) + throws JobExecutionException; } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/JobBuilder.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/JobDataMap.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/JobDataMap.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/JobDataMap.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/JobDataMap.java 15 Dec 2014 10:09:47 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,26 +16,20 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; import java.io.Serializable; -import java.util.Iterator; import java.util.Map; -import org.quartz.utils.DirtyFlagMap; +import org.quartz.utils.StringKeyDirtyFlagMap; /** - *

* Holds state information for Job instances. - *

* *

* JobDataMap instances are stored once when the Job * is added to a scheduler. They are also re-persisted after every execution of - * StatefulJob instances. + * jobs annotated with @PersistJobDataAfterExecution. *

* *

@@ -54,13 +48,13 @@ *

* * @see Job - * @see StatefulJob + * @see PersistJobDataAfterExecution * @see Trigger * @see JobExecutionContext * * @author James House */ -public class JobDataMap extends DirtyFlagMap implements Serializable { +public class JobDataMap extends StringKeyDirtyFlagMap implements Serializable { private static final long serialVersionUID = -6939901990106713909L; @@ -72,16 +66,6 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - private boolean allowsTransientData = false; - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Constructors. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - /** *

* Create an empty JobDataMap. @@ -96,10 +80,11 @@ * Create a JobDataMap with the given data. *

*/ - public JobDataMap(Map map) { + public JobDataMap(Map map) { this(); - - putAll(map); + @SuppressWarnings("unchecked") // casting to keep API compatible and avoid compiler errors/warnings. + Map mapTyped = (Map)map; + putAll(mapTyped); } /* @@ -112,163 +97,12 @@ /** *

- * Tell the JobDataMap that it should allow non- Serializable - * data. - *

- * - *

- * If the JobDataMap does contain non- Serializable - * objects, and it belongs to a non-volatile Job that is - * stored in a JobStore that supports persistence, then - * those elements will be nulled-out during persistence. - *

- */ - public void setAllowsTransientData(boolean allowsTransientData) { - - if (containsTransientData() && !allowsTransientData) - throw new IllegalStateException( - "Cannot set property 'allowsTransientData' to 'false' " - + "when data map contains non-serializable objects."); - - this.allowsTransientData = allowsTransientData; - } - - public boolean getAllowsTransientData() { - return allowsTransientData; - } - - public boolean containsTransientData() { - - if (!getAllowsTransientData()) // short circuit... - return false; - - String[] keys = getKeys(); - - for (int i = 0; i < keys.length; i++) { - Object o = super.get(keys[i]); - if (!(o instanceof Serializable)) return true; - } - - return false; - } - - /** - *

- * Nulls-out any data values that are non-Serializable. - *

- */ - public void removeTransientData() { - - if (!getAllowsTransientData()) // short circuit... - return; - - String[] keys = getKeys(); - - for (int i = 0; i < keys.length; i++) { - Object o = super.get(keys[i]); - if (!(o instanceof Serializable)) remove(keys[i]); - } - - } - - /** - *

- * Adds the name-value pairs in the given Map to the JobDataMap. - *

- * - *

- * All keys must be Strings, and all values must be Serializable. - *

- */ - public void putAll(Map map) { - Iterator itr = map.keySet().iterator(); - while (itr.hasNext()) { - Object key = itr.next(); - Object val = map.get(key); - - put(key, val); - // will throw IllegalArgumentException if value not serilizable - } - } - - /** - *

- * Adds the given int value to the Job's - * data map. - *

- */ - public void put(String key, int value) { - super.put(key, new Integer(value)); - } - - /** - *

- * Adds the given long value to the Job's - * data map. - *

- */ - public void put(String key, long value) { - super.put(key, new Long(value)); - } - - /** - *

- * Adds the given float value to the Job's - * data map. - *

- */ - public void put(String key, float value) { - super.put(key, new Float(value)); - } - - /** - *

- * Adds the given double value to the Job's - * data map. - *

- */ - public void put(String key, double value) { - super.put(key, new Double(value)); - } - - /** - *

- * Adds the given boolean value to the Job's - * data map. - *

- */ - public void put(String key, boolean value) { - super.put(key, new Boolean(value)); - } - - /** - *

- * Adds the given char value to the Job's - * data map. - *

- */ - public void put(String key, char value) { - super.put(key, new Character(value)); - } - - /** - *

- * Adds the given String value to the Job's - * data map. - *

- */ - public void put(String key, String value) { - super.put(key, value); - } - - /** - *

* Adds the given boolean value as a string version to the * Job's data map. *

*/ public void putAsString(String key, boolean value) { - String strValue = new Boolean(value).toString(); + String strValue = Boolean.valueOf(value).toString(); super.put(key, strValue); } @@ -292,7 +126,7 @@ *

*/ public void putAsString(String key, char value) { - String strValue = new Character(value).toString(); + String strValue = Character.valueOf(value).toString(); super.put(key, strValue); } @@ -316,7 +150,7 @@ *

*/ public void putAsString(String key, double value) { - String strValue = new Double(value).toString(); + String strValue = Double.toString(value); super.put(key, strValue); } @@ -340,7 +174,7 @@ *

*/ public void putAsString(String key, float value) { - String strValue = new Float(value).toString(); + String strValue = Float.toString(value); super.put(key, strValue); } @@ -364,7 +198,7 @@ *

*/ public void putAsString(String key, int value) { - String strValue = new Integer(value).toString(); + String strValue = Integer.valueOf(value).toString(); super.put(key, strValue); } @@ -388,7 +222,7 @@ *

*/ public void putAsString(String key, long value) { - String strValue = new Long(value).toString(); + String strValue = Long.valueOf(value).toString(); super.put(key, strValue); } @@ -407,156 +241,16 @@ /** *

- * Adds the given Serializable object value to the JobDataMap. - *

- */ - public Object put(Object key, Object value) { - if (!(key instanceof String)) - throw new IllegalArgumentException( - "Keys in map must be Strings."); - - return super.put(key, value); - } - - /** - *

* Retrieve the identified int value from the JobDataMap. *

* * @throws ClassCastException - * if the identified object is not an Integer. - */ - public int getInt(String key) { - Object obj = get(key); - - try { - return ((Integer) obj).intValue(); - } catch (Exception e) { - throw new ClassCastException("Identified object is not an Integer."); - } - } - - /** - *

- * Retrieve the identified long value from the JobDataMap. - *

- * - * @throws ClassCastException - * if the identified object is not a Long. - */ - public long getLong(String key) { - Object obj = get(key); - - try { - return ((Long) obj).longValue(); - } catch (Exception e) { - throw new ClassCastException("Identified object is not a Long."); - } - } - - /** - *

- * Retrieve the identified float value from the JobDataMap. - *

- * - * @throws ClassCastException - * if the identified object is not a Float. - */ - public float getFloat(String key) { - Object obj = get(key); - - try { - return ((Float) obj).floatValue(); - } catch (Exception e) { - throw new ClassCastException("Identified object is not a Float."); - } - } - - /** - *

- * Retrieve the identified double value from the JobDataMap. - *

- * - * @throws ClassCastException - * if the identified object is not a Double. - */ - public double getDouble(String key) { - Object obj = get(key); - - try { - return ((Double) obj).doubleValue(); - } catch (Exception e) { - throw new ClassCastException("Identified object is not a Double."); - } - } - - /** - *

- * Retrieve the identified boolean value from the JobDataMap. - *

- * - * @throws ClassCastException - * if the identified object is not a Boolean. - */ - public boolean getBoolean(String key) { - Object obj = get(key); - - try { - return ((Boolean) obj).booleanValue(); - } catch (Exception e) { - throw new ClassCastException("Identified object is not a Boolean."); - } - } - - /** - *

- * Retrieve the identified char value from the JobDataMap. - *

- * - * @throws ClassCastException - * if the identified object is not a Character. - */ - public char getChar(String key) { - Object obj = get(key); - - try { - return ((Character) obj).charValue(); - } catch (Exception e) { - throw new ClassCastException( - "Identified object is not a Character."); - } - } - - /** - *

- * Retrieve the identified String value from the JobDataMap. - *

- * - * @throws ClassCastException * if the identified object is not a String. */ - public String getString(String key) { - Object obj = get(key); - - try { - return (String) obj; - } catch (Exception e) { - throw new ClassCastException("Identified object is not a String."); - } - } - - /** - *

- * Retrieve the identified int value from the JobDataMap. - *

- * - * @throws ClassCastException - * if the identified object is not a String. - */ public int getIntFromString(String key) { Object obj = get(key); - return new Integer((String) obj).intValue(); + return new Integer((String) obj); } /** @@ -565,15 +259,16 @@ *

* * @throws ClassCastException - * if the identified object is not a String or Integeger. + * if the identified object is not a String or Integer. */ - public long getIntValue(String key) { + public int getIntValue(String key) { Object obj = get(key); - if(obj instanceof String) + if(obj instanceof String) { return getIntFromString(key); - else + } else { return getInt(key); + } } /** @@ -601,7 +296,7 @@ public boolean getBooleanValueFromString(String key) { Object obj = get(key); - return new Boolean((String) obj).booleanValue(); + return Boolean.valueOf((String) obj); } /** @@ -616,10 +311,11 @@ public boolean getBooleanValue(String key) { Object obj = get(key); - if(obj instanceof String) + if(obj instanceof String) { return getBooleanValueFromString(key); - else + } else { return getBoolean(key); + } } /** @@ -633,7 +329,7 @@ public Boolean getBooleanFromString(String key) { Object obj = get(key); - return new Boolean((String) obj); + return Boolean.valueOf((String) obj); } /** @@ -661,7 +357,7 @@ public Character getCharacterFromString(String key) { Object obj = get(key); - return new Character(((String) obj).charAt(0)); + return ((String) obj).charAt(0); } /** @@ -675,7 +371,7 @@ public double getDoubleValueFromString(String key) { Object obj = get(key); - return new Double((String) obj).doubleValue(); + return Double.valueOf((String) obj); } /** @@ -689,10 +385,11 @@ public double getDoubleValue(String key) { Object obj = get(key); - if(obj instanceof String) + if(obj instanceof String) { return getDoubleValueFromString(key); - else + } else { return getDouble(key); + } } /** @@ -720,7 +417,7 @@ public float getFloatValueFromString(String key) { Object obj = get(key); - return new Float((String) obj).floatValue(); + return new Float((String) obj); } /** @@ -734,10 +431,11 @@ public float getFloatValue(String key) { Object obj = get(key); - if(obj instanceof String) + if(obj instanceof String) { return getFloatValueFromString(key); - else + } else { return getFloat(key); + } } /** @@ -765,7 +463,7 @@ public long getLongValueFromString(String key) { Object obj = get(key); - return new Long((String) obj).longValue(); + return new Long((String) obj); } /** @@ -779,10 +477,11 @@ public long getLongValue(String key) { Object obj = get(key); - if(obj instanceof String) + if(obj instanceof String) { return getLongValueFromString(key); - else + } else { return getLong(key); + } } /** @@ -798,9 +497,4 @@ return new Long((String) obj); } - - public String[] getKeys() { - return (String[]) keySet().toArray(new String[size()]); - } - } Index: 3rdParty_sources/quartz/org/quartz/JobDetail.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/JobDetail.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/JobDetail.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/JobDetail.java 15 Dec 2014 10:09:47 -0000 1.1.2.1 @@ -1,6 +1,5 @@ - -/* - * Copyright 2004-2005 OpenSymphony +/* + * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,364 +15,67 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; -import java.util.ArrayList; +import java.io.Serializable; /** - *

- * Conveys the detail properties of a given Job instance. - *

+ * Conveys the detail properties of a given Job instance. JobDetails are + * to be created/defined with {@link JobBuilder}. * *

* Quartz does not store an actual instance of a Job class, but * instead allows you to define an instance of one, through the use of a JobDetail. *

* *

- * Job s have a name and group associated with them, which + * Jobs have a name and group associated with them, which * should uniquely identify them within a single {@link Scheduler}. *

* *

- * Trigger s are the 'mechanism' by which Job s - * are scheduled. Many Trigger s can point to the same Job, + * Triggers are the 'mechanism' by which Jobs + * are scheduled. Many Triggers can point to the same Job, * but a single Trigger can only point to one Job. *

* + * @see JobBuilder * @see Job - * @see StatefulJob * @see JobDataMap * @see Trigger * * @author James House - * @author Sharada Jambula */ -public class JobDetail implements Cloneable, java.io.Serializable { +public interface JobDetail extends Serializable, Cloneable { - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Data members. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ + public JobKey getKey(); - private String name; - - private String group = Scheduler.DEFAULT_GROUP; - - private String description; - - private Class jobClass; - - private JobDataMap jobDataMap; - - private boolean volatility = false; - - private boolean durability = false; - - private boolean shouldRecover = false; - - private ArrayList jobListeners = new ArrayList(2); - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Constructors. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - /** *

- * Create a JobDetail with no specified name or group, and - * the default settings of all the other properties. - *

- * - *

- * Note that the {@link #setName(String)},{@link #setGroup(String)}and - * {@link #setJobClass(Class)}methods must be called before the job can be - * placed into a {@link Scheduler} - *

- */ - public JobDetail() { - // do nothing... - } - - /** - *

- * Create a JobDetail with the given name, and group, and - * the default settings of all the other properties. - *

- * - * @param group if null, Scheduler.DEFAULT_GROUP will be used. - * - * @exception IllegalArgumentException - * if nameis null or empty, or the group is an empty string. - */ - public JobDetail(String name, String group, Class jobClass) { - setName(name); - setGroup(group); - setJobClass(jobClass); - } - - /** - *

- * Create a JobDetail with the given name, and group, and - * the given settings of all the other properties. - *

- * - * @param group if null, Scheduler.DEFAULT_GROUP will be used. - * - * @exception IllegalArgumentException - * if nameis null or empty, or the group is an empty string. - */ - public JobDetail(String name, String group, Class jobClass, - boolean volatility, boolean durability, boolean recover) { - setName(name); - setGroup(group); - setJobClass(jobClass); - setVolatility(volatility); - setDurability(durability); - setRequestsRecovery(recover); - } - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Interface. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - /** - *

- * Get the name of this Job. - *

- */ - public String getName() { - return name; - } - - /** - *

- * Set the name of this Job. - *

- * - * @exception IllegalArgumentException - * if name is null or empty. - */ - public void setName(String name) { - if (name == null || name.trim().length() == 0) - throw new IllegalArgumentException("Job name cannot be empty."); - - this.name = name; - } - - /** - *

- * Get the group of this Job. - *

- */ - public String getGroup() { - return group; - } - - /** - *

- * Set the group of this Job. - *

- * - * @param group if null, Scheduler.DEFAULT_GROUP will be used. - * - * @exception IllegalArgumentException - * if the group is an empty string. - */ - public void setGroup(String group) { - if (group != null && group.trim().length() == 0) - throw new IllegalArgumentException( - "Group name cannot be empty."); - - if(group == null) - group = Scheduler.DEFAULT_GROUP; - - this.group = group; - } - - /** - *

- * Returns the 'full name' of the Trigger in the format - * "group.name". - *

- */ - public String getFullName() { - return group + "." + name; - } - - /** - *

* Return the description given to the Job instance by its * creator (if any). *

* * @return null if no description was set. */ - public String getDescription() { - return description; - } + public String getDescription(); /** *

- * Set a description for the Job instance - may be useful - * for remembering/displaying the purpose of the job, though the - * description has no meaning to Quartz. - *

- */ - public void setDescription(String description) { - this.description = description; - } - - /** - *

* Get the instance of Job that will be executed. *

*/ - public Class getJobClass() { - return jobClass; - } + public Class getJobClass(); /** *

- * Set the instance of Job that will be executed. - *

- * - * @exception IllegalArgumentException - * if jobClass is null or the class is not a Job. - */ - public void setJobClass(Class jobClass) { - if (jobClass == null) - throw new IllegalArgumentException("Job class cannot be null."); - - if (!Job.class.isAssignableFrom(jobClass)) - throw new IllegalArgumentException( - "Job class must implement the Job interface."); - - this.jobClass = jobClass; - } - - /** - *

* Get the JobDataMap that is associated with the Job. *

*/ - public JobDataMap getJobDataMap() { - if (jobDataMap == null) jobDataMap = new JobDataMap(); - return jobDataMap; - } + public JobDataMap getJobDataMap(); /** *

- * Set the JobDataMap to be associated with the Job. - *

- */ - public void setJobDataMap(JobDataMap jobDataMap) { - this.jobDataMap = jobDataMap; - } - - /** - *

- * Validates whether the properties of the JobDetail are - * valid for submission into a Scheduler. - * - * @throws IllegalStateException - * if a required property (such as Name, Group, Class) is not - * set. - */ - public void validate() throws SchedulerException { - if (name == null) - throw new SchedulerException("Job's name cannot be null", - SchedulerException.ERR_CLIENT_ERROR); - - if (group == null) - throw new SchedulerException("Job's group cannot be null", - SchedulerException.ERR_CLIENT_ERROR); - - if (jobClass == null) - throw new SchedulerException("Job's class cannot be null", - SchedulerException.ERR_CLIENT_ERROR); - } - - /** - *

- * Set whether or not the Job should be persisted in the - * {@link org.quartz.spi.JobStore} for re-use after program - * restarts. - *

- * - *

- * If not explicitly set, the default value is false. - *

- */ - public void setVolatility(boolean volatility) { - this.volatility = volatility; - } - - /** - *

- * Set whether or not the Job should remain stored after it - * is orphaned (no {@link Trigger}s point to it). - *

- * - *

- * If not explicitly set, the default value is false. - *

- */ - public void setDurability(boolean durability) { - this.durability = durability; - } - - /** - *

- * Set whether or not the the Scheduler should re-execute - * the Job if a 'recovery' or 'fail-over' situation is - * encountered. - *

- * - *

- * If not explicitly set, the default value is false. - *

- * - * @see JobExecutionContext#isRecovering() - * @see JobExecutionContext#isFailedOver() - */ - public void setRequestsRecovery(boolean shouldRecover) { - this.shouldRecover = shouldRecover; - } - - /** - *

- * Whether or not the Job should not be persisted in the - * {@link org.quartz.spi.JobStore} for re-use after program - * restarts. - *

- * - *

- * If not explicitly set, the default value is false. - *

- * - * @return true if the Job should be garbage - * collected along with the {@link Scheduler}. - */ - public boolean isVolatile() { - return volatility; - } - - /** - *

* Whether or not the Job should remain stored after it is * orphaned (no {@link Trigger}s point to it). *

@@ -385,21 +87,19 @@ * @return true if the Job should remain persisted after * being orphaned. */ - public boolean isDurable() { - return durability; - } + public boolean isDurable(); /** - *

- * Whether or not the Job implements the interface {@link StatefulJob}. - *

+ * @see PersistJobDataAfterExecution + * @return whether the associated Job class carries the {@link PersistJobDataAfterExecution} annotation. */ - public boolean isStateful() { - if (jobClass == null) - return false; + public boolean isPersistJobDataAfterExecution(); - return (StatefulJob.class.isAssignableFrom(jobClass)); - } + /** + * @see DisallowConcurrentExecution + * @return whether the associated Job class carries the {@link DisallowConcurrentExecution} annotation. + */ + public boolean isConcurrentExectionDisallowed(); /** *

@@ -413,70 +113,15 @@ *

* * @see JobExecutionContext#isRecovering() - * @see JobExecutionContext#isFailedOver() */ - public boolean requestsRecovery() { - return shouldRecover; - } + public boolean requestsRecovery(); + public Object clone(); + /** - *

- * Add the specified name of a {@link JobListener} to the - * end of the Job's list of listeners. - *

+ * Get a {@link JobBuilder} that is configured to produce a + * JobDetail identical to this one. */ - public void addJobListener(String name) { - jobListeners.add(name); - } + public JobBuilder getJobBuilder(); - /** - *

- * Remove the specified name of a {@link JobListener} from - * the Job's list of listeners. - *

- * - * @return true if the given name was found in the list, and removed - */ - public boolean removeJobListener(String name) { - return jobListeners.remove(name); - } - - /** - *

- * Returns an array of String s containing the names of all - * {@link JobListener} s assigned to the Job, - * in the order in which they should be notified. - *

- */ - public String[] getJobListenerNames() { - return (String[]) jobListeners.toArray(new String[jobListeners.size()]); - } - - /** - *

- * Return a simple string representation of this object. - *

- */ - public String toString() { - return "JobDetail '" + getFullName() + "': jobClass: '" - + ((getJobClass() == null) ? null : getJobClass().getName()) - + " isStateful: " + isStateful() + " isVolatile: " - + isVolatile() + " isDurable: " + isDurable() - + " requestsRecovers: " + requestsRecovery(); - } - - public Object clone() { - JobDetail copy; - try { - copy = (JobDetail) super.clone(); - copy.jobListeners = (ArrayList) jobListeners.clone(); - if (jobDataMap != null) - copy.jobDataMap = (JobDataMap) jobDataMap.clone(); - } catch (CloneNotSupportedException ex) { - throw new IncompatibleClassChangeError("Not Cloneable."); - } - - return copy; - } - -} +} \ No newline at end of file Index: 3rdParty_sources/quartz/org/quartz/JobExecutionContext.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/JobExecutionContext.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/JobExecutionContext.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/JobExecutionContext.java 15 Dec 2014 10:09:46 -0000 1.1.2.1 @@ -1,6 +1,5 @@ - -/* - * Copyright 2004-2005 OpenSymphony +/* + * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,23 +15,15 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; import java.util.Date; -import java.util.HashMap; -import org.quartz.spi.TriggerFiredBundle; - /** - *

* A context bundle containing handles to various environment information, that * is given to a {@link org.quartz.JobDetail} instance as it is * executed, and to a {@link Trigger} instance after the * execution completes. - *

* *

* The JobDataMap found on this object (via the @@ -43,13 +34,14 @@ * It is thus considered a 'best practice' that the execute code of a Job * retrieve data from the JobDataMap found on this object NOTE: Do not * expect value 'set' into this JobDataMap to somehow be set back onto a - * StatefulJob's own JobDataMap. + * job's own JobDataMap - even if it has the + * @PersistJobDataAfterExecution annotation. *

* *

* JobExecutionContext s are also returned from the * Scheduler.getCurrentlyExecutingJobs() - * method. These are the same instances as those past into the jobs that are + * method. These are the same instances as those passed into the jobs that are * currently executing within the scheduler. The exception to this is when your * application is using Quartz remotely (i.e. via RMI) - in which case you get * a clone of the JobExecutionContexts, and their references to @@ -58,145 +50,66 @@ * to the job instance that is running). *

* - * @see #getJobDetail() * @see #getScheduler() * @see #getMergedJobDataMap() + * @see #getJobDetail() * * @see Job * @see Trigger * @see JobDataMap * * @author James House */ -public class JobExecutionContext implements java.io.Serializable { +public interface JobExecutionContext { - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Data members. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - private transient Scheduler scheduler; - - private Trigger trigger; - - private JobDetail jobDetail; - - private JobDataMap jobDataMap; - - private transient Job job; - - private Calendar calendar; - - private boolean recovering = false; - - private int numRefires = 0; - - private Date fireTime; - - private Date scheduledFireTime; - - private Date prevFireTime; - - private Date nextFireTime; - - private long jobRunTime = -1; - - private Object result; - - private HashMap data = new HashMap(); - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Constructors. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - /** *

- * Create a JobExcecutionContext with the given context data. - *

- */ - public JobExecutionContext(Scheduler scheduler, - TriggerFiredBundle firedBundle, Job job) { - this.scheduler = scheduler; - this.trigger = firedBundle.getTrigger(); - this.calendar = firedBundle.getCalendar(); - this.jobDetail = firedBundle.getJobDetail(); - this.job = job; - this.recovering = firedBundle.isRecovering(); - this.fireTime = firedBundle.getFireTime(); - this.scheduledFireTime = firedBundle.getScheduledFireTime(); - this.prevFireTime = firedBundle.getPrevFireTime(); - this.nextFireTime = firedBundle.getNextFireTime(); - - this.jobDataMap = new JobDataMap(); - this.jobDataMap.putAll(jobDetail.getJobDataMap()); - this.jobDataMap.putAll(trigger.getJobDataMap()); - - this.jobDataMap.setMutable(false); - this.trigger.getJobDataMap().setMutable(false); - } - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Interface. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - /** - *

* Get a handle to the Scheduler instance that fired the * Job. *

*/ - public Scheduler getScheduler() { - return scheduler; - } + public Scheduler getScheduler(); /** *

* Get a handle to the Trigger instance that fired the * Job. *

*/ - public Trigger getTrigger() { - return trigger; - } + public Trigger getTrigger(); /** *

* Get a handle to the Calendar referenced by the Trigger * instance that fired the Job. *

*/ - public Calendar getCalendar() { - return calendar; - } + public Calendar getCalendar(); /** *

* If the Job is being re-executed because of a 'recovery' * situation, this method will return true. *

*/ - public boolean isRecovering() { - return recovering; - } + public boolean isRecovering(); - public void incrementRefireCount() { - numRefires++; - } + /** + * Return the {@code TriggerKey} of the originally scheduled and now recovering job. + *

+ * When recovering a previously failed job execution this method returns the identity + * of the originally firing trigger. This recovering job will have been scheduled for + * the same firing time as the original job, and so is available via the + * {@link #getScheduledFireTime()} method. The original firing time of the job can be + * accessed via the {@link Scheduler#FAILED_JOB_ORIGINAL_TRIGGER_FIRETIME_IN_MILLISECONDS} + * element of this job's {@code JobDataMap}. + * + * @return the recovering trigger details + * @throws IllegalStateException if this is not a recovering job. + */ + public TriggerKey getRecoveringTriggerKey() throws IllegalStateException; - public int getRefireCount() { - return numRefires; - } + public int getRefireCount(); /** *

@@ -209,12 +122,12 @@ * JobDetail and the one found on the Trigger, with * the value in the latter overriding any same-named values in the former. * It is thus considered a 'best practice' that the execute code of a Job - * retrieve data from the JobDataMap found on this object + * retrieve data from the JobDataMap found on this object. *

* - *

NOTE: Do not - * expect value 'set' into this JobDataMap to somehow be set back onto a - * StatefulJob's own JobDataMap. + *

NOTE: Do not expect value 'set' into this JobDataMap to somehow be set + * or persisted back onto a job's own JobDataMap - even if it has the + * @PersistJobDataAfterExecution annotation. *

* *

@@ -223,18 +136,14 @@ *

* */ - public JobDataMap getMergedJobDataMap() { - return jobDataMap; - } + public JobDataMap getMergedJobDataMap(); /** *

* Get the JobDetail associated with the Job. *

*/ - public JobDetail getJobDetail() { - return jobDetail; - } + public JobDetail getJobDetail(); /** *

@@ -247,9 +156,7 @@ * interfaces. *

*/ - public Job getJobInstance() { - return job; - } + public Job getJobInstance(); /** * The actual time the trigger fired. For instance the scheduled time may @@ -259,9 +166,7 @@ * @return Returns the fireTime. * @see #getScheduledFireTime() */ - public Date getFireTime() { - return fireTime; - } + public Date getFireTime(); /** * The scheduled time the trigger fired for. For instance the scheduled @@ -271,29 +176,23 @@ * @return Returns the scheduledFireTime. * @see #getFireTime() */ - public Date getScheduledFireTime() { - return scheduledFireTime; - } + public Date getScheduledFireTime(); - public Date getPreviousFireTime() { - return prevFireTime; - } + public Date getPreviousFireTime(); - public Date getNextFireTime() { - return nextFireTime; - } + public Date getNextFireTime(); - public String toString() { - return "JobExecutionContext:" + " trigger: '" - + getTrigger().getFullName() + " job: " - + getJobDetail().getFullName() + " fireTime: '" + getFireTime() - + " scheduledFireTime: " + getScheduledFireTime() - + " previousFireTime: '" + getPreviousFireTime() - + " nextFireTime: " + getNextFireTime() + " isRecovering: " - + isRecovering() + " refireCount: " + getRefireCount(); - } - /** + * Get the unique Id that identifies this particular firing instance of the + * trigger that triggered this job execution. It is unique to this + * JobExecutionContext instance as well. + * + * @return the unique fire instance id + * @see Scheduler#interrupt(String) + */ + public String getFireInstanceId(); + + /** * Returns the result (if any) that the Job set before its * execution completed (the type of object set as the result is entirely up * to the particular job). @@ -307,10 +206,8 @@ * * @return Returns the result. */ - public Object getResult() { - return result; - } - + public Object getResult(); + /** * Set the result (if any) of the Job's execution (the type of * object set as the result is entirely up to the particular job). @@ -321,13 +218,9 @@ * {@link TriggerListener}s that are watching the job's * execution. *

- * - * @return Returns the result. */ - public void setResult(Object result) { - this.result = result; - } - + public void setResult(Object result); + /** * The amount of time the job ran for (in milliseconds). The returned * value will be -1 until the job has actually completed (or thrown an @@ -336,16 +229,7 @@ * * @return Returns the jobRunTime. */ - public long getJobRunTime() { - return jobRunTime; - } - - /** - * @param jobRunTime The jobRunTime to set. - */ - public void setJobRunTime(long jobRunTime) { - this.jobRunTime = jobRunTime; - } + public long getJobRunTime(); /** * Put the specified value into the context's data map with the given key. @@ -355,19 +239,16 @@ * completes, and all TriggerListeners and JobListeners have been * notified.

* - * @param key - * @param value + * @param key the key for the associated value + * @param value the value to store */ - public void put(Object key, Object value) { - data.put(key, value); - } - + public void put(Object key, Object value); + /** * Get the value with the given key from the context's data map. * - * @param key + * @param key the key for the desired value */ - public Object get(Object key) { - return data.get(key); - } -} + public Object get(Object key); + +} \ No newline at end of file Index: 3rdParty_sources/quartz/org/quartz/JobExecutionException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/JobExecutionException.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/JobExecutionException.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/JobExecutionException.java 15 Dec 2014 10:09:46 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,19 +16,14 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; /** - *

* An exception that can be thrown by a {@link org.quartz.Job} * to indicate to the Quartz {@link Scheduler} that an error - * occured while executing, and whether or not the Job requests + * occurred while executing, and whether or not the Job requests * to be re-fired immediately (using the same {@link JobExecutionContext}, * or whether it wants to be unscheduled. - *

* *

* Note that if the flag for 'refire immediately' is set, the flags for @@ -43,6 +38,8 @@ */ public class JobExecutionException extends SchedulerException { + private static final long serialVersionUID = 1326342535829043325L; + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -79,7 +76,7 @@ * Create a JobExcecutionException, with the given cause. *

*/ - public JobExecutionException(Exception cause) { + public JobExecutionException(Throwable cause) { super(cause); } @@ -108,7 +105,7 @@ * the 're-fire immediately' flag set to the given value. *

*/ - public JobExecutionException(Exception cause, boolean refireImmediately) { + public JobExecutionException(Throwable cause, boolean refireImmediately) { super(cause); refire = refireImmediately; @@ -117,16 +114,36 @@ /** *

* Create a JobExcecutionException with the given message, and underlying + * exception. + *

+ */ + public JobExecutionException(String msg, Throwable cause) { + super(msg, cause); + } + + /** + *

+ * Create a JobExcecutionException with the given message, and underlying * exception, and the 're-fire immediately' flag set to the given value. *

*/ - public JobExecutionException(String msg, Exception cause, + public JobExecutionException(String msg, Throwable cause, boolean refireImmediately) { super(msg, cause); refire = refireImmediately; } + + /** + * Create a JobExcecutionException with the given message and the 're-fire + * immediately' flag set to the given value. + */ + public JobExecutionException(String msg, boolean refireImmediately) { + super(msg); + refire = refireImmediately; + } + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -135,6 +152,10 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + public void setRefireImmediately(boolean refire) { + this.refire = refire; + } + public boolean refireImmediately() { return refire; } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/JobKey.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/JobListener.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/JobListener.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/JobListener.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/JobListener.java 15 Dec 2014 10:09:47 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,20 +16,16 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; /** - *

* The interface to be implemented by classes that want to be informed when a * {@link org.quartz.JobDetail} executes. In general, * applications that use a Scheduler will not have use for this * mechanism. - *

* - * @see Scheduler + * @see ListenerManager#addJobListener(JobListener, Matcher) + * @see Matcher * @see Job * @see JobExecutionContext * @see JobExecutionException @@ -52,13 +48,13 @@ * Get the name of the JobListener. *

*/ - public String getName(); + String getName(); /** *

* Called by the {@link Scheduler} when a {@link org.quartz.JobDetail} * is about to be executed (an associated {@link Trigger} - * has occured). + * has occurred). *

* *

@@ -68,19 +64,19 @@ * * @see #jobExecutionVetoed(JobExecutionContext) */ - public void jobToBeExecuted(JobExecutionContext context); + void jobToBeExecuted(JobExecutionContext context); /** *

* Called by the {@link Scheduler} when a {@link org.quartz.JobDetail} * was about to be executed (an associated {@link Trigger} - * has occured), but a {@link TriggerListener} vetoed it's + * has occurred), but a {@link TriggerListener} vetoed it's * execution. *

* * @see #jobToBeExecuted(JobExecutionContext) */ - public void jobExecutionVetoed(JobExecutionContext context); + void jobExecutionVetoed(JobExecutionContext context); /** @@ -90,7 +86,7 @@ * triggered(xx) method has been called. *

*/ - public void jobWasExecuted(JobExecutionContext context, + void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException); } Index: 3rdParty_sources/quartz/org/quartz/JobPersistenceException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/JobPersistenceException.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/JobPersistenceException.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/JobPersistenceException.java 15 Dec 2014 10:09:47 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,20 +16,17 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; /** - *

* An exception that is thrown to indicate that there has been a failure in the * scheduler's underlying persistence mechanism. - *

* * @author James House */ public class JobPersistenceException extends SchedulerException { + + private static final long serialVersionUID = -8924958757341995694L; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -46,38 +43,17 @@ */ public JobPersistenceException(String msg) { super(msg); - setErrorCode(ERR_PERSISTENCE); } - /** - *

- * Create a JobPersistenceException with the given message - * and error code. - *

- */ - public JobPersistenceException(String msg, int errCode) { - super(msg, errCode); - } /** *

* Create a JobPersistenceException with the given message * and cause. *

*/ - public JobPersistenceException(String msg, Exception cause) { + public JobPersistenceException(String msg, Throwable cause) { super(msg, cause); - setErrorCode(ERR_PERSISTENCE); } - /** - *

- * Create a JobPersistenceException with the given message, - * cause and error code. - *

- */ - public JobPersistenceException(String msg, Exception cause, int errorCode) { - super(msg, cause, errorCode); - } - } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/ListenerManager.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/Matcher.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/NthIncludedDayTrigger.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/ObjectAlreadyExistsException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/ObjectAlreadyExistsException.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/ObjectAlreadyExistsException.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/ObjectAlreadyExistsException.java 15 Dec 2014 10:09:46 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,22 +16,19 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; /** - *

* An exception that is thrown to indicate that an attempt to store a new * object (i.e. {@link org.quartz.JobDetail},{@link Trigger} * or {@link Calendar}) in a {@link Scheduler} * failed, because one with the same name & group already exists. - *

* * @author James House */ public class ObjectAlreadyExistsException extends JobPersistenceException { + + private static final long serialVersionUID = -558301282071659896L; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -63,8 +60,7 @@ *

*/ public ObjectAlreadyExistsException(JobDetail offendingJob) { - super("Unable to store Job with name: '" + offendingJob.getName() - + "' and group: '" + offendingJob.getGroup() + super("Unable to store Job : '" + offendingJob.getKey() + "', because one already exists with this identification."); } @@ -81,8 +77,8 @@ */ public ObjectAlreadyExistsException(Trigger offendingTrigger) { super("Unable to store Trigger with name: '" - + offendingTrigger.getName() + "' and group: '" - + offendingTrigger.getGroup() + + offendingTrigger.getKey().getName() + "' and group: '" + + offendingTrigger.getKey().getGroup() + "', because one already exists with this identification."); } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/PersistJobDataAfterExecution.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/ScheduleBuilder.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/Scheduler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/Scheduler.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/Scheduler.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/Scheduler.java 15 Dec 2014 10:09:46 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,26 +16,25 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; import java.util.Date; import java.util.List; +import java.util.Map; import java.util.Set; +import org.quartz.Trigger.TriggerState; +import org.quartz.impl.matchers.GroupMatcher; import org.quartz.spi.JobFactory; +import org.quartz.utils.Key; /** - *

* This is the main interface of a Quartz Scheduler. - *

* *

- * A Scheduler maintains a registery of {@link org.quartz.JobDetail} - * s and {@link Trigger}s. Once registered, the Scheduler - * is responible for executing Job s when their associated + * A Scheduler maintains a registry of {@link org.quartz.JobDetail}s + * and {@link Trigger}s. Once registered, the Scheduler + * is responsible for executing Job s when their associated * Trigger s fire (when their scheduled time arrives). *

* @@ -87,7 +86,8 @@ * provides notifications of Job executions. The {@link TriggerListener} * interface provides notifications of Trigger firings. The * {@link SchedulerListener} interface provides notifications of - * Scheduler events and errors. + * Scheduler events and errors. Listeners can be associated with + * local schedulers through the {@link ListenerManager} interface. *

* *

@@ -97,7 +97,9 @@ * * @see Job * @see JobDetail + * @see JobBuilder * @see Trigger + * @see TriggerBuilder * @see JobListener * @see TriggerListener * @see SchedulerListener @@ -116,40 +118,78 @@ */ /** - *

- * A (possibly) usefull constant that can be used for specifying the group + * A (possibly) useful constant that can be used for specifying the group * that Job and Trigger instances belong to. - *

*/ - public static final String DEFAULT_GROUP = "DEFAULT"; + String DEFAULT_GROUP = Key.DEFAULT_GROUP; /** - *

* A constant Trigger group name used internally by the * scheduler - clients should not use the value of this constant - * ("MANUAL_TRIGGER") for thename of a Trigger's group. - *

+ * ("RECOVERING_JOBS") for the name of a Trigger's group. + * + * @see org.quartz.JobDetail#requestsRecovery() */ - public static final String DEFAULT_MANUAL_TRIGGERS = "MANUAL_TRIGGER"; + String DEFAULT_RECOVERY_GROUP = "RECOVERING_JOBS"; /** - *

* A constant Trigger group name used internally by the * scheduler - clients should not use the value of this constant - * ("RECOVERING_JOBS") for thename of a Trigger's group. - *

+ * ("FAILED_OVER_JOBS") for the name of a Trigger's group. + * + * @see org.quartz.JobDetail#requestsRecovery() */ - public static final String DEFAULT_RECOVERY_GROUP = "RECOVERING_JOBS"; + String DEFAULT_FAIL_OVER_GROUP = "FAILED_OVER_JOBS"; + /** - *

- * A constant Trigger group name used internally by the - * scheduler - clients should not use the value of this constant - * ("FAILED_OVER_JOBS") for thename of a Trigger's group. - *

+ * A constant JobDataMap key that can be used to retrieve the + * name of the original Trigger from a recovery trigger's + * data map in the case of a job recovering after a failed scheduler + * instance. + * + * @see org.quartz.JobDetail#requestsRecovery() */ - public static final String DEFAULT_FAIL_OVER_GROUP = "FAILED_OVER_JOBS"; + String FAILED_JOB_ORIGINAL_TRIGGER_NAME = "QRTZ_FAILED_JOB_ORIG_TRIGGER_NAME"; + /** + * A constant JobDataMap key that can be used to retrieve the + * group of the original Trigger from a recovery trigger's + * data map in the case of a job recovering after a failed scheduler + * instance. + * + * @see org.quartz.JobDetail#requestsRecovery() + */ + String FAILED_JOB_ORIGINAL_TRIGGER_GROUP = "QRTZ_FAILED_JOB_ORIG_TRIGGER_GROUP"; + + /** + * A constant JobDataMap key that can be used to retrieve the + * fire time of the original Trigger from a recovery + * trigger's data map in the case of a job recovering after a failed scheduler + * instance. + * + *

Note that this is the time the original firing actually occurred, + * which may be different from the scheduled fire time - as a trigger doesn't + * always fire exactly on time.

+ * + * @see org.quartz.JobDetail#requestsRecovery() + */ + String FAILED_JOB_ORIGINAL_TRIGGER_FIRETIME_IN_MILLISECONDS = "QRTZ_FAILED_JOB_ORIG_TRIGGER_FIRETIME_IN_MILLISECONDS_AS_STRING"; + + /** + * A constant JobDataMap key that can be used to retrieve the + * scheduled fire time of the original Trigger from a recovery + * trigger's data map in the case of a job recovering after a failed scheduler + * instance. + * + *

Note that this is the time the original firing was scheduled for, + * which may be different from the actual firing time - as a trigger doesn't + * always fire exactly on time.

+ * + * @see org.quartz.JobDetail#requestsRecovery() + */ + String FAILED_JOB_ORIGINAL_TRIGGER_SCHEDULED_FIRETIME_IN_MILLISECONDS = "QRTZ_FAILED_JOB_ORIG_TRIGGER_SCHEDULED_FIRETIME_IN_MILLISECONDS_AS_STRING"; + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -159,39 +199,31 @@ */ /** - *

* Returns the name of the Scheduler. - *

*/ - public String getSchedulerName() throws SchedulerException; + String getSchedulerName() throws SchedulerException; /** - *

* Returns the instance Id of the Scheduler. - *

*/ - public String getSchedulerInstanceId() throws SchedulerException; + String getSchedulerInstanceId() throws SchedulerException; /** - *

* Returns the SchedulerContext of the Scheduler. - *

*/ - public SchedulerContext getContext() throws SchedulerException; + SchedulerContext getContext() throws SchedulerException; /////////////////////////////////////////////////////////////////////////// /// - /// Schedululer State Management Methods + /// Scheduler State Management Methods /// /////////////////////////////////////////////////////////////////////////// - + /** - *

* Starts the Scheduler's threads that fire {@link Trigger}s. * When a scheduler is first created it is in "stand-by" mode, and will not * fire triggers. The scheduler can also be put into stand-by mode by * calling the standby() method. - *

* *

* The misfire/recovery process will be started, if it is the initial call @@ -201,17 +233,48 @@ * @throws SchedulerException * if shutdown() has been called, or there is an * error within the Scheduler. - * - * @see #standby - * @see #shutdown + * + * @see #startDelayed(int) + * @see #standby() + * @see #shutdown() */ - public void start() throws SchedulerException; + void start() throws SchedulerException; /** + * Calls {#start()} after the indicated number of seconds. + * (This call does not block). This can be useful within applications that + * have initializers that create the scheduler immediately, before the + * resources needed by the executing jobs have been fully initialized. + * + * @throws SchedulerException + * if shutdown() has been called, or there is an + * error within the Scheduler. + * + * @see #start() + * @see #standby() + * @see #shutdown() + */ + void startDelayed(int seconds) throws SchedulerException; + + /** + * Whether the scheduler has been started. + * *

- * Temporarily halts the Scheduler's firing of {@link Trigger}s. + * Note: This only reflects whether {@link #start()} has ever + * been called on this Scheduler, so it will return true even + * if the Scheduler is currently in standby mode or has been + * since shutdown. *

* + * @see #start() + * @see #isShutdown() + * @see #isInStandbyMode() + */ + boolean isStarted() throws SchedulerException; + + /** + * Temporarily halts the Scheduler's firing of {@link Trigger}s. + * *

* When start() is called (to bring the scheduler out of * stand-by mode), trigger misfire instructions will NOT be applied @@ -227,50 +290,32 @@ * @see #start() * @see #pauseAll() */ - public void standby() throws SchedulerException; + void standby() throws SchedulerException; /** - * @deprecated replaced by better-named standby() method. - * @see #standby() - */ - public void pause() throws SchedulerException; - - /** - *

* Reports whether the Scheduler is in stand-by mode. - *

* * @see #standby() * @see #start() */ - public boolean isInStandbyMode() throws SchedulerException; + boolean isInStandbyMode() throws SchedulerException; /** - * @deprecated - * @see #isInStandbyMode() - */ - public boolean isPaused() throws SchedulerException; - - /** - *

* Halts the Scheduler's firing of {@link Trigger}s, * and cleans up all resources associated with the Scheduler. Equivalent to * shutdown(false). - *

* *

* The scheduler cannot be re-started. *

* * @see #shutdown(boolean) */ - public void shutdown() throws SchedulerException; + void shutdown() throws SchedulerException; /** - *

* Halts the Scheduler's firing of {@link Trigger}s, * and cleans up all resources associated with the Scheduler. - *

* *

* The scheduler cannot be re-started. @@ -282,33 +327,33 @@ * * @see #shutdown */ - public void shutdown(boolean waitForJobsToComplete) - throws SchedulerException; + void shutdown(boolean waitForJobsToComplete) + throws SchedulerException; /** - *

* Reports whether the Scheduler has been shutdown. - *

*/ - public boolean isShutdown() throws SchedulerException; + boolean isShutdown() throws SchedulerException; /** - *

- * Get a SchedulerMetaData object describiing the settings + * Get a SchedulerMetaData object describing the settings * and capabilities of the scheduler instance. - *

* *

* Note that the data returned is an 'instantaneous' snap-shot, and that as * soon as it's returned, the meta data values may be different. *

*/ - public SchedulerMetaData getMetaData() throws SchedulerException; + SchedulerMetaData getMetaData() throws SchedulerException; /** - *

* Return a list of JobExecutionContext objects that - * represent all currently executing Jobs. + * represent all currently executing Jobs in this Scheduler instance. + * + *

+ * This method is not cluster aware. That is, it will only return Jobs + * currently executing in this Scheduler instance, not across the entire + * cluster. *

* *

@@ -320,37 +365,46 @@ * * @see JobExecutionContext */ - public List getCurrentlyExecutingJobs() throws SchedulerException; + List getCurrentlyExecutingJobs() throws SchedulerException; /** - *

* Set the JobFactory that will be responsible for producing * instances of Job classes. - *

* *

* JobFactories may be of use to those wishing to have their application * produce Job instances via some special mechanism, such as to - * give the opertunity for dependency injection. + * give the opportunity for dependency injection. *

* - * @see org.quart.spi.JobFactory - * @throws SchedulerException + * @see org.quartz.spi.JobFactory */ - public void setJobFactory(JobFactory factory) throws SchedulerException; + void setJobFactory(JobFactory factory) throws SchedulerException; + + /** + * Get a reference to the scheduler's ListenerManager, + * through which listeners may be registered. + * + * @return the scheduler's ListenerManager + * @throws SchedulerException if the scheduler is not local + * @see ListenerManager + * @see JobListener + * @see TriggerListener + * @see SchedulerListener + */ + ListenerManager getListenerManager() throws SchedulerException; + /////////////////////////////////////////////////////////////////////////// /// /// Scheduling-related Methods /// /////////////////////////////////////////////////////////////////////////// /** - *

* Add the given {@link org.quartz.JobDetail} to the * Scheduler, and associate the given {@link Trigger} with * it. - *

* *

* If the given Trigger does not reference any Job, then it @@ -361,272 +415,327 @@ * if the Job or Trigger cannot be added to the Scheduler, or * there is an internal Scheduler error. */ - public Date scheduleJob(JobDetail jobDetail, Trigger trigger) - throws SchedulerException; + Date scheduleJob(JobDetail jobDetail, Trigger trigger) + throws SchedulerException; /** - *

* Schedule the given {@link org.quartz.Trigger} with the * Job identified by the Trigger's settings. - *

* * @throws SchedulerException * if the indicated Job does not exist, or the Trigger cannot be * added to the Scheduler, or there is an internal Scheduler * error. */ - public Date scheduleJob(Trigger trigger) throws SchedulerException; + Date scheduleJob(Trigger trigger) throws SchedulerException; /** - *

+ * Schedule all of the given jobs with the related set of triggers. + * + *

If any of the given jobs or triggers already exist (or more + * specifically, if the keys are not unique) and the replace + * parameter is not set to true then an exception will be thrown.

+ * + * @throws ObjectAlreadyExistsException if the job/trigger keys + * are not unique and the replace flag is not set to true. + */ + void scheduleJobs(Map> triggersAndJobs, boolean replace) throws SchedulerException; + + /** + * Schedule the given job with the related set of triggers. + * + *

If any of the given job or triggers already exist (or more + * specifically, if the keys are not unique) and the replace + * parameter is not set to true then an exception will be thrown.

+ * + * @throws ObjectAlreadyExistsException if the job/trigger keys + * are not unique and the replace flag is not set to true. + */ + void scheduleJob(JobDetail jobDetail, Set triggersForJob, boolean replace) throws SchedulerException; + + /** * Remove the indicated {@link Trigger} from the scheduler. - *

+ * + *

If the related job does not have any other triggers, and the job is + * not durable, then the job will also be deleted.

*/ - public boolean unscheduleJob(String triggerName, String groupName) - throws SchedulerException; + boolean unscheduleJob(TriggerKey triggerKey) + throws SchedulerException; /** - *

+ * Remove all of the indicated {@link Trigger}s from the scheduler. + * + *

If the related job does not have any other triggers, and the job is + * not durable, then the job will also be deleted.

+ * + *

Note that while this bulk operation is likely more efficient than + * invoking unscheduleJob(TriggerKey triggerKey) several + * times, it may have the adverse affect of holding data locks for a + * single long duration of time (rather than lots of small durations + * of time).

+ */ + boolean unscheduleJobs(List triggerKeys) + throws SchedulerException; + + /** * Remove (delete) the {@link org.quartz.Trigger} with the - * given name, and store the new given one - which must be associated + * given key, and store the new given one - which must be associated * with the same job (the new trigger must have the job name & group specified) * - however, the new trigger need not have the same name as the old trigger. - *

* - * @param triggerName - * The name of the Trigger to be replaced. - * @param groupName - * The group name of the Trigger to be replaced. + * @param triggerKey identity of the trigger to replace * @param newTrigger * The new Trigger to be stored. + * * @return null if a Trigger with the given - * name & group was not found and removed from the store, otherwise - * the first fire time of the newly scheduled trigger. + * name & group was not found and removed from the store (and the + * new trigger is therefore not stored), otherwise + * the first fire time of the newly scheduled trigger is returned. */ - public Date rescheduleJob(String triggerName, - String groupName, Trigger newTrigger) throws SchedulerException; - + Date rescheduleJob(TriggerKey triggerKey, Trigger newTrigger) + throws SchedulerException; /** - *

* Add the given Job to the Scheduler - with no associated * Trigger. The Job will be 'dormant' until * it is scheduled with a Trigger, or Scheduler.triggerJob() * is called for it. - *

* *

* The Job must by definition be 'durable', if it is not, * SchedulerException will be thrown. *

- * + * + * @see #addJob(JobDetail, boolean, boolean) + * * @throws SchedulerException * if there is an internal Scheduler error, or if the Job is not * durable, or a Job with the same name already exists, and * replace is false. */ - public void addJob(JobDetail jobDetail, boolean replace) - throws SchedulerException; + void addJob(JobDetail jobDetail, boolean replace) + throws SchedulerException; /** + * Add the given Job to the Scheduler - with no associated + * Trigger. The Job will be 'dormant' until + * it is scheduled with a Trigger, or Scheduler.triggerJob() + * is called for it. + * *

+ * With the storeNonDurableWhileAwaitingScheduling parameter + * set to true, a non-durable job can be stored. Once it is + * scheduled, it will resume normal non-durable behavior (i.e. be deleted + * once there are no remaining associated triggers). + *

+ * + * @throws SchedulerException + * if there is an internal Scheduler error, or if the Job is not + * durable, or a Job with the same name already exists, and + * replace is false. + */ + void addJob(JobDetail jobDetail, boolean replace, boolean storeNonDurableWhileAwaitingScheduling) + throws SchedulerException; + + /** * Delete the identified Job from the Scheduler - and any * associated Triggers. - *

* * @return true if the Job was found and deleted. * @throws SchedulerException * if there is an internal Scheduler error. */ - public boolean deleteJob(String jobName, String groupName) - throws SchedulerException; + boolean deleteJob(JobKey jobKey) + throws SchedulerException; /** - *

- * Trigger the identified {@link org.quartz.JobDetail} - * (execute it now) - the generated trigger will be non-volatile. - *

+ * Delete the identified Jobs from the Scheduler - and any + * associated Triggers. + * + *

Note that while this bulk operation is likely more efficient than + * invoking deleteJob(JobKey jobKey) several + * times, it may have the adverse affect of holding data locks for a + * single long duration of time (rather than lots of small durations + * of time).

+ * + * @return true if all of the Jobs were found and deleted, false if + * one or more were not deleted. + * @throws SchedulerException + * if there is an internal Scheduler error. */ - public void triggerJob(String jobName, String groupName) - throws SchedulerException; - + boolean deleteJobs(List jobKeys) + throws SchedulerException; + /** - *

* Trigger the identified {@link org.quartz.JobDetail} - * (execute it now) - the generated trigger will be volatile. - *

+ * (execute it now). */ - public void triggerJobWithVolatileTrigger(String jobName, String groupName) - throws SchedulerException; + void triggerJob(JobKey jobKey) + throws SchedulerException; /** - *

* Trigger the identified {@link org.quartz.JobDetail} - * (execute it now) - the generated trigger will be non-volatile. - *

+ * (execute it now). * - * @param jobName the name of the Job to trigger - * @param groupName the group name of the Job to trigger * @param data the (possibly null) JobDataMap to be * associated with the trigger that fires the job immediately. */ - public void triggerJob(String jobName, String groupName, JobDataMap data) - throws SchedulerException; + void triggerJob(JobKey jobKey, JobDataMap data) + throws SchedulerException; /** - *

- * Trigger the identified {@link org.quartz.JobDetail} - * (execute it now) - the generated trigger will be volatile. - *

- * - * @param jobName the name of the Job to trigger - * @param groupName the group name of the Job to trigger - * @param data the (possibly null) JobDataMap to be - * associated with the trigger that fires the job immediately. - */ - public void triggerJobWithVolatileTrigger(String jobName, String groupName, JobDataMap data) - throws SchedulerException; - - /** - *

* Pause the {@link org.quartz.JobDetail} with the given - * name - by pausing all of its current Triggers. - *

+ * key - by pausing all of its current Triggers. * - * @see #resumeJob(String, String) + * @see #resumeJob(JobKey) */ - public void pauseJob(String jobName, String groupName) - throws SchedulerException; + void pauseJob(JobKey jobKey) + throws SchedulerException; /** - *

* Pause all of the {@link org.quartz.JobDetail}s in the - * given group - by pausing all of their Triggers. - *

- * + * matching groups - by pausing all of their Triggers. + * *

- * The Scheduler will "remember" that the group is paused, and impose the - * pause on any new jobs that are added to the group while the group is - * paused. + * The Scheduler will "remember" the groups paused, and impose the + * pause on any new jobs that are added to any of those groups + * until it is resumed. *

* - * @see #resumeJobGroup(String) + *

NOTE: There is a limitation that only exactly matched groups + * can be remembered as paused. For example, if there are pre-existing + * job in groups "aaa" and "bbb" and a matcher is given to pause + * groups that start with "a" then the group "aaa" will be remembered + * as paused and any subsequently added jobs in group "aaa" will be paused, + * however if a job is added to group "axx" it will not be paused, + * as "axx" wasn't known at the time the "group starts with a" matcher + * was applied. HOWEVER, if there are pre-existing groups "aaa" and + * "bbb" and a matcher is given to pause the group "axx" (with a + * group equals matcher) then no jobs will be paused, but it will be + * remembered that group "axx" is paused and later when a job is added + * in that group, it will become paused.

+ * + * @param matcher The matcher to evaluate against know groups + * @throws SchedulerException On error + * @see #resumeJobs(org.quartz.impl.matchers.GroupMatcher) */ - public void pauseJobGroup(String groupName) throws SchedulerException; + void pauseJobs(GroupMatcher matcher) throws SchedulerException; /** - *

- * Pause the {@link Trigger} with the given name. - *

+ * Pause the {@link Trigger} with the given key. * - * @see #resumeTrigger(String, String) + * @see #resumeTrigger(TriggerKey) */ - public void pauseTrigger(String triggerName, String groupName) - throws SchedulerException; + void pauseTrigger(TriggerKey triggerKey) + throws SchedulerException; /** - *

- * Pause all of the {@link Trigger}s in the given group. - *

+ * Pause all of the {@link Trigger}s in the groups matching. * *

- * The Scheduler will "remember" that the group is paused, and impose the - * pause on any new triggers that are added to the group while the group is - * paused. + * The Scheduler will "remember" all the groups paused, and impose the + * pause on any new triggers that are added to any of those groups + * until it is resumed. *

* - * @see #resumeTriggerGroup(String) + *

NOTE: There is a limitation that only exactly matched groups + * can be remembered as paused. For example, if there are pre-existing + * triggers in groups "aaa" and "bbb" and a matcher is given to pause + * groups that start with "a" then the group "aaa" will be remembered as + * paused and any subsequently added triggers in that group be paused, + * however if a trigger is added to group "axx" it will not be paused, + * as "axx" wasn't known at the time the "group starts with a" matcher + * was applied. HOWEVER, if there are pre-existing groups "aaa" and + * "bbb" and a matcher is given to pause the group "axx" (with a + * group equals matcher) then no triggers will be paused, but it will be + * remembered that group "axx" is paused and later when a trigger is added + * in that group, it will become paused.

+ * + * @param matcher The matcher to evaluate against know groups + * @throws SchedulerException + * @see #resumeTriggers(org.quartz.impl.matchers.GroupMatcher) */ - public void pauseTriggerGroup(String groupName) throws SchedulerException; + void pauseTriggers(GroupMatcher matcher) throws SchedulerException; /** - *

* Resume (un-pause) the {@link org.quartz.JobDetail} with - * the given name. - *

+ * the given key. * *

* If any of the Job'sTrigger s missed one * or more fire-times, then the Trigger's misfire * instruction will be applied. *

* - * @see #pauseJob(String, String) + * @see #pauseJob(JobKey) */ - public void resumeJob(String jobName, String groupName) - throws SchedulerException; + void resumeJob(JobKey jobKey) + throws SchedulerException; /** - *

* Resume (un-pause) all of the {@link org.quartz.JobDetail}s - * in the given group. - *

+ * in matching groups. * *

* If any of the Job s had Trigger s that * missed one or more fire-times, then the Trigger's * misfire instruction will be applied. *

* - * @see #pauseJobGroup(String) + * @param matcher The matcher to evaluate against known paused groups + * @throws SchedulerException On error + * @see #pauseJobs(GroupMatcher) */ - public void resumeJobGroup(String groupName) throws SchedulerException; + void resumeJobs(GroupMatcher matcher) throws SchedulerException; /** - *

* Resume (un-pause) the {@link Trigger} with the given - * name. - *

+ * key. * *

* If the Trigger missed one or more fire-times, then the * Trigger's misfire instruction will be applied. *

* - * @see #pauseTrigger(String, String) + * @see #pauseTrigger(TriggerKey) */ - public void resumeTrigger(String triggerName, String groupName) - throws SchedulerException; + void resumeTrigger(TriggerKey triggerKey) + throws SchedulerException; /** - *

- * Resume (un-pause) all of the {@link Trigger}s in the - * given group. - *

+ * Resume (un-pause) all of the {@link Trigger}s in matching groups. * *

* If any Trigger missed one or more fire-times, then the * Trigger's misfire instruction will be applied. *

* - * @see #pauseTriggerGroup(String) + * @param matcher The matcher to evaluate against know paused groups + * @throws SchedulerException On error + * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher) */ - public void resumeTriggerGroup(String groupName) throws SchedulerException; + void resumeTriggers(GroupMatcher matcher) throws SchedulerException; /** - *

* Pause all triggers - similar to calling pauseTriggerGroup(group) * on every group, however, after using this method resumeAll() * must be called to clear the scheduler's state of 'remembering' that all * new triggers will be paused as they are added. - *

* *

* When resumeAll() is called (to un-pause), trigger misfire * instructions WILL be applied. *

* * @see #resumeAll() - * @see #pauseTriggerGroup(String) + * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher) * @see #standby() */ - public void pauseAll() throws SchedulerException; + void pauseAll() throws SchedulerException; /** - *

* Resume (un-pause) all triggers - similar to calling * resumeTriggerGroup(group) on every group. - *

* *

* If any Trigger missed one or more fire-times, then the @@ -635,95 +744,89 @@ * * @see #pauseAll() */ - public void resumeAll() throws SchedulerException; + void resumeAll() throws SchedulerException; /** - *

* Get the names of all known {@link org.quartz.JobDetail} * groups. - *

*/ - public String[] getJobGroupNames() throws SchedulerException; + List getJobGroupNames() throws SchedulerException; /** - *

- * Get the names of all the {@link org.quartz.JobDetail}s - * in the given group. - *

+ * Get the keys of all the {@link org.quartz.JobDetail}s + * in the matching groups. + * @param matcher Matcher to evaluate against known groups + * @return Set of all keys matching + * @throws SchedulerException On error */ - public String[] getJobNames(String groupName) throws SchedulerException; + Set getJobKeys(GroupMatcher matcher) throws SchedulerException; /** - *

* Get all {@link Trigger} s that are associated with the * identified {@link org.quartz.JobDetail}. + * + *

The returned Trigger objects will be snap-shots of the actual stored + * triggers. If you wish to modify a trigger, you must re-store the + * trigger afterward (e.g. see {@link #rescheduleJob(TriggerKey, Trigger)}). *

+ * */ - public Trigger[] getTriggersOfJob(String jobName, String groupName) - throws SchedulerException; + List getTriggersOfJob(JobKey jobKey) + throws SchedulerException; /** - *

* Get the names of all known {@link Trigger} groups. - *

*/ - public String[] getTriggerGroupNames() throws SchedulerException; + List getTriggerGroupNames() throws SchedulerException; /** - *

* Get the names of all the {@link Trigger}s in the given * group. - *

+ * @param matcher Matcher to evaluate against known groups + * @return List of all keys matching + * @throws SchedulerException On error */ - public String[] getTriggerNames(String groupName) throws SchedulerException; + Set getTriggerKeys(GroupMatcher matcher) throws SchedulerException; /** - *

* Get the names of all {@link Trigger} groups that are paused. - *

- * - * @return - * @throws SchedulerException */ - public Set getPausedTriggerGroups() throws SchedulerException; + Set getPausedTriggerGroups() throws SchedulerException; /** - *

* Get the {@link JobDetail} for the Job - * instance with the given name and group. + * instance with the given key. + * + *

The returned JobDetail object will be a snap-shot of the actual stored + * JobDetail. If you wish to modify the JobDetail, you must re-store the + * JobDetail afterward (e.g. see {@link #addJob(JobDetail, boolean)}). *

+ * */ - public JobDetail getJobDetail(String jobName, String jobGroup) - throws SchedulerException; + JobDetail getJobDetail(JobKey jobKey) + throws SchedulerException; /** - *

- * Get the {@link Trigger} instance with the given name and - * group. + * Get the {@link Trigger} instance with the given key. + * + *

The returned Trigger object will be a snap-shot of the actual stored + * trigger. If you wish to modify the trigger, you must re-store the + * trigger afterward (e.g. see {@link #rescheduleJob(TriggerKey, Trigger)}). *

*/ - public Trigger getTrigger(String triggerName, String triggerGroup) - throws SchedulerException; + Trigger getTrigger(TriggerKey triggerKey) + throws SchedulerException; /** - *

* Get the current state of the identified {@link Trigger}. - *

* - * @see Trigger#STATE_NORMAL - * @see Trigger#STATE_PAUSED - * @see Trigger#STATE_COMPLETE - * @see Trigger#STATE_ERROR - * @see Trigger#STATE_BLOCKED - * @see Trigger#STATE_NONE + * @see Trigger.TriggerState */ - public int getTriggerState(String triggerName, String triggerGroup) - throws SchedulerException; + TriggerState getTriggerState(TriggerKey triggerKey) + throws SchedulerException; /** - *

* Add (register) the given Calendar to the Scheduler. - *

* * @param updateTriggers whether or not to update existing triggers that * referenced the already existing calendar so that they are 'correct' @@ -735,40 +838,39 @@ * the same name already exists, and replace is * false. */ - public void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers) - throws SchedulerException; + void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers) + throws SchedulerException; /** - *

* Delete the identified Calendar from the Scheduler. + * + *

+ * If removal of the Calendar would result in + * Triggers pointing to non-existent calendars, then a + * SchedulerException will be thrown. *

* * @return true if the Calendar was found and deleted. * @throws SchedulerException - * if there is an internal Scheduler error. + * if there is an internal Scheduler error, or one or more + * triggers reference the calendar */ - public boolean deleteCalendar(String calName) throws SchedulerException; + boolean deleteCalendar(String calName) throws SchedulerException; /** - *

* Get the {@link Calendar} instance with the given name. - *

*/ - public Calendar getCalendar(String calName) throws SchedulerException; + Calendar getCalendar(String calName) throws SchedulerException; /** - *

* Get the names of all registered {@link Calendar}s. - *

*/ - public String[] getCalendarNames() throws SchedulerException; + List getCalendarNames() throws SchedulerException; /** - *

- * Request the interruption of all currently executing instances of the - * identified Job, which must be an implementor of the - * InterruptableJob interface. - *

+ * Request the interruption, within this Scheduler instance, of all + * currently executing instances of the identified Job, which + * must be an implementor of the InterruptableJob interface. * *

* If more than one instance of the identified job is currently executing, @@ -780,198 +882,73 @@ *

* *

- * If you wish to interrupt a specific instance of a job (when more than - * one is executing) you can do so by calling - * {@link #getCurrentlyExecutingJobs()} to obtain a handle - * to the job instance, and then invoke interrupt() on it - * yourself. + * This method is not cluster aware. That is, it will only interrupt + * instances of the identified InterruptableJob currently executing in this + * Scheduler instance, not across the entire cluster. *

* - * @param jobName - * @param groupName - * @return true is at least one instance of the identified job was found + * @return true if at least one instance of the identified job was found * and interrupted. * @throws UnableToInterruptJobException if the job does not implement * InterruptableJob, or there is an exception while * interrupting the job. * @see InterruptableJob#interrupt() * @see #getCurrentlyExecutingJobs() + * @see #interrupt(String) */ - public boolean interrupt(String jobName, String groupName) throws UnableToInterruptJobException; + boolean interrupt(JobKey jobKey) throws UnableToInterruptJobException; - /////////////////////////////////////////////////////////////////////////// - /// - /// Listener-related Methods - /// - /////////////////////////////////////////////////////////////////////////// - /** - *

- * Add the given {@link JobListener} to the Scheduler's - * global list. - *

+ * Request the interruption, within this Scheduler instance, of the + * identified executing Job instance, which + * must be an implementor of the InterruptableJob interface. * *

- * Listeners in the 'global' list receive notification of execution events - * for ALL {@link org.quartz.JobDetail}s. + * This method is not cluster aware. That is, it will only interrupt + * instances of the identified InterruptableJob currently executing in this + * Scheduler instance, not across the entire cluster. *

- */ - public void addGlobalJobListener(JobListener jobListener) - throws SchedulerException; - - /** - *

- * Add the given {@link JobListener} to the Scheduler's - * list, of registered JobListeners. - */ - public void addJobListener(JobListener jobListener) - throws SchedulerException; - - /** - *

- * Remove the given {@link JobListener} from the Scheduler's - * list of global listeners. - *

* - * @return true if the identifed listener was found in the list, and - * removed. + * @param fireInstanceId the unique identifier of the job instance to + * be interrupted (see {@link JobExecutionContext#getFireInstanceId()} + * @return true if the identified job instance was found and interrupted. + * @throws UnableToInterruptJobException if the job does not implement + * InterruptableJob, or there is an exception while + * interrupting the job. + * @see InterruptableJob#interrupt() + * @see #getCurrentlyExecutingJobs() + * @see JobExecutionContext#getFireInstanceId() + * @see #interrupt(JobKey) */ - public boolean removeGlobalJobListener(JobListener jobListener) - throws SchedulerException; - + boolean interrupt(String fireInstanceId) throws UnableToInterruptJobException; + /** - *

- * Remove the identifed {@link JobListener} from the Scheduler's - * list of registered listeners. - *

+ * Determine whether a {@link Job} with the given identifier already + * exists within the scheduler. * - * @return true if the identifed listener was found in the list, and - * removed. + * @param jobKey the identifier to check for + * @return true if a Job exists with the given identifier + * @throws SchedulerException */ - public boolean removeJobListener(String name) throws SchedulerException; - + boolean checkExists(JobKey jobKey) throws SchedulerException; + /** - *

- * Get a List containing all of the {@link JobListener} s in - * the Scheduler'sglobal list. - *

- */ - public List getGlobalJobListeners() throws SchedulerException; - - /** - *

- * Get a Set containing the names of all the non-global{@link JobListener} - * s registered with the Scheduler. - *

- */ - public Set getJobListenerNames() throws SchedulerException; - - /** - *

- * Get the non-global{@link JobListener} that has - * the given name. - *

- */ - public JobListener getJobListener(String name) throws SchedulerException; - - /** - *

- * Add the given {@link TriggerListener} to the Scheduler's - * global list. - *

+ * Determine whether a {@link Trigger} with the given identifier already + * exists within the scheduler. * - *

- * Listeners in the 'global' list receive notification of execution events - * for ALL {@link Trigger}s. - *

+ * @param triggerKey the identifier to check for + * @return true if a Trigger exists with the given identifier + * @throws SchedulerException */ - public void addGlobalTriggerListener(TriggerListener triggerListener) - throws SchedulerException; - + boolean checkExists(TriggerKey triggerKey) throws SchedulerException; + /** - *

- * Add the given {@link TriggerListener} to the Scheduler's - * list, of registered TriggerListeners. - */ - public void addTriggerListener(TriggerListener triggerListener) - throws SchedulerException; - - /** - *

- * Remove the given {@link TriggerListener} from the Scheduler's - * list of global listeners. - *

+ * Clears (deletes!) all scheduling data - all {@link Job}s, {@link Trigger}s + * {@link Calendar}s. * - * @return true if the identifed listener was found in the list, and - * removed. + * @throws SchedulerException */ - public boolean removeGlobalTriggerListener(TriggerListener triggerListener) - throws SchedulerException; + void clear() throws SchedulerException; - /** - *

- * Remove the identifed {@link TriggerListener} from the - * Scheduler's list of registered listeners. - *

- * - * @return true if the identifed listener was found in the list, and - * removed. - */ - public boolean removeTriggerListener(String name) throws SchedulerException; - /** - *

- * Get a List containing all of the {@link TriggerListener} - * s in the Scheduler'sglobal list. - *

- */ - public List getGlobalTriggerListeners() throws SchedulerException; - - /** - *

- * Get a Set containing the names of all the non-global{@link TriggerListener} - * s registered with the Scheduler. - *

- */ - public Set getTriggerListenerNames() throws SchedulerException; - - /** - *

- * Get the non-global{@link TriggerListener} that - * has the given name. - *

- */ - public TriggerListener getTriggerListener(String name) - throws SchedulerException; - - /** - *

- * Register the given {@link SchedulerListener} with the - * Scheduler. - *

- */ - public void addSchedulerListener(SchedulerListener schedulerListener) - throws SchedulerException; - - /** - *

- * Remove the given {@link SchedulerListener} from the - * Scheduler. - *

- * - * @return true if the identifed listener was found in the list, and - * removed. - */ - public boolean removeSchedulerListener(SchedulerListener schedulerListener) - throws SchedulerException; - - /** - *

- * Get a List containing all of the {@link SchedulerListener} - * s registered with the Scheduler. - *

- */ - public List getSchedulerListeners() throws SchedulerException; - - } Index: 3rdParty_sources/quartz/org/quartz/SchedulerConfigException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/SchedulerConfigException.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/SchedulerConfigException.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/SchedulerConfigException.java 15 Dec 2014 10:09:46 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,21 +16,18 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; /** - *

* An exception that is thrown to indicate that there is a misconfiguration of * the SchedulerFactory- or one of the components it * configures. - *

* * @author James House */ public class SchedulerConfigException extends SchedulerException { + + private static final long serialVersionUID = -5921239824646083098L; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -46,7 +43,7 @@ *

*/ public SchedulerConfigException(String msg) { - super(msg, ERR_BAD_CONFIGURATION); + super(msg); } /** @@ -55,9 +52,8 @@ * and cause. *

*/ - public SchedulerConfigException(String msg, Exception cause) { + public SchedulerConfigException(String msg, Throwable cause) { super(msg, cause); - setErrorCode(ERR_BAD_CONFIGURATION); } } Index: 3rdParty_sources/quartz/org/quartz/SchedulerContext.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/SchedulerContext.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/SchedulerContext.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/SchedulerContext.java 15 Dec 2014 10:09:47 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,361 +16,46 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; import java.io.Serializable; -import java.util.Iterator; import java.util.Map; -import org.quartz.utils.DirtyFlagMap; +import org.quartz.utils.StringKeyDirtyFlagMap; /** - *

* Holds context/environment data that can be made available to Jobs as they * are executed. This feature is much like the ServletContext feature when * working with J2EE servlets. - *

* + *

+ * Future versions of Quartz may make distinctions on how it propagates + * data in SchedulerContext between instances of proxies to a + * single scheduler instance - i.e. if Quartz is being used via RMI. + *

+ * * @see Scheduler#getContext * * @author James House */ -public class SchedulerContext extends DirtyFlagMap implements Serializable { - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Data members. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - private boolean allowsTransientData = false; - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Constructors. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - +public class SchedulerContext extends StringKeyDirtyFlagMap implements Serializable { + + private static final long serialVersionUID = -6659641334616491764L; + /** - *

- * Create an empty JobDataMap. - *

+ * Create an empty SchedulerContext. */ public SchedulerContext() { super(15); } /** - *

- * Create a JobDataMap with the given data. - *

+ * Create a SchedulerContext with the given data. */ - public SchedulerContext(Map map) { + public SchedulerContext(Map map) { this(); - - putAll(map); + @SuppressWarnings("unchecked") // param must be a String key map. + Map mapTyped = (Map)map; + putAll(mapTyped); } - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Interface. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - /** - *

- * Tell the SchedulerContext that it should allow non- - * Serializable data. - *

- * - *

- * Future versions of Quartz may make distinctions on how it propogates - * data in the SchedulerContext between instances of proxies to a single - * scheduler instance - i.e. if Quartz is being used via RMI. - *

- */ - public void setAllowsTransientData(boolean allowsTransientData) { - - if (containsTransientData() && !allowsTransientData) - throw new IllegalStateException( - "Cannot set property 'allowsTransientData' to 'false' " - + "when data map contains non-serializable objects."); - - this.allowsTransientData = allowsTransientData; - } - - public boolean getAllowsTransientData() { - return allowsTransientData; - } - - public boolean containsTransientData() { - - if (!getAllowsTransientData()) // short circuit... - return false; - - String[] keys = getKeys(); - - for (int i = 0; i < keys.length; i++) { - Object o = super.get(keys[i]); - if (!(o instanceof Serializable)) return true; - } - - return false; - } - - /** - *

- * Nulls-out any data values that are non-Serializable. - *

- */ - public void removeTransientData() { - - if (!getAllowsTransientData()) // short circuit... - return; - - String[] keys = getKeys(); - - for (int i = 0; i < keys.length; i++) { - Object o = super.get(keys[i]); - if (!(o instanceof Serializable)) remove(keys[i]); - } - - } - - /** - *

- * Adds the name-value pairs in the given Map to the SchedulerContext. - *

- * - *

- * All keys must be Strings. - *

- */ - public void putAll(Map map) { - Iterator itr = map.keySet().iterator(); - while (itr.hasNext()) { - Object key = itr.next(); - Object val = map.get(key); - - put(key, val); - // will throw IllegalArgumentException if value not serilizable - } - } - - /** - *

- * Adds the given int value to the SchedulerContext. - *

- */ - public void put(String key, int value) { - super.put(key, new Integer(value)); - } - - /** - *

- * Adds the given long value to the SchedulerContext. - *

- */ - public void put(String key, long value) { - super.put(key, new Long(value)); - } - - /** - *

- * Adds the given float value to the SchedulerContext. - *

- */ - public void put(String key, float value) { - super.put(key, new Float(value)); - } - - /** - *

- * Adds the given double value to the SchedulerContext. - *

- */ - public void put(String key, double value) { - super.put(key, new Double(value)); - } - - /** - *

- * Adds the given boolean value to the SchedulerContext. - *

- */ - public void put(String key, boolean value) { - super.put(key, new Boolean(value)); - } - - /** - *

- * Adds the given char value to the SchedulerContext. - *

- */ - public void put(String key, char value) { - super.put(key, new Character(value)); - } - - /** - *

- * Adds the given String value to the SchedulerContext. - *

- */ - public void put(String key, String value) { - super.put(key, value); - } - - /** - *

- * Adds the given Object value to the SchedulerContext. - *

- */ - public Object put(Object key, Object value) { - if (!(key instanceof String)) - throw new IllegalArgumentException( - "Keys in map must be Strings."); - - return super.put(key, value); - } - - /** - *

- * Retrieve the identified int value from the SchedulerContext. - *

- * - * @throws ClassCastException - * if the identified object is not an Integer. - */ - public int getInt(String key) { - Object obj = get(key); - - try { - return ((Integer) obj).intValue(); - } catch (Exception e) { - throw new ClassCastException("Identified object is not an Integer."); - } - } - - /** - *

- * Retrieve the identified long value from the SchedulerContext. - *

- * - * @throws ClassCastException - * if the identified object is not a Long. - */ - public long getLong(String key) { - Object obj = get(key); - - try { - return ((Long) obj).longValue(); - } catch (Exception e) { - throw new ClassCastException("Identified object is not a Long."); - } - } - - /** - *

- * Retrieve the identified float value from the SchedulerContext. - *

- * - * @throws ClassCastException - * if the identified object is not a Float. - */ - public float getFloat(String key) { - Object obj = get(key); - - try { - return ((Float) obj).floatValue(); - } catch (Exception e) { - throw new ClassCastException("Identified object is not a Float."); - } - } - - /** - *

- * Retrieve the identified double value from the SchedulerContext. - *

- * - * @throws ClassCastException - * if the identified object is not a Double. - */ - public double getDouble(String key) { - Object obj = get(key); - - try { - return ((Double) obj).doubleValue(); - } catch (Exception e) { - throw new ClassCastException("Identified object is not a Double."); - } - } - - /** - *

- * Retrieve the identified boolean value from the SchedulerContext. - *

- * - * @throws ClassCastException - * if the identified object is not a Boolean. - */ - public boolean getBoolean(String key) { - Object obj = get(key); - - try { - return ((Boolean) obj).booleanValue(); - } catch (Exception e) { - throw new ClassCastException("Identified object is not a Boolean."); - } - } - - /** - *

- * Retrieve the identified char value from the SchedulerContext. - *

- * - * @throws ClassCastException - * if the identified object is not a Character. - */ - public char getChar(String key) { - Object obj = get(key); - - try { - return ((Character) obj).charValue(); - } catch (Exception e) { - throw new ClassCastException( - "Identified object is not a Character."); - } - } - - /** - *

- * Retrieve the identified String value from the SchedulerContext. - *

- * - * @throws ClassCastException - * if the identified object is not a String. - */ - public String getString(String key) { - Object obj = get(key); - - try { - return (String) obj; - } catch (Exception e) { - throw new ClassCastException("Identified object is not a String."); - } - } - - public String[] getKeys() { - return (String[]) keySet().toArray(new String[size()]); - } - } Index: 3rdParty_sources/quartz/org/quartz/SchedulerException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/SchedulerException.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/SchedulerException.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/SchedulerException.java 15 Dec 2014 10:09:47 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,91 +16,27 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; -import java.io.PrintStream; -import java.io.PrintWriter; + /** - *

* Base class for exceptions thrown by the Quartz {@link Scheduler}. - *

* *

- * SchedulerException s may contain a reference to another + * SchedulerExceptions may contain a reference to another * Exception, which was the underlying cause of the SchedulerException. *

* * @author James House */ public class SchedulerException extends Exception { + + private static final long serialVersionUID = 174841398690789156L; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * - * Constants. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - public static final int ERR_UNSPECIFIED = 0; - - public static final int ERR_BAD_CONFIGURATION = 50; - - public static final int ERR_TIME_BROKER_FAILURE = 70; - - public static final int ERR_CLIENT_ERROR = 100; - - public static final int ERR_COMMUNICATION_FAILURE = 200; - - public static final int ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION = 210; - - public static final int ERR_PERSISTENCE = 400; - - public static final int ERR_PERSISTENCE_JOB_DOES_NOT_EXIST = 410; - - public static final int ERR_PERSISTENCE_CALENDAR_DOES_NOT_EXIST = 420; - - public static final int ERR_PERSISTENCE_TRIGGER_DOES_NOT_EXIST = 430; - - public static final int ERR_PERSISTENCE_CRITICAL_FAILURE = 499; - - public static final int ERR_THREAD_POOL = 500; - - public static final int ERR_THREAD_POOL_EXHAUSTED = 510; - - public static final int ERR_THREAD_POOL_CRITICAL_FAILURE = 599; - - public static final int ERR_JOB_LISTENER = 600; - - public static final int ERR_JOB_LISTENER_NOT_FOUND = 610; - - public static final int ERR_TRIGGER_LISTENER = 700; - - public static final int ERR_TRIGGER_LISTENER_NOT_FOUND = 710; - - public static final int ERR_JOB_EXECUTION_THREW_EXCEPTION = 800; - - public static final int ERR_TRIGGER_THREW_EXCEPTION = 850; - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Data members. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - private Exception cause; - - private int errorCode = ERR_UNSPECIFIED; - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * * Constructors. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -114,27 +50,16 @@ super(msg); } - public SchedulerException(String msg, int errorCode) { - super(msg); - setErrorCode(errorCode); + public SchedulerException(Throwable cause) { + super(cause); } - public SchedulerException(Exception cause) { - super(cause.toString()); - this.cause = cause; + public SchedulerException(String msg, Throwable cause) { + super(msg, cause); } - public SchedulerException(String msg, Exception cause) { - super(msg); - this.cause = cause; - } - public SchedulerException(String msg, Exception cause, int errorCode) { - super(msg); - this.cause = cause; - setErrorCode(errorCode); - } - + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -156,167 +81,18 @@ * one. */ public Throwable getUnderlyingException() { - return cause; + return super.getCause(); } - /** - *

- * Get the error code associated with this exception. - *

- * - *

- * This may be used to find more detail about the cause of the error. - *

- * - * @return one of the ERR_XXX constants defined in this class. - */ - public int getErrorCode() { - return errorCode; - } - - /** - *

- * Get the error code associated with this exception. - *

- * - *

- * This may be used to provide more detail about the cause of the error. - *

- * - * @param errorCode - * one of the ERR_XXX constants defined in this class. - */ - public void setErrorCode(int errorCode) { - this.errorCode = errorCode; - } - - /** - *

- * Determine if the specified error code is in the 'ERR_PERSISTENCE' - * category of errors. - *

- */ - public boolean isPersistenceError() { - return (errorCode >= ERR_PERSISTENCE && errorCode <= ERR_PERSISTENCE + 99); - } - - /** - *

- * Determine if the specified error code is in the 'ERR_THREAD_POOL' - * category of errors. - *

- */ - public boolean isThreadPoolError() { - return (errorCode >= ERR_THREAD_POOL && errorCode <= ERR_THREAD_POOL + 99); - } - - /** - *

- * Determine if the specified error code is in the 'ERR_JOB_LISTENER' - * category of errors. - *

- */ - public boolean isJobListenerError() { - return (errorCode >= ERR_JOB_LISTENER && errorCode <= ERR_JOB_LISTENER + 99); - } - - /** - *

- * Determine if the specified error code is in the 'ERR_TRIGGER_LISTENER' - * category of errors. - *

- */ - public boolean isTriggerListenerError() { - return (errorCode >= ERR_TRIGGER_LISTENER && errorCode <= ERR_TRIGGER_LISTENER + 99); - } - - /** - *

- * Determine if the specified error code is in the 'ERR_CLIENT_ERROR' - * category of errors. - *

- */ - public boolean isClientError() { - return (errorCode >= ERR_CLIENT_ERROR && errorCode <= ERR_CLIENT_ERROR + 99); - } - - /** - *

- * Determine if the specified error code is in the 'ERR_CLIENT_ERROR' - * category of errors. - *

- */ - public boolean isConfigurationError() { - return (errorCode >= ERR_BAD_CONFIGURATION && errorCode <= ERR_BAD_CONFIGURATION + 49); - } - + @Override public String toString() { - if (cause == null) return super.toString(); - else - return super.toString() + " [See nested exception: " - + cause.toString() + "]"; - } - - /** - *

- * Print a stack trace to the standard error stream. - *

- * - *

- * This overridden version will print the nested stack trace if available, - * otherwise it prints only this exception's stack. - *

- */ - public void printStackTrace() { - printStackTrace(System.err); - } - - /** - *

- * Print a stack trace to the specified stream. - *

- * - *

- * This overridden version will print the nested stack trace if available, - * otherwise it prints only this exception's stack. - *

- * - * @param out - * the stream to which the stack traces will be printed. - */ - public void printStackTrace(PrintStream out) { - super.printStackTrace(out); - if ((cause != null)) { - synchronized (out) { - out - .println("* Nested Exception (Underlying Cause) ---------------"); - cause.printStackTrace(out); - } + Throwable cause = getUnderlyingException(); + if (cause == null || cause == this) { + return super.toString(); + } else { + return super.toString() + " [See nested exception: " + cause + "]"; } } - /** - *

- * Print a stack trace to the specified writer. - *

- * - *

- * This overridden version will print the nested stack trace if available, - * otherwise it prints this exception's stack. - *

- * - * @param out - * the writer to which the stack traces will be printed. - */ - public void printStackTrace(PrintWriter out) { - super.printStackTrace(out); - if ((cause != null)) { - synchronized (out) { - out - .println("* Nested Exception (Underlying Cause) ---------------"); - cause.printStackTrace(out); - } - } - } } Index: 3rdParty_sources/quartz/org/quartz/SchedulerFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/SchedulerFactory.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/SchedulerFactory.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/SchedulerFactory.java 15 Dec 2014 10:09:46 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,18 +16,13 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; import java.util.Collection; /** - *

* Provides a mechanism for obtaining client-usable handles to Scheduler * instances. - *

* * @see Scheduler * @see org.quartz.impl.StdSchedulerFactory @@ -52,21 +47,21 @@ * @throws SchedulerException * if there is a problem with the underlying Scheduler. */ - public Scheduler getScheduler() throws SchedulerException; + Scheduler getScheduler() throws SchedulerException; /** *

* Returns a handle to the Scheduler with the given name, if it exists. *

*/ - public Scheduler getScheduler(String schedName) throws SchedulerException; + Scheduler getScheduler(String schedName) throws SchedulerException; /** *

* Returns handles to all known Schedulers (made by any SchedulerFactory * within this jvm.). *

*/ - public Collection getAllSchedulers() throws SchedulerException; + Collection getAllSchedulers() throws SchedulerException; } Index: 3rdParty_sources/quartz/org/quartz/SchedulerListener.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/SchedulerListener.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/SchedulerListener.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/SchedulerListener.java 15 Dec 2014 10:09:47 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,16 +16,11 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; /** - *

* The interface to be implemented by classes that want to be informed of major * {@link Scheduler} events. - *

* * @see Scheduler * @see JobListener @@ -49,82 +44,116 @@ * is scheduled. *

*/ - public void jobScheduled(Trigger trigger); + void jobScheduled(Trigger trigger); /** *

* Called by the {@link Scheduler} when a {@link org.quartz.JobDetail} * is unscheduled. *

+ * + * @see SchedulerListener#schedulingDataCleared() */ - public void jobUnscheduled(String triggerName, String triggerGroup); + void jobUnscheduled(TriggerKey triggerKey); /** *

* Called by the {@link Scheduler} when a {@link Trigger} * has reached the condition in which it will never fire again. *

*/ - public void triggerFinalized(Trigger trigger); + void triggerFinalized(Trigger trigger); /** *

* Called by the {@link Scheduler} when a {@link Trigger} - * or group of {@link Trigger}s has been paused. + * has been paused. *

- * + */ + void triggerPaused(TriggerKey triggerKey); + + /** *

- * If a group was paused, then the triggerName parameter - * will be null. + * Called by the {@link Scheduler} when a + * group of {@link Trigger}s has been paused. *

+ * + *

If all groups were paused then triggerGroup will be null

+ * + * @param triggerGroup the paused group, or null if all were paused */ - public void triggersPaused(String triggerName, String triggerGroup); - + void triggersPaused(String triggerGroup); + /** *

* Called by the {@link Scheduler} when a {@link Trigger} - * or group of {@link Trigger}s has been un-paused. + * has been un-paused. *

- * + */ + void triggerResumed(TriggerKey triggerKey); + + /** *

- * If a group was resumed, then the triggerName parameter - * will be null. + * Called by the {@link Scheduler} when a + * group of {@link Trigger}s has been un-paused. *

*/ - public void triggersResumed(String triggerName, String triggerGroup); + void triggersResumed(String triggerGroup); /** *

* Called by the {@link Scheduler} when a {@link org.quartz.JobDetail} - * or group of {@link org.quartz.JobDetail}s has been - * paused. + * has been added. *

- * + */ + void jobAdded(JobDetail jobDetail); + + /** *

- * If a group was paused, then the jobName parameter will be - * null. If all jobs were paused, then both parameters will be null. + * Called by the {@link Scheduler} when a {@link org.quartz.JobDetail} + * has been deleted. *

*/ - public void jobsPaused(String jobName, String jobGroup); - + void jobDeleted(JobKey jobKey); + /** *

* Called by the {@link Scheduler} when a {@link org.quartz.JobDetail} - * or group of {@link org.quartz.JobDetail}s has been - * un-paused. + * has been paused. *

+ */ + void jobPaused(JobKey jobKey); + + /** + *

+ * Called by the {@link Scheduler} when a + * group of {@link org.quartz.JobDetail}s has been paused. + *

* + * @param jobGroup the paused group, or null if all were paused + */ + void jobsPaused(String jobGroup); + + /** *

- * If a group was resumed, then the jobName parameter will - * be null. If all jobs were paused, then both parameters will be null. + * Called by the {@link Scheduler} when a {@link org.quartz.JobDetail} + * has been un-paused. *

*/ - public void jobsResumed(String jobName, String jobGroup); + void jobResumed(JobKey jobKey); /** *

+ * Called by the {@link Scheduler} when a + * group of {@link org.quartz.JobDetail}s has been un-paused. + *

+ */ + void jobsResumed(String jobGroup); + + /** + *

* Called by the {@link Scheduler} when a serious error has - * occured within the scheduler - such as repeated failures in the JobStore, + * occurred within the scheduler - such as repeated failures in the JobStore, * or the inability to instantiate a Job instance when its * Trigger has fired. *

@@ -135,14 +164,51 @@ * error that was encountered. *

*/ - public void schedulerError(String msg, SchedulerException cause); + void schedulerError(String msg, SchedulerException cause); /** *

* Called by the {@link Scheduler} to inform the listener + * that it has move to standby mode. + *

+ */ + void schedulerInStandbyMode(); + + /** + *

+ * Called by the {@link Scheduler} to inform the listener + * that it has started. + *

+ */ + void schedulerStarted(); + + /** + *

+ * Called by the {@link Scheduler} to inform the listener + * that it is starting. + *

+ */ + void schedulerStarting(); + + /** + *

+ * Called by the {@link Scheduler} to inform the listener * that it has shutdown. *

*/ - public void schedulerShutdown(); + void schedulerShutdown(); + + /** + *

+ * Called by the {@link Scheduler} to inform the listener + * that it has begun the shutdown sequence. + *

+ */ + void schedulerShuttingdown(); + /** + * Called by the {@link Scheduler} to inform the listener + * that all jobs, triggers and calendars were deleted. + */ + void schedulingDataCleared(); } Index: 3rdParty_sources/quartz/org/quartz/SchedulerMetaData.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/SchedulerMetaData.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/SchedulerMetaData.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/SchedulerMetaData.java 15 Dec 2014 10:09:46 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,22 +16,19 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; import java.util.Date; /** - *

* Describes the settings and capabilities of a given {@link Scheduler} * instance. - *

* * @author James House */ public class SchedulerMetaData implements java.io.Serializable { + + private static final long serialVersionUID = 4203690002633917647L; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -45,26 +42,28 @@ private String schedInst; - private Class schedClass; + private Class schedClass; private boolean isRemote; private boolean started; - private boolean paused; + private boolean isInStandbyMode; private boolean shutdown; private Date startTime; private int numJobsExec; - private Class jsClass; + private Class jsClass; private boolean jsPersistent; - private Class tpClass; + private boolean jsClustered; + private Class tpClass; + private int tpSize; private String version; @@ -78,21 +77,22 @@ */ public SchedulerMetaData(String schedName, String schedInst, - Class schedClass, boolean isRemote, boolean started, - boolean paused, boolean shutdown, Date startTime, int numJobsExec, - Class jsClass, boolean jsPersistent, Class tpClass, int tpSize, + Class schedClass, boolean isRemote, boolean started, + boolean isInStandbyMode, boolean shutdown, Date startTime, int numJobsExec, + Class jsClass, boolean jsPersistent, boolean jsClustered, Class tpClass, int tpSize, String version) { this.schedName = schedName; this.schedInst = schedInst; this.schedClass = schedClass; this.isRemote = isRemote; this.started = started; - this.paused = paused; + this.isInStandbyMode = isInStandbyMode; this.shutdown = shutdown; this.startTime = startTime; this.numJobsExec = numJobsExec; this.jsClass = jsClass; this.jsPersistent = jsPersistent; + this.jsClustered = jsClustered; this.tpClass = tpClass; this.tpSize = tpSize; this.version = version; @@ -129,7 +129,7 @@ * Returns the class-name of the Scheduler instance. *

*/ - public Class getSchedulerClass() { + public Class getSchedulerClass() { return schedClass; } @@ -140,17 +140,17 @@ * * @return null if the scheduler has not been started. */ - public Date runningSince() { + public Date getRunningSince() { return startTime; } - + /** *

* Returns the number of jobs executed since the Scheduler * started.. *

*/ - public int numJobsExecuted() { + public int getNumberOfJobsExecuted() { return numJobsExec; } @@ -171,25 +171,18 @@ * *

* Note: isStarted() may return true even if - * isPaused() returns true. + * isInStandbyMode() returns true. *

*/ public boolean isStarted() { return started; } /** - *

- * Reports whether the Scheduler is paused. - *

- * - *

- * Note: isStarted() may return true even if - * isPaused() returns true. - *

+ * Reports whether the Scheduler is in standby mode. */ - public boolean isPaused() { - return paused; + public boolean isInStandbyMode() { + return isInStandbyMode; } /** @@ -207,27 +200,37 @@ * being used by the Scheduler. *

*/ - public Class getJobStoreClass() { + public Class getJobStoreClass() { return jsClass; } - + /** *

* Returns whether or not the Scheduler'sJobStore * instance supports persistence. *

*/ - public boolean jobStoreSupportsPersistence() { + public boolean isJobStoreSupportsPersistence() { return jsPersistent; } /** *

+ * Returns whether or not the Scheduler'sJobStore + * is clustered. + *

+ */ + public boolean isJobStoreClustered() { + return jsClustered; + } + + /** + *

* Returns the class-name of the ThreadPool instance that is * being used by the Scheduler. *

*/ - public Class getThreadPoolClass() { + public Class getThreadPoolClass() { return tpClass; } @@ -255,6 +258,7 @@ * Return a simple string representation of this object. *

*/ + @Override public String toString() { try { return getSummary(); @@ -281,7 +285,7 @@ *

*/ public String getSummary() throws SchedulerException { - StringBuffer str = new StringBuffer("Quartz Scheduler (v"); + StringBuilder str = new StringBuilder("Quartz Scheduler (v"); str.append(getVersion()); str.append(") '"); @@ -293,29 +297,34 @@ str.append(" Scheduler class: '"); str.append(getSchedulerClass().getName()); str.append("'"); - if (isSchedulerRemote()) str.append(" - access via RMI."); - else + if (isSchedulerRemote()) { + str.append(" - access via RMI."); + } else { str.append(" - running locally."); + } str.append("\n"); if (!isShutdown()) { - if (runningSince() != null) { + if (getRunningSince() != null) { str.append(" Running since: "); - str.append(runningSince()); - } else - str.append("NOT STARTED."); + str.append(getRunningSince()); + } else { + str.append(" NOT STARTED."); + } str.append("\n"); - if (isPaused()) str.append(" Currently PAUSED."); - else - str.append(" Not currently paused."); + if (isInStandbyMode()) { + str.append(" Currently in standby mode."); + } else { + str.append(" Not currently in standby mode."); + } } else { str.append(" Scheduler has been SHUTDOWN."); } str.append("\n"); str.append(" Number of jobs executed: "); - str.append(numJobsExecuted()); + str.append(getNumberOfJobsExecuted()); str.append("\n"); str.append(" Using thread pool '"); @@ -328,9 +337,16 @@ str.append(" Using job-store '"); str.append(getJobStoreClass().getName()); str.append("' - which "); - if (jobStoreSupportsPersistence()) str.append("supports persistence."); - else + if (isJobStoreSupportsPersistence()) { + str.append("supports persistence."); + } else { str.append("does not support persistence."); + } + if (isJobStoreClustered()) { + str.append(" and is clustered."); + } else { + str.append(" and is not clustered."); + } str.append("\n"); return str.toString(); Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/SimpleScheduleBuilder.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/SimpleTrigger.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/SimpleTrigger.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/SimpleTrigger.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/SimpleTrigger.java 15 Dec 2014 10:09:47 -0000 1.1.2.1 @@ -1,6 +1,5 @@ - -/* - * Copyright 2004-2005 OpenSymphony +/* + * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,37 +15,22 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; -import java.util.Date; - - /** - *

- * A concrete {@link Trigger} that is used to fire a {@link org.quartz.JobDetail} + * A {@link Trigger} that is used to fire a Job * at a given moment in time, and optionally repeated at a specified interval. - *

* - * @see Trigger - * @see CronTrigger - * @see TriggerUtils + * @see TriggerBuilder + * @see SimpleScheduleBuilder * * @author James House * @author contributions by Lieven Govaerts of Ebitec Nv, Belgium. */ -public class SimpleTrigger extends Trigger { +public interface SimpleTrigger extends Trigger { - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Constants. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - + public static final long serialVersionUID = -3735980074222850397L; + /** *

* Instructs the {@link Scheduler} that upon a mis-fire @@ -62,13 +46,15 @@ *

*/ public static final int MISFIRE_INSTRUCTION_FIRE_NOW = 1; - + /** *

* Instructs the {@link Scheduler} that upon a mis-fire * situation, the {@link SimpleTrigger} wants to be * re-scheduled to 'now' (even if the associated {@link Calendar} - * excludes 'now') with the repeat count left as-is. + * excludes 'now') with the repeat count left as-is. This does obey the + * Trigger end-time however, so if 'now' is after the + * end-time the Trigger will not fire again. *

* *

@@ -77,29 +63,27 @@ * is only an issue if you for some reason wanted to be able to tell what * the original values were at some later time). *

- * - *

- * NOTE: This instruction could cause the Trigger - * to go to the 'COMPLETE' state after firing 'now', if all the - * repeat-fire-times where missed. - *

*/ public static final int MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT = 2; - + /** *

* Instructs the {@link Scheduler} that upon a mis-fire * situation, the {@link SimpleTrigger} wants to be * re-scheduled to 'now' (even if the associated {@link Calendar} * excludes 'now') with the repeat count set to what it would be, if it had - * not missed any firings. + * not missed any firings. This does obey the Trigger end-time + * however, so if 'now' is after the end-time the Trigger will + * not fire again. *

* *

* NOTE: Use of this instruction causes the trigger to 'forget' - * the start-time and repeat-count that it was originally setup with (this - * is only an issue if you for some reason wanted to be able to tell what - * the original values were at some later time). + * the start-time and repeat-count that it was originally setup with. + * Instead, the repeat count on the trigger will be changed to whatever + * the remaining repeat count is (this is only an issue if you for some + * reason wanted to be able to tell what the original values were at some + * later time). *

* *

@@ -109,7 +93,7 @@ *

*/ public static final int MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT = 3; - + /** *

* Instructs the {@link Scheduler} that upon a mis-fire @@ -125,7 +109,7 @@ *

*/ public static final int MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT = 4; - + /** *

* Instructs the {@link Scheduler} that upon a mis-fire @@ -136,705 +120,45 @@ *

* *

- * NOTE: Use of this instruction causes the trigger to 'forget' - * the repeat-count that it was originally setup with (this is only an - * issue if you for some reason wanted to be able to tell what the original - * values were at some later time). - *

- * - *

* NOTE/WARNING: This instruction could cause the Trigger - * to go directly to the 'COMPLETE' state if all fire-times where missed. + * to go directly to the 'COMPLETE' state if the end-time of the trigger + * has arrived. *

*/ public static final int MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT = 5; - + /** *

* Used to indicate the 'repeat count' of the trigger is indefinite. Or in * other words, the trigger should repeat continually until the trigger's * ending timestamp. *

*/ - public static int REPEAT_INDEFINITELY = -1; + public static final int REPEAT_INDEFINITELY = -1; - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Data members. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - private Date startTime = null; - - private Date endTime = null; - - private Date nextFireTime = null; - - private Date previousFireTime = null; - - private int repeatCount = 0; - - private long repeatInterval = 0; - - private int timesTriggered = 0; - - private boolean complete = false; - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Constructors. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - /** *

- * Create a SimpleTrigger with no settings. - *

- */ - public SimpleTrigger() { - super(); - } - - /** - *

- * Create a SimpleTrigger that will occur immediately, and - * not repeat. - *

- */ - public SimpleTrigger(String name, String group) { - this(name, group, new Date(), null, 0, 0); - } - - /** - *

- * Create a SimpleTrigger that will occur immediately, and - * repeat at the the given interval the given number of times. - *

- */ - public SimpleTrigger(String name, String group, int repeatCount, - long repeatInterval) { - this(name, group, new Date(), null, repeatCount, repeatInterval); - } - - /** - *

- * Create a SimpleTrigger that will occur at the given time, - * and not repeat. - *

- */ - public SimpleTrigger(String name, String group, Date startTime) { - this(name, group, startTime, null, 0, 0); - } - - /** - *

- * Create a SimpleTrigger that will occur at the given time, - * and repeat at the the given interval the given number of times, or until - * the given end time. - *

- * - * @param startTime - * A Date set to the time for the Trigger - * to fire. - * @param endTime - * A Date set to the time for the Trigger - * to quit repeat firing. - * @param repeatCount - * The number of times for the Trigger to repeat - * firing, use {@link #REPEAT_INDEFINITELY}for unlimitted times. - * @param repeatInterval - * The number of milliseconds to pause between the repeat firing. - */ - public SimpleTrigger(String name, String group, Date startTime, - Date endTime, int repeatCount, long repeatInterval) { - super(name, group); - - setStartTime(startTime); - setEndTime(endTime); - setRepeatCount(repeatCount); - setRepeatInterval(repeatInterval); - } - - /** - *

- * Create a SimpleTrigger that will occur at the given time, - * fire the identified Job and repeat at the the given - * interval the given number of times, or until the given end time. - *

- * - * @param startTime - * A Date set to the time for the Trigger - * to fire. - * @param endTime - * A Date set to the time for the Trigger - * to quit repeat firing. - * @param repeatCount - * The number of times for the Trigger to repeat - * firing, use {@link #REPEAT_INDEFINITELY}for unlimitted times. - * @param repeatInterval - * The number of milliseconds to pause between the repeat firing. - */ - public SimpleTrigger(String name, String group, String jobName, - String jobGroup, Date startTime, Date endTime, int repeatCount, - long repeatInterval) { - super(name, group, jobName, jobGroup); - - setStartTime(startTime); - setEndTime(endTime); - setRepeatCount(repeatCount); - setRepeatInterval(repeatInterval); - } - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Interface. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - /** - *

- * Get the time at which the SimpleTrigger should occur. - *

- */ - public Date getStartTime() { - return startTime; - } - - /** - *

- * Set the time at which the SimpleTrigger should occur. - *

- * - * @exception IllegalArgumentException - * if startTime is null. - */ - public void setStartTime(Date startTime) { - if (startTime == null) - throw new IllegalArgumentException("Start time cannot be null"); - - Date eTime = getEndTime(); - if (eTime != null && startTime != null && eTime.before(startTime)) - throw new IllegalArgumentException( - "End time cannot be before start time"); - - this.startTime = startTime; - } - - /** - *

- * Get the time at which the SimpleTrigger should quit - * repeating - even if repeastCount isn't yet satisfied. - *

- * - * @see #getFinalFireTime() - */ - public Date getEndTime() { - return endTime; - } - - /** - *

- * Set the time at which the SimpleTrigger should quit - * repeating (and be automatically deleted). - *

- * - * @exception IllegalArgumentException - * if endTime is before start time. - */ - public void setEndTime(Date endTime) { - Date sTime = getStartTime(); - if (sTime != null && endTime != null && sTime.after(endTime)) - throw new IllegalArgumentException( - "End time cannot be before start time"); - - this.endTime = endTime; - } - - /** - *

* Get the the number of times the SimpleTrigger should * repeat, after which it will be automatically deleted. *

* * @see #REPEAT_INDEFINITELY */ - public int getRepeatCount() { - return repeatCount; - } + public int getRepeatCount(); /** *

- * Set the the number of time the SimpleTrigger should - * repeat, after which it will be automatically deleted. + * Get the the time interval (in milliseconds) at which the SimpleTrigger should repeat. *

- * - * @see #REPEAT_INDEFINITELY - * @exception IllegalArgumentException - * if repeatCount is < 0 */ - public void setRepeatCount(int repeatCount) { - if (repeatCount < 0 && repeatCount != REPEAT_INDEFINITELY) - throw new IllegalArgumentException( - "Repeat count must be >= 0, use the " - + "constant REPEAT_INDEFINITELY for infinite."); - - this.repeatCount = repeatCount; - } - + public long getRepeatInterval(); + /** *

- * Get the the time interval (in milliseconds) at which the SimpleTrigger - * should repeat. + * Get the number of times the SimpleTrigger has already fired. *

*/ - public long getRepeatInterval() { - return repeatInterval; - } + public int getTimesTriggered(); - /** - *

- * Set the the time interval (in milliseconds) at which the SimpleTrigger - * should repeat. - *

- * - * @exception IllegalArgumentException - * if repeatInterval is <= 0 - */ - public void setRepeatInterval(long repeatInterval) { - if (repeatInterval < 0) - throw new IllegalArgumentException( - "Repeat interval must be >= 0"); - - this.repeatInterval = repeatInterval; - } - - /** - *

- * Get the number of times the SimpleTrigger has already - * fired. - *

- */ - public int getTimesTriggered() { - return timesTriggered; - } - - /** - *

- * Set the number of times the SimpleTrigger has already - * fired. - *

- */ - public void setTimesTriggered(int timesTriggered) { - this.timesTriggered = timesTriggered; - } - - protected boolean validateMisfireInstruction(int misfireInstruction) { - if (misfireInstruction < MISFIRE_INSTRUCTION_SMART_POLICY) - return false; - - if (misfireInstruction > MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT) - return false; - - return true; - } - - /** - *

- * Updates the SimpleTrigger's state based on the - * MISFIRE_INSTRUCTION_XXX that was selected when the SimpleTrigger - * was created. - *

- * - *

- * If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY, - * then the following scheme will be used:
- *

    - *
  • If the Repeat Count is 0, then the instruction will - * be interpreted as MISFIRE_INSTRUCTION_FIRE_NOW.
  • - *
  • If the Repeat Count is REPEAT_INDEFINITELY, then - * the instruction will be interpreted as MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT. - * WARNING: using MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT - * with a trigger that has a non-null end-time may cause the trigger to - * never fire again if the end-time arrived during the misfire time span. - *
  • - *
  • If the Repeat Count is > 0, then the instruction - * will be interpreted as MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT. - *
  • - *
- *

- */ - public void updateAfterMisfire(Calendar cal) { - int instr = getMisfireInstruction(); - if (instr == Trigger.MISFIRE_INSTRUCTION_SMART_POLICY) { - if (getRepeatCount() == 0) instr = MISFIRE_INSTRUCTION_FIRE_NOW; - else if (getRepeatCount() == REPEAT_INDEFINITELY) instr = MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT; - else - // if (getRepeatCount() > 0) - instr = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT; - } else if (instr == MISFIRE_INSTRUCTION_FIRE_NOW - && getRepeatCount() != 0) - instr = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT; - - if (instr == MISFIRE_INSTRUCTION_FIRE_NOW) { - setNextFireTime(new Date()); - } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT) { - Date newFireTime = getFireTimeAfter(new Date()); - while (newFireTime != null && cal != null - && !cal.isTimeIncluded(newFireTime.getTime())) { - newFireTime = getFireTimeAfter(newFireTime); - } - setNextFireTime(newFireTime); - } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT) { - Date newFireTime = getFireTimeAfter(new Date()); - while (newFireTime != null && cal != null - && !cal.isTimeIncluded(newFireTime.getTime())) { - newFireTime = getFireTimeAfter(newFireTime); - } - if (newFireTime != null) { - int timesMissed = computeNumTimesFiredBetween(nextFireTime, - newFireTime); - setTimesTriggered(getTimesTriggered() + timesMissed); - } - - setNextFireTime(newFireTime); - } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT) { - Date newFireTime = new Date(); - if (repeatCount != 0 && repeatCount != REPEAT_INDEFINITELY) { - setRepeatCount(getRepeatCount() - getTimesTriggered()); - setTimesTriggered(0); - } - setStartTime(newFireTime); - setNextFireTime(newFireTime); - } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT) { - Date newFireTime = new Date(); - - int timesMissed = computeNumTimesFiredBetween(nextFireTime, - newFireTime); - - if (repeatCount != 0 && repeatCount != REPEAT_INDEFINITELY) { - int remainingCount = getRepeatCount() - - (getTimesTriggered() + timesMissed); - if (remainingCount <= 0) { - remainingCount = 0; - } - setRepeatCount(remainingCount); - setTimesTriggered(0); - } - - if(getEndTime() != null && getEndTime().before(newFireTime)) - setEndTime(new Date(newFireTime.getTime() + 50)); - - setStartTime(newFireTime); - setNextFireTime(newFireTime); - } - - } - - /** - *

- * Called when the {@link Scheduler} has decided to 'fire' - * the trigger (execute the associated Job), in order to - * give the Trigger a chance to update itself for its next - * triggering (if any). - *

- * - * @see #executionComplete(JobExecutionContext, JobExecutionException) - */ - public void triggered(Calendar calendar) { - timesTriggered++; - previousFireTime = nextFireTime; - nextFireTime = getFireTimeAfter(nextFireTime); - - while (nextFireTime != null && calendar != null - && !calendar.isTimeIncluded(nextFireTime.getTime())) { - nextFireTime = getFireTimeAfter(nextFireTime); - } - } - - /** - * - * @see org.quartz.Trigger#updateWithNewCalendar(org.quartz.Calendar, long) - */ - public void updateWithNewCalendar(Calendar calendar, long misfireThreshold) - { - nextFireTime = getFireTimeAfter(previousFireTime); - - Date now = new Date(); - do { - while (nextFireTime != null && calendar != null - && !calendar.isTimeIncluded(nextFireTime.getTime())) { - nextFireTime = getFireTimeAfter(nextFireTime); - } - - if(nextFireTime != null && nextFireTime.before(now)) { - long diff = now.getTime() - nextFireTime.getTime(); - if(diff >= misfireThreshold) { - nextFireTime = getFireTimeAfter(nextFireTime); - continue; - } - } - }while(false); - } - - /** - *

- * Called by the scheduler at the time a Trigger is first - * added to the scheduler, in order to have the Trigger - * compute its first fire time, based on any associated calendar. - *

- * - *

- * After this method has been called, getNextFireTime() - * should return a valid answer. - *

- * - * @return the first time at which the Trigger will be fired - * by the scheduler, which is also the same value getNextFireTime() - * will return (until after the first firing of the Trigger). - *

- */ - public Date computeFirstFireTime(Calendar calendar) { - nextFireTime = getStartTime(); - - while (nextFireTime != null && calendar != null - && !calendar.isTimeIncluded(nextFireTime.getTime())) { - nextFireTime = getFireTimeAfter(nextFireTime); - } - - return nextFireTime; - } - - /** - *

- * Called after the {@link Scheduler} has executed the - * {@link org.quartz.JobDetail} associated with the Trigger - * in order to get the final instruction code from the trigger. - *

- * - * @param context - * is the JobExecutionContext that was used by the - * Job'sexecute(xx) method. - * @param result - * is the JobExecutionException thrown by the - * Job, if any (may be null). - * @return one of the Trigger.INSTRUCTION_XXX constants. - * - * @see #INSTRUCTION_NOOP - * @see #INSTRUCTION_RE_EXECUTE_JOB - * @see #INSTRUCTION_DELETE_TRIGGER - * @see #INSTRUCTION_SET_TRIGGER_COMPLETE - * @see #triggered(Calendar) - */ - public int executionComplete(JobExecutionContext context, - JobExecutionException result) { - if (result != null && result.refireImmediately()) - return INSTRUCTION_RE_EXECUTE_JOB; - - if (result != null && result.unscheduleFiringTrigger()) - return INSTRUCTION_SET_TRIGGER_COMPLETE; - - if (result != null && result.unscheduleAllTriggers()) - return INSTRUCTION_SET_ALL_JOB_TRIGGERS_COMPLETE; - - if (!mayFireAgain()) return INSTRUCTION_DELETE_TRIGGER; - - return INSTRUCTION_NOOP; - } - - /** - *

- * Returns the next time at which the SimpleTrigger will - * fire. If the trigger will not fire again, null will be - * returned. The value returned is not guaranteed to be valid until after - * the Trigger has been added to the scheduler. - *

- */ - public Date getNextFireTime() { - return nextFireTime; - } - - /** - *

- * Returns the previous time at which the SimpleTrigger will - * fire. If the trigger has not yet fired, null will be - * returned. - */ - public Date getPreviousFireTime() { - return previousFireTime; - } - - /** - *

- * Set the next time at which the SimpleTrigger should fire. - *

- * - *

- * This method should not be invoked by client code. - *

- */ - public void setNextFireTime(Date nextFireTime) { - this.nextFireTime = nextFireTime; - } - - /** - *

- * Set the previous time at which the SimpleTrigger fired. - *

- * - *

- * This method should not be invoked by client code. - *

- */ - public void setPreviousFireTime(Date previousFireTime) { - this.previousFireTime = previousFireTime; - } - - /** - *

- * Returns the next time at which the SimpleTrigger will - * fire, after the given time. If the trigger will not fire after the given - * time, null will be returned. - *

- */ - public Date getFireTimeAfter(Date afterTime) { - if (complete) return null; - - if ((timesTriggered > repeatCount) - && (repeatCount != REPEAT_INDEFINITELY)) return null; - - if (afterTime == null) afterTime = new Date(); - - if (repeatCount == 0 && afterTime.compareTo(getStartTime()) >= 0) - return null; - - long startMillis = getStartTime().getTime(); - long afterMillis = afterTime.getTime(); - long endMillis = (getEndTime() == null) ? Long.MAX_VALUE : getEndTime() - .getTime(); - - if (endMillis <= afterMillis) return null; - - if (startMillis < afterMillis && repeatCount == 0) return null; - - if (afterMillis < startMillis) return new Date(startMillis); - - long numberoftimesexecutedplusone = ((afterMillis - startMillis) / repeatInterval) + 1; - - if ((numberoftimesexecutedplusone > repeatCount) - && (repeatCount != REPEAT_INDEFINITELY)) return null; - - Date time = new Date((numberoftimesexecutedplusone * repeatInterval) - + startMillis); - - if (endMillis <= time.getTime()) return null; - - return time; - } - - /** - *

- * Returns the last time at which the SimpleTrigger will - * fire, before the given time. If the trigger will not fire before the - * given time, null will be returned. - *

- */ - public Date getFireTimeBefore(Date end) { - if (end.getTime() < getStartTime().getTime()) return null; - - int numFires = computeNumTimesFiredBetween(getStartTime(), end); - - return new Date(getStartTime().getTime() + (numFires * repeatInterval)); - } - - public int computeNumTimesFiredBetween(Date start, Date end) { - long time = end.getTime() - start.getTime(); - - return (int) (time / repeatInterval); - } - - /** - *

- * Returns the final time at which the SimpleTrigger will - * fire, if repeatCount is REPEAT_INDEFINITELY, null will be returned. - *

- * - *

- * Note that the return time may be in the past. - *

- */ - public Date getFinalFireTime() { - if (repeatCount == 0) return startTime; - - if (repeatCount == REPEAT_INDEFINITELY && getEndTime() == null) - return null; - - if (repeatCount == REPEAT_INDEFINITELY && getEndTime() == null) return null; - else if (repeatCount == REPEAT_INDEFINITELY) - return getFireTimeBefore(getEndTime()); - - long lastTrigger = startTime.getTime() + (repeatCount * repeatInterval); - - if ((getEndTime() == null) || (lastTrigger < getEndTime().getTime())) return new Date( - lastTrigger); - else - return getFireTimeBefore(getEndTime()); - } - - /** - *

- * Determines whether or not the SimpleTrigger will occur - * again. - *

- */ - public boolean mayFireAgain() { - return (getNextFireTime() != null); - } - - /** - *

- * Validates whether the properties of the JobDetail are - * valid for submission into a Scheduler. - * - * @throws IllegalStateException - * if a required property (such as Name, Group, Class) is not - * set. - */ - public void validate() throws SchedulerException { - super.validate(); - - if (repeatCount != 0 && repeatInterval < 1) - throw new SchedulerException("Repeat Interval cannot be zero.", - SchedulerException.ERR_CLIENT_ERROR); - } - - public static void main(String[] args) // TODO: remove method after good - // unit testing - throws Exception { - - Date sdt = new Date(); - - Date edt = new Date(sdt.getTime() + 55000L); - - SimpleTrigger st = new SimpleTrigger("t", "g", "j", "g", sdt, edt, 10, - 10000L); - - System.err.println(); - - st.computeFirstFireTime(null); - - System.err.println("lastTime=" + st.getFinalFireTime()); - - java.util.List times = TriggerUtils.computeFireTimes(st, null, 50); - - for (int i = 0; i < times.size(); i++) { - System.err.println("firetime = " + times.get(i)); - } - } - + TriggerBuilder getTriggerBuilder(); } Index: 3rdParty_sources/quartz/org/quartz/StatefulJob.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/StatefulJob.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/StatefulJob.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/StatefulJob.java 15 Dec 2014 10:09:46 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,16 +16,11 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; /** - *

* A marker interface for {@link org.quartz.JobDetail} s that * wish to have their state maintained between executions. - *

* *

* StatefulJob instances follow slightly different rules from @@ -37,13 +32,21 @@ * the execute(xx) method will be delayed. *

* + * @see DisallowConcurrentExecution + * @see PersistJobDataAfterExecution + * * @see Job * @see JobDetail * @see JobDataMap * @see Scheduler * + * + * @deprecated use DisallowConcurrentExecution and/or PersistJobDataAfterExecution annotations instead. + * * @author James House */ +@PersistJobDataAfterExecution +@DisallowConcurrentExecution public interface StatefulJob extends Job { /* Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/TimeOfDay.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/Trigger.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/Trigger.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/Trigger.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/Trigger.java 15 Dec 2014 10:09:47 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,126 +16,85 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; +import java.io.Serializable; +import java.util.Comparator; import java.util.Date; -import java.util.LinkedList; + /** - *

- * The base abstract class to be extended by all Triggers. - *

+ * The base interface with properties common to all Triggers - + * use {@link TriggerBuilder} to instantiate an actual Trigger. * *

- * Triggers s have a name and group associated with them, which + * Triggerss have a {@link TriggerKey} associated with them, which * should uniquely identify them within a single {@link Scheduler}. *

* *

- * Triggers are the 'mechanism' by which Job s - * are scheduled. Many Trigger s can point to the same Job, + * Triggers are the 'mechanism' by which Jobs + * are scheduled. Many Triggers can point to the same Job, * but a single Trigger can only point to one Job. *

* *

* Triggers can 'send' parameters/data to Jobs by placing contents * into the JobDataMap on the Trigger. *

- * - * @see SimpleTrigger - * @see CronTrigger - * @see NthIncludedDayTrigger - * @see TriggerUtils + * + * @see TriggerBuilder * @see JobDataMap * @see JobExecutionContext + * @see TriggerUtils + * @see SimpleTrigger + * @see CronTrigger + * @see CalendarIntervalTrigger * * @author James House - * @author Sharada Jambula */ -public abstract class Trigger implements java.io.Serializable, Cloneable, - Comparable { +public interface Trigger extends Serializable, Cloneable, Comparable { - private static final long serialVersionUID = -3904243490805975570L; + public static final long serialVersionUID = -3904243490805975570L; - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + public enum TriggerState { NONE, NORMAL, PAUSED, COMPLETE, ERROR, BLOCKED } + + /** + *

NOOP Instructs the {@link Scheduler} that the + * {@link Trigger} has no further instructions.

* - * Constants. + *

RE_EXECUTE_JOB Instructs the {@link Scheduler} that the + * {@link Trigger} wants the {@link org.quartz.JobDetail} to + * re-execute immediately. If not in a 'RECOVERING' or 'FAILED_OVER' situation, the + * execution context will be re-used (giving the Job the + * ability to 'see' anything placed in the context by its last execution).

* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + *

SET_TRIGGER_COMPLETE Instructs the {@link Scheduler} that the + * {@link Trigger} should be put in the COMPLETE state.

+ * + *

DELETE_TRIGGER Instructs the {@link Scheduler} that the + * {@link Trigger} wants itself deleted.

+ * + *

SET_ALL_JOB_TRIGGERS_COMPLETE Instructs the {@link Scheduler} + * that all Triggers referencing the same {@link org.quartz.JobDetail} + * as this one should be put in the COMPLETE state.

+ * + *

SET_TRIGGER_ERROR Instructs the {@link Scheduler} that all + * Triggers referencing the same {@link org.quartz.JobDetail} as + * this one should be put in the ERROR state.

+ * + *

SET_ALL_JOB_TRIGGERS_ERROR Instructs the {@link Scheduler} that + * the Trigger should be put in the ERROR state.

*/ + public enum CompletedExecutionInstruction { NOOP, RE_EXECUTE_JOB, SET_TRIGGER_COMPLETE, DELETE_TRIGGER, + SET_ALL_JOB_TRIGGERS_COMPLETE, SET_TRIGGER_ERROR, SET_ALL_JOB_TRIGGERS_ERROR } /** - *

- * Instructs the {@link Scheduler} that the {@link Trigger} - * has no further instructions. - *

- */ - public static final int INSTRUCTION_NOOP = 0; - - /** - *

- * Instructs the {@link Scheduler} that the {@link Trigger} - * wants the {@link org.quartz.JobDetail} to re-execute - * immediately. If not in a 'RECOVERING' or 'FAILED_OVER' situation, the - * execution context will be re-used (giving the Job the - * abilitiy to 'see' anything placed in the context by its last execution). - *

- */ - public static final int INSTRUCTION_RE_EXECUTE_JOB = 1; - - /** - *

- * Instructs the {@link Scheduler} that the {@link Trigger} - * should be put in the COMPLETE state. - *

- */ - public static final int INSTRUCTION_SET_TRIGGER_COMPLETE = 2; - - /** - *

- * Instructs the {@link Scheduler} that the {@link Trigger} - * wants itself deleted. - *

- */ - public static final int INSTRUCTION_DELETE_TRIGGER = 3; - - /** - *

- * Instructs the {@link Scheduler} that all Trigger - * s referencing the same {@link org.quartz.JobDetail} as - * this one should be put in the COMPLETE state. - *

- */ - public static final int INSTRUCTION_SET_ALL_JOB_TRIGGERS_COMPLETE = 4; - - /** - *

- * Instructs the {@link Scheduler} that all Trigger - * s referencing the same {@link org.quartz.JobDetail} as - * this one should be put in the ERROR state. - *

- */ - public static final int INSTRUCTION_SET_TRIGGER_ERROR = 5; - - /** - *

- * Instructs the {@link Scheduler} that the Trigger - * should be put in the ERROR state. - *

- */ - public static final int INSTRUCTION_SET_ALL_JOB_TRIGGERS_ERROR = 6; - - /** - *

* Instructs the {@link Scheduler} that upon a mis-fire * situation, the updateAfterMisfire() method will be called - * on the Trigger to determine the mis-fire instruction. - *

+ * on the Trigger to determine the mis-fire instruction, + * which logic will be trigger-implementation-dependent. * *

* In order to see if this instruction fits your needs, you should look at @@ -144,788 +103,227 @@ *

*/ public static final int MISFIRE_INSTRUCTION_SMART_POLICY = 0; - + /** - *

- * Indicates that the Trigger is in the "normal" state. - *

- */ - public final static int STATE_NORMAL = 0; - - /** - *

- * Indicates that the Trigger is in the "paused" state. - *

- */ - public final static int STATE_PAUSED = 1; - - /** - *

- * Indicates that the Trigger is in the "complete" state. - *

+ * Instructs the {@link Scheduler} that the + * Trigger will never be evaluated for a misfire situation, + * and that the scheduler will simply try to fire it as soon as it can, + * and then update the Trigger as if it had fired at the proper time. * - *

- * "Complete" indicates that the trigger has not remaining fire-times in - * its schedule. - *

+ *

NOTE: if a trigger uses this instruction, and it has missed + * several of its scheduled firings, then several rapid firings may occur + * as the trigger attempt to catch back up to where it would have been. + * For example, a SimpleTrigger that fires every 15 seconds which has + * misfired for 5 minutes will fire 20 times once it gets the chance to + * fire.

*/ - public final static int STATE_COMPLETE = 2; - + public static final int MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1; + /** - *

- * Indicates that the Trigger is in the "error" state. - *

- * - *

- * A Trigger arrives at the error state when the scheduler - * attempts to fire it, but cannot due to an error creating and executing - * its related job. Often this is due to the Job's - * class not existing in the classpath. - *

- * - *

- * When the trigger is in the error state, the scheduler will make no - * attempts to fire it. - *

+ * The default value for priority. */ - public final static int STATE_ERROR = 3; + public static final int DEFAULT_PRIORITY = 5; + public TriggerKey getKey(); - /** - *

- * Indicates that the Trigger is in the "blocked" state. - *

- * - *

- * A Trigger arrives at the blocked state when the job that - * it is associated with is a StatefulJob and it is - * currently executing. - *

- * - * @see StatefulJob - */ - public final static int STATE_BLOCKED = 4; - - /** - *

- * Indicates that the Trigger does not exist. - *

- */ - public final static int STATE_NONE = -1; - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Data members. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - private String name; - - private String group = Scheduler.DEFAULT_GROUP; - - private String jobName; - - private String jobGroup = Scheduler.DEFAULT_GROUP; - - private String description; + public JobKey getJobKey(); - private JobDataMap jobDataMap; - - private boolean volatility = false; - - private String calendarName = null; - - private String fireInstanceId = null; - - private int misfireInstruction = MISFIRE_INSTRUCTION_SMART_POLICY; - - private LinkedList triggerListeners = new LinkedList(); - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Constructors. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - /** - *

- * Create a Trigger with no specified name, group, or {@link org.quartz.JobDetail}. - *

- * - *

- * Note that the {@link #setName(String)},{@link #setGroup(String)}and - * the {@link #setJobName(String)}and {@link #setJobGroup(String)}methods - * must be called before the Trigger can be placed into a - * {@link Scheduler}. - *

- */ - public Trigger() { - // do nothing... - } - - /** - *

- * Create a Trigger with the given name, and group. - *

- * - *

- * Note that the {@link #setJobName(String)}and - * {@link #setJobGroup(String)}methods must be called before the Trigger - * can be placed into a {@link Scheduler}. - *

- * - * @param group if null, Scheduler.DEFAULT_GROUP will be used. - * - * @exception IllegalArgumentException - * if name is null or empty, or the group is an empty string. - */ - public Trigger(String name, String group) { - setName(name); - setGroup(group); - } - - /** - *

- * Create a Trigger with the given name, and group. - *

- * - * @param group if null, Scheduler.DEFAULT_GROUP will be used. - * - * @exception IllegalArgumentException - * if name is null or empty, or the group is an empty string. - */ - public Trigger(String name, String group, String jobName, String jobGroup) { - setName(name); - setGroup(group); - setJobName(jobName); - setJobGroup(jobGroup); - } - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Interface. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - /** - *

- * Get the name of this Trigger. - *

- */ - public String getName() { - return name; - } - - /** - *

- * Set the name of this Trigger. - *

- * - * @exception IllegalArgumentException - * if name is null or empty. - */ - public void setName(String name) { - if (name == null || name.trim().length() == 0) - throw new IllegalArgumentException( - "Trigger name cannot be null or empty."); - - this.name = name; - } - - /** - *

- * Get the group of this Trigger. - *

- */ - public String getGroup() { - return group; - } - - /** - *

- * Set the name of this Trigger. - *

- * - * @param group if null, Scheduler.DEFAULT_GROUP will be used. - * - * @exception IllegalArgumentException - * if group is an empty string. - */ - public void setGroup(String group) { - if (group != null && group.trim().length() == 0) - throw new IllegalArgumentException( - "Group name cannot be an empty string."); - - if(group == null) - group = Scheduler.DEFAULT_GROUP; - - this.group = group; - } - - /** - *

- * Get the name of the associated {@link org.quartz.JobDetail}. - *

- */ - public String getJobName() { - return jobName; - } - - /** - *

- * Set the name of the associated {@link org.quartz.JobDetail}. - *

- * - * @exception IllegalArgumentException - * if jobName is null or empty. - */ - public void setJobName(String jobName) { - if (jobName == null || jobName.trim().length() == 0) - throw new IllegalArgumentException( - "Job name cannot be null or empty."); - - this.jobName = jobName; - } - - /** - *

- * Get the name of the associated {@link org.quartz.JobDetail}'s - * group. - *

- */ - public String getJobGroup() { - return jobGroup; - } - - /** - *

- * Set the name of the associated {@link org.quartz.JobDetail}'s - * group. - *

- * - * @param group if null, Scheduler.DEFAULT_GROUP will be used. - * - * @exception IllegalArgumentException - * if group is an empty string. - */ - public void setJobGroup(String jobGroup) { - if (jobGroup != null && jobGroup.trim().length() == 0) - throw new IllegalArgumentException( - "Group name cannot be null or empty."); - - if(jobGroup == null) - jobGroup = Scheduler.DEFAULT_GROUP; - - this.jobGroup = jobGroup; - } - - /** - *

- * Returns the 'full name' of the Trigger in the format - * "group.name". - *

- */ - public String getFullName() { - return group + "." + name; - } - - /** - *

- * Returns the 'full name' of the Job that the Trigger - * points to, in the format "group.name". - *

- */ - public String getFullJobName() { - return jobGroup + "." + jobName; - } - - /** - *

* Return the description given to the Trigger instance by * its creator (if any). - *

* * @return null if no description was set. */ - public String getDescription() { - return description; - } + public String getDescription(); /** - *

- * Set a description for the Trigger instance - may be - * useful for remembering/displaying the purpose of the trigger, though the - * description has no meaning to Quartz. - *

- */ - public void setDescription(String description) { - this.description = description; - } - - /** - *

- * Set whether or not the Trigger should be persisted in the - * {@link org.quartz.spi.JobStore} for re-use after program - * restarts. - *

- */ - public void setVolatility(boolean volatility) { - this.volatility = volatility; - } - - /** - *

- * Associate the {@link Calendar} with the given name with - * this Trigger. - *

- * - * @param calendarName - * use null to dis-associate a Calendar. - */ - public void setCalendarName(String calendarName) { - this.calendarName = calendarName; - } - - /** - *

* Get the name of the {@link Calendar} associated with this * Trigger. - *

* * @return null if there is no associated Calendar. */ - public String getCalendarName() { - return calendarName; - } + public String getCalendarName(); /** - *

* Get the JobDataMap that is associated with the * Trigger. - *

* *

* Changes made to this map during job execution are not re-persisted, and * in fact typically result in an IllegalStateException. *

*/ - public JobDataMap getJobDataMap() { - if (jobDataMap == null) jobDataMap = new JobDataMap(); - return jobDataMap; - } + public JobDataMap getJobDataMap(); - /** - *

- * Set the JobDataMap to be associated with the - * Trigger. - *

- */ - public void setJobDataMap(JobDataMap jobDataMap) { - this.jobDataMap = jobDataMap; - } - - /** - *

- * Whether or not the Trigger should be persisted in the - * {@link org.quartz.spi.JobStore} for re-use after program - * restarts. - *

+ * The priority of a Trigger acts as a tiebreaker such that if + * two Triggers have the same scheduled fire time, then the + * one with the higher priority will get first access to a worker + * thread. * *

- * If not explicitly set, the default value is false. + * If not explicitly set, the default value is 5. *

* - * @return true if the Trigger should be - * garbage collected along with the {@link Scheduler}. + * @see #DEFAULT_PRIORITY */ - public boolean isVolatile() { - return volatility; - } + public int getPriority(); /** - *

- * Add the specified name of a {@link TriggerListener} to - * the end of the Trigger's list of listeners. - *

- */ - public void addTriggerListener(String name) { - triggerListeners.add(name); - } - - /** - *

- * Remove the specified name of a {@link TriggerListener} - * from the Trigger's list of listeners. - *

- * - * @return true if the given name was found in the list, and removed - */ - public boolean removeTriggerListener(String name) { - return triggerListeners.remove(name); - } - - /** - *

- * Returns an array of String s containing the names of all - * {@link TriggerListener} assigned to the Trigger, - * in the order in which they should be notified. - *

- */ - public String[] getTriggerListenerNames() { - String[] outNames = new String[triggerListeners.size()]; - return (String[]) triggerListeners.toArray(outNames); - } - - /** - *

- * This method should not be used by the Quartz client. - *

- * - *

- * Called when the {@link Scheduler} has decided to 'fire' - * the trigger (execute the associated Job), in order to - * give the Trigger a chance to update itself for its next - * triggering (if any). - *

- * - * @see #executionComplete(JobExecutionContext, JobExecutionException) - */ - public abstract void triggered(Calendar calendar); - - /** - *

- * This method should not be used by the Quartz client. - *

- * - *

- * Called by the scheduler at the time a Trigger is first - * added to the scheduler, in order to have the Trigger - * compute its first fire time, based on any associated calendar. - *

- * - *

- * After this method has been called, getNextFireTime() - * should return a valid answer. - *

- * - * @return the first time at which the Trigger will be fired - * by the scheduler, which is also the same value getNextFireTime() - * will return (until after the first firing of the Trigger). - *

- */ - public abstract Date computeFirstFireTime(Calendar calendar); - - /** - *

- * This method should not be used by the Quartz client. - *

- * - *

- * Called after the {@link Scheduler} has executed the - * {@link org.quartz.JobDetail} associated with the Trigger - * in order to get the final instruction code from the trigger. - *

- * - * @param context - * is the JobExecutionContext that was used by the - * Job'sexecute(xx) method. - * @param result - * is the JobExecutionException thrown by the - * Job, if any (may be null). - * @return one of the Trigger.INSTRUCTION_XXX constants. - * - * @see #INSTRUCTION_NOOP - * @see #INSTRUCTION_RE_EXECUTE_JOB - * @see #INSTRUCTION_DELETE_TRIGGER - * @see #INSTRUCTION_SET_TRIGGER_COMPLETE - * @see #triggered(Calendar) - */ - public abstract int executionComplete(JobExecutionContext context, - JobExecutionException result); - - /** - *

* Used by the {@link Scheduler} to determine whether or not * it is possible for this Trigger to fire again. - *

* *

* If the returned value is false then the Scheduler * may remove the Trigger from the {@link org.quartz.spi.JobStore}. *

*/ - public abstract boolean mayFireAgain(); + public boolean mayFireAgain(); /** - *

* Get the time at which the Trigger should occur. - *

*/ - public abstract Date getStartTime(); + public Date getStartTime(); - public abstract void setStartTime(Date startTime); - - public abstract void setEndTime(Date endTime); - /** - *

* Get the time at which the Trigger should quit repeating - - * even if an assigned 'repeatCount' isn't yet satisfied. - *

+ * regardless of any remaining repeats (based on the trigger's particular + * repeat settings). * * @see #getFinalFireTime() */ - public abstract Date getEndTime(); + public Date getEndTime(); /** - *

- * Returns the next time at which the Trigger will fire. If - * the trigger will not fire again, null will be returned. - * The value returned is not guaranteed to be valid until after the Trigger + * Returns the next time at which the Trigger is scheduled to fire. If + * the trigger will not fire again, null will be returned. Note that + * the time returned can possibly be in the past, if the time that was computed + * for the trigger to next fire has already arrived, but the scheduler has not yet + * been able to fire the trigger (which would likely be due to lack of resources + * e.g. threads). + * + *

The value returned is not guaranteed to be valid until after the Trigger * has been added to the scheduler. *

+ * + * @see TriggerUtils#computeFireTimesBetween(org.quartz.spi.OperableTrigger, Calendar, java.util.Date, java.util.Date) */ - public abstract Date getNextFireTime(); + public Date getNextFireTime(); /** - *

- * Returns the previous time at which the Trigger will fire. + * Returns the previous time at which the Trigger fired. * If the trigger has not yet fired, null will be returned. */ - public abstract Date getPreviousFireTime(); + public Date getPreviousFireTime(); /** - *

* Returns the next time at which the Trigger will fire, * after the given time. If the trigger will not fire after the given time, * null will be returned. - *

*/ - public abstract Date getFireTimeAfter(Date afterTime); + public Date getFireTimeAfter(Date afterTime); /** - *

* Returns the last time at which the Trigger will fire, if * the Trigger will repeat indefinitely, null will be returned. - *

* *

* Note that the return time *may* be in the past. *

*/ - public abstract Date getFinalFireTime(); + public Date getFinalFireTime(); /** - *

- * Set the instruction the Scheduler should be given for - * handling misfire situations for this Trigger- the - * concrete Trigger type that you are using will have - * defined a set of additional MISFIRE_INSTRUCTION_XXX - * constants that may be passed to this method. - *

- * - *

- * If not explicitly set, the default value is MISFIRE_INSTRUCTION_SMART_POLICY. - *

- * - * @see #MISFIRE_INSTRUCTION_SMART_POLICY - * @see #updateAfterMisfire(Calendar) - * @see SimpleTrigger - * @see CronTrigger - */ - public void setMisfireInstruction(int misfireInstruction) { - if (!validateMisfireInstruction(misfireInstruction)) - throw new IllegalArgumentException( - "The misfire instruction code is invalid for this type of trigger."); - this.misfireInstruction = misfireInstruction; - } - - protected abstract boolean validateMisfireInstruction(int misfireInstruction); - - /** - *

* Get the instruction the Scheduler should be given for * handling misfire situations for this Trigger- the * concrete Trigger type that you are using will have * defined a set of additional MISFIRE_INSTRUCTION_XXX - * constants that may be passed to this method. - *

+ * constants that may be set as this property's value. * *

* If not explicitly set, the default value is MISFIRE_INSTRUCTION_SMART_POLICY. *

* * @see #MISFIRE_INSTRUCTION_SMART_POLICY - * @see #updateAfterMisfire(Calendar) * @see SimpleTrigger * @see CronTrigger */ - public int getMisfireInstruction() { - return misfireInstruction; - } + public int getMisfireInstruction(); /** - *

- * This method should not be used by the Quartz client. - *

+ * Get a {@link TriggerBuilder} that is configured to produce a + * Trigger identical to this one. * - *

- * To be implemented by the concrete classes that extend this class. - *

- * - *

- * The implementation should update the Trigger's state - * based on the MISFIRE_INSTRUCTION_XXX that was selected when the Trigger - * was created. - *

+ * @see #getScheduleBuilder() */ - public abstract void updateAfterMisfire(Calendar cal); - + public TriggerBuilder getTriggerBuilder(); + /** - *

- * This method should not be used by the Quartz client. - *

+ * Get a {@link ScheduleBuilder} that is configured to produce a + * schedule identical to this trigger's schedule. * - *

- * To be implemented by the concrete class. - *

- * - *

- * The implementation should update the Trigger's state - * based on the given new version of the associated Calendar - * (the state should be updated so that it's next fire time is appropriate - * given the Calendar's new settings). - *

- * - * @param cal + * @see #getTriggerBuilder() */ - public abstract void updateWithNewCalendar(Calendar cal, long misfireThreshold); + public ScheduleBuilder getScheduleBuilder(); /** - *

- * Validates whether the properties of the JobDetail are - * valid for submission into a Scheduler. + * Trigger equality is based upon the equality of the TriggerKey. * - * @throws IllegalStateException - * if a required property (such as Name, Group, Class) is not - * set. + * @return true if the key of this Trigger equals that of the given Trigger. */ - public void validate() throws SchedulerException { - if (name == null) - throw new SchedulerException("Trigger's name cannot be null", - SchedulerException.ERR_CLIENT_ERROR); - - if (group == null) - throw new SchedulerException("Trigger's group cannot be null", - SchedulerException.ERR_CLIENT_ERROR); - - if (jobName == null) - throw new SchedulerException( - "Trigger's related Job's name cannot be null", - SchedulerException.ERR_CLIENT_ERROR); - - if (jobGroup == null) - throw new SchedulerException( - "Trigger's related Job's group cannot be null", - SchedulerException.ERR_CLIENT_ERROR); - } - + public boolean equals(Object other); + /** *

- * This method should not be used by the Quartz client. + * Compare the next fire time of this Trigger to that of + * another by comparing their keys, or in other words, sorts them + * according to the natural (i.e. alphabetical) order of their keys. *

- * - *

- * Usable by {@link org.quartz.spi.JobStore} - * implementations, in order to facilitate 'recognizing' instances of fired - * Trigger s as their jobs complete execution. - *

- * - * */ - public void setFireInstanceId(String id) { - this.fireInstanceId = id; - } + public int compareTo(Trigger other); /** - *

- * This method should not be used by the Quartz client. - *

+ * A Comparator that compares trigger's next fire times, or in other words, + * sorts them according to earliest next fire time. If the fire times are + * the same, then the triggers are sorted according to priority (highest + * value first), if the priorities are the same, then they are sorted + * by key. */ - public String getFireInstanceId() { - return fireInstanceId; - } + class TriggerTimeComparator implements Comparator, Serializable { + + private static final long serialVersionUID = -3904243490805975570L; + + // This static method exists for comparator in TC clustered quartz + public static int compare(Date nextFireTime1, int priority1, TriggerKey key1, Date nextFireTime2, int priority2, TriggerKey key2) { + if (nextFireTime1 != null || nextFireTime2 != null) { + if (nextFireTime1 == null) { + return 1; + } - /** - *

- * Return a simple string representation of this object. - *

- */ - public String toString() { - return "Trigger '" + getFullName() + "': triggerClass: '" - + getClass().getName() + " isVolatile: " + isVolatile() - + " calendar: '" + getCalendarName() + "' misfireInstruction: " - + getMisfireInstruction() + " nextFireTime: " + getNextFireTime(); - } + if (nextFireTime2 == null) { + return -1; + } - /** - *

- * Compare the next fire time of this Trigger to that of - * another. - *

- */ - public int compareTo(Object obj) { - Trigger other = (Trigger) obj; + if(nextFireTime1.before(nextFireTime2)) { + return -1; + } - Date myTime = getNextFireTime(); - Date otherTime = other.getNextFireTime(); + if(nextFireTime1.after(nextFireTime2)) { + return 1; + } + } - if (myTime == null && otherTime == null) return 0; + int comp = priority2 - priority1; + if (comp != 0) { + return comp; + } - if (myTime == null) return 1; + return key1.compareTo(key2); + } - if (otherTime == null) return -1; - if(myTime.before(otherTime)) - return -1; - - if(myTime.after(otherTime)) - return 1; - - return 0; - } - - public boolean equals(Object obj) { - if (!(obj instanceof Trigger)) return false; - - Trigger other = (Trigger) obj; - - if (!other.getName().equals(getName())) return false; - if (!other.getGroup().equals(getGroup())) return false; - - return true; - } - - - public int hashCode() { - return getFullName().hashCode(); - } - - public Object clone() { - Trigger copy; - try { - copy = (Trigger) super.clone(); - } catch (CloneNotSupportedException ex) { - throw new IncompatibleClassChangeError("Not Cloneable."); + public int compare(Trigger t1, Trigger t2) { + return compare(t1.getNextFireTime(), t1.getPriority(), t1.getKey(), t2.getNextFireTime(), t2.getPriority(), t2.getKey()); } - return copy; } - } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/TriggerBuilder.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/TriggerKey.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/TriggerListener.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/TriggerListener.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/TriggerListener.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/TriggerListener.java 15 Dec 2014 10:09:47 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,19 +16,17 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; +import org.quartz.Trigger.CompletedExecutionInstruction; + /** - *

* The interface to be implemented by classes that want to be informed when a * {@link Trigger} fires. In general, applications that use a * Scheduler will not have use for this mechanism. - *

* - * @see Scheduler + * @see ListenerManager#addTriggerListener(TriggerListener, Matcher) + * @see Matcher * @see Trigger * @see JobListener * @see JobExecutionContext @@ -50,7 +48,7 @@ * Get the name of the TriggerListener. *

*/ - public String getName(); + String getName(); /** *

@@ -70,13 +68,14 @@ * The JobExecutionContext that will be passed to * the Job'sexecute(xx) method. */ - public void triggerFired(Trigger trigger, JobExecutionContext context); + void triggerFired(Trigger trigger, JobExecutionContext context); /** *

* Called by the {@link Scheduler} when a {@link Trigger} * has fired, and it's associated {@link org.quartz.JobDetail} - * is about to be executed. + * is about to be executed. If the implementation vetos the execution (via + * returning true), the job's execute method will not be called. *

* *

@@ -90,7 +89,7 @@ * The JobExecutionContext that will be passed to * the Job'sexecute(xx) method. */ - public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context); + boolean vetoJobExecution(Trigger trigger, JobExecutionContext context); /** @@ -109,7 +108,7 @@ * @param trigger * The Trigger that has misfired. */ - public void triggerMisfired(Trigger trigger); + void triggerMisfired(Trigger trigger); /** *

@@ -124,11 +123,11 @@ * @param context * The JobExecutionContext that was passed to the * Job'sexecute(xx) method. - * @param triggerIntructionCode + * @param triggerInstructionCode * the result of the call on the Trigger'striggered(xx) * method. */ - public void triggerComplete(Trigger trigger, JobExecutionContext context, - int triggerInstructionCode); + void triggerComplete(Trigger trigger, JobExecutionContext context, + CompletedExecutionInstruction triggerInstructionCode); } Index: 3rdParty_sources/quartz/org/quartz/TriggerUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/TriggerUtils.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/TriggerUtils.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/TriggerUtils.java 15 Dec 2014 10:09:46 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,31 +16,21 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz; -import java.util.Calendar; import java.util.Date; import java.util.LinkedList; import java.util.List; -import java.util.TimeZone; +import org.quartz.spi.OperableTrigger; + /** - *

- * Convenience and utility methods for simplifying the construction and - * configuration of {@link Trigger}s. - *

+ * Convenience and utility methods for working with {@link Trigger}s. * - *

- * Please submit suggestions for additional convenience methods to either the - * Quartz user forum or the developer's mail list at - * source forge. - *

* * @see CronTrigger * @see SimpleTrigger + * @see DateBuilder * * @author James House */ @@ -54,30 +44,12 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - public static final int SUNDAY = 1; - - public static final int MONDAY = 2; - - public static final int TUESDAY = 3; - - public static final int WEDNESDAY = 4; - - public static final int THURSDAY = 5; - - public static final int FRIDAY = 6; - - public static final int SATURDAY = 7; - - public static final int LAST_DAY_OF_MONTH = -1; - - public static final long MILLISECONDS_IN_MINUTE = 60l * 1000l; - - public static final long MILLISECONDS_IN_HOUR = 60l * 60l * 1000l; - - public static final long SECONDS_IN_DAY = 24l * 60l * 60L; - - public static final long MILLISECONDS_IN_DAY = SECONDS_IN_DAY * 1000l; - + /** + * Private constructor because this is a pure utility class. + */ + private TriggerUtils() { + } + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -86,1134 +58,48 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - private static void validateDayOfWeek(int dayOfWeek) { - if (dayOfWeek < SUNDAY || dayOfWeek > SATURDAY) - throw new IllegalArgumentException("Invalid day of week."); - } - - private static void validateHour(int hour) { - if (hour < 0 || hour > 23) - throw new IllegalArgumentException( - "Invalid hour (must be >= 0 and <= 23)."); - } - - private static void validateMinute(int minute) { - if (minute < 0 || minute > 59) - throw new IllegalArgumentException( - "Invalid minute (must be >= 0 and <= 59)."); - } - - private static void validateSecond(int second) { - if (second < 0 || second > 59) - throw new IllegalArgumentException( - "Invalid second (must be >= 0 and <= 59)."); - } - - private static void validateDayOfMonth(int day) { - if ((day < 1 || day > 31) && day != LAST_DAY_OF_MONTH) - throw new IllegalArgumentException("Invalid day of month."); - } - - private static void validateMonth(int month) { - if (month < 1 || month > 12) - throw new IllegalArgumentException( - "Invalid month (must be >= 1 and <= 12."); - } - - private static void validateYear(int year) { - if (year < 1970 || year > 2099) - throw new IllegalArgumentException( - "Invalid year (must be >= 1970 and <= 2099."); - } - /** - *

- * Set the given Trigger's name to the given value, and its - * group to the default group (Scheduler.DEFAULT_GROUP). - *

+ * Returns a list of Dates that are the next fire times of a + * Trigger. + * The input trigger will be cloned before any work is done, so you need + * not worry about its state being altered by this method. * - * @param trig the tigger to change name to - * @param name the new trigger name + * @param trigg + * The trigger upon which to do the work + * @param cal + * The calendar to apply to the trigger's schedule + * @param numTimes + * The number of next fire times to produce + * @return List of java.util.Date objects */ - public static void setTriggerIdentity(Trigger trig, String name) { - setTriggerIdentity(trig, name, Scheduler.DEFAULT_GROUP); - } + public static List computeFireTimes(OperableTrigger trigg, org.quartz.Calendar cal, + int numTimes) { + LinkedList lst = new LinkedList(); - /** - *

- * Set the given Trigger's name to the given value, and its - * group to the given group. - *

- * - * @param trig the tigger to change name to - * @param name the new trigger name - * @param group the new trigger group - */ - public static void setTriggerIdentity( - Trigger trig, String name, String group) { - trig.setName(name); - trig.setGroup(group); - } + OperableTrigger t = (OperableTrigger) trigg.clone(); - /** - *

- * Make a trigger that will fire every day at the given time. - *

- * - *

- * The generated trigger will not have its name, group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @param hour the hour (0-23) upon which to fire - * @param minute the minute (0-59) upon which to fire - * @return the new trigger - */ - public static Trigger makeDailyTrigger(int hour, int minute) { - validateHour(hour); - validateMinute(minute); - - CronTrigger trig = new CronTrigger(); - - try { - trig.setCronExpression("0 " + minute + " " + hour + " ? * *"); - } catch (Exception ignore) { - return null; /* never happens... */ + if (t.getNextFireTime() == null) { + t.computeFirstFireTime(cal); } - trig.setStartTime(new Date()); - - return trig; - } - - /** - *

- * Make a trigger that will fire every day at the given time. - *

- * - *

- * The generated trigger will not have its group or end-time set. - * The Start time defaults to 'now'. - *

- * - * @param trigName the trigger's name - * @param hour the hour (0-23) upon which to fire - * @param minute the minute (0-59) upon which to fire - * @return the newly created trigger - */ - public static Trigger makeDailyTrigger( - String trigName, int hour, int minute) { - Trigger trig = makeDailyTrigger(hour, minute); - trig.setName(trigName); - return trig; - } - - /** - *

- * Make a trigger that will fire every week at the given day and time. - *

- * - *

- * The generated trigger will not have its name, group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @param dayOfWeek (1-7) the day of week upon which to fire - * @param hour the hour (0-23) upon which to fire - * @param minute the minute (0-59) upon which to fire - * @return the new trigger - * - * @see #SUNDAY - * @see #MONDAY - * @see #TUESDAY - * @see #WEDNESDAY - * @see #THURSDAY - * @see #FRIDAY - * @see #SATURDAY - */ - public static Trigger makeWeeklyTrigger( - int dayOfWeek, int hour, int minute) { - validateDayOfWeek(dayOfWeek); - validateHour(hour); - validateMinute(minute); - - CronTrigger trig = new CronTrigger(); - - try { - trig.setCronExpression("0 " + minute + " " + hour + " ? * " - + dayOfWeek); - } catch (Exception ignore) { - return null; /* never happens... */ + for (int i = 0; i < numTimes; i++) { + Date d = t.getNextFireTime(); + if (d != null) { + lst.add(d); + t.triggered(cal); + } else { + break; + } } - - trig.setStartTime(new Date()); - return trig; + return java.util.Collections.unmodifiableList(lst); } - - /** - *

- * Make a trigger that will fire every week at the given day and time. - *

- * - *

- * The generated trigger will not have its group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @param trigName the trigger's name - * @param dayOfWeek (1-7) the day of week upon which to fire - * @param hour the hour (0-23) upon which to fire - * @param minute the minute (0-59) upon which to fire - * @return the newly created trigger - * - * @see #SUNDAY - * @see #MONDAY - * @see #TUESDAY - * @see #WEDNESDAY - * @see #THURSDAY - * @see #FRIDAY - * @see #SATURDAY - */ - public static Trigger makeWeeklyTrigger( - String trigName, int dayOfWeek, int hour, int minute) { - Trigger trig = makeWeeklyTrigger(dayOfWeek, hour, minute); - trig.setName(trigName); - return trig; - } - /** - *

- * Make a trigger that will fire every month at the given day and time. - *

- * - *

- * The generated trigger will not have its name, group, - * or end-time set. The Start time defaults to 'now'. - *

- * - *

- * If the day of the month specified does not occur in a given month, a - * firing will not occur that month. (i.e. if dayOfMonth is specified as - * 31, no firing will occur in the months of the year with fewer than 31 - * days). - *

- * - * @param dayOfMonth (1-31, or -1) the day of week upon which to fire - * @param hour the hour (0-23) upon which to fire - * @param minute the minute (0-59) upon which to fire - * @return the newly created trigger - */ - public static Trigger makeMonthlyTrigger( - int dayOfMonth, int hour, int minute) { - validateDayOfMonth(dayOfMonth); - validateHour(hour); - validateMinute(minute); - - CronTrigger trig = new CronTrigger(); - - try { - if (dayOfMonth != LAST_DAY_OF_MONTH) trig.setCronExpression("0 " - + minute + " " + hour + " " + dayOfMonth + " * ?"); - else - trig.setCronExpression("0 " + minute + " " + hour + " L * ?"); - } catch (Exception ignore) { - return null; /* never happens... */ - } - - trig.setStartTime(new Date()); - - return trig; - } - - /** - *

- * Make a trigger that will fire every month at the given day and time. - *

- * - *

- * The generated trigger will not have its group, - * or end-time set. The Start time defaults to 'now'. - *

- * - *

- * If the day of the month specified does not occur in a given month, a - * firing will not occur that month. (i.e. if dayOfMonth is specified as - * 31, no firing will occur in the months of the year with fewer than 31 - * days). - *

- * - * @param trigName the trigger's name - * @param dayOfMonth (1-31, or -1) the day of week upon which to fire - * @param hour the hour (0-23) upon which to fire - * @param minute the minute (0-59) upon which to fire - * @return the newly created trigger - */ - public static Trigger makeMonthlyTrigger( - String trigName, int dayOfMonth, int hour, int minute) { - Trigger trig = makeMonthlyTrigger(dayOfMonth, hour, minute); - trig.setName(trigName); - return trig; - } - - /* - *

Make a trigger that will fire every N days at the given time.

- * - *

TThe generated trigger will not have its name, group, - * start-time and end-time set.

- * - * @param hour the hour (0-23) upon which to fire @param minute the minute - * (0-59) upon which to fire @param interval the number of days between - * firings public static Trigger makeDailyTrigger(int interval, int hour, - * int minute) { - * - * SimpleTrigger trig = new SimpleTrigger(); - * - * MILLISECONDS_IN_DAY); - * trig.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY); - * - * return trig; - * } - */ - - /** - *

- * Make a trigger that will fire repeatCount times, waiting - * repeatInterval milliseconds between each fire. - *

- * - *

- * The generated trigger will not have its name, group, - * or end-time set. The Start time defaults to 'now'. - *

+ * Compute the Date that is 1 second after the Nth firing of + * the given Trigger, taking the triger's associated + * Calendar into consideration. * - * @param repeatCount the number of times to fire the trigger - * @param repeatInterval the number of milliseconds to wait between fires - * @return the newly created trigger - */ - public static Trigger makeImmediateTrigger( - int repeatCount, long repeatInterval) { - SimpleTrigger trig = new SimpleTrigger(); - trig.setStartTime( new Date() ); - trig.setRepeatCount(repeatCount); - trig.setRepeatInterval(repeatInterval); - return trig; - } - - /** - *

- * Make a trigger that will fire repeatCount times, waiting - * repeatInterval milliseconds between each fire. - *

- * - *

- * The generated trigger will not have its name, group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @param trigName the trigger's name - * @param repeatCount the number of times to fire the trigger - * @param repeatInterval the number of milliseconds to wait between fires - * @return the new trigger - */ - public static Trigger makeImmediateTrigger( - String trigName, int repeatCount, long repeatInterval) { - Trigger trig = makeImmediateTrigger(repeatCount, repeatInterval); - trig.setName(trigName); - return trig; - } - - /** - *

- * Make a trigger that will fire every second, indefinitely. - *

- * - *

- * The generated trigger will not have its name, group, - * or end-time set. The Start time defaults to 'now'. - *

- * @return the new trigger - */ - public static Trigger makeSecondlyTrigger() { - return makeSecondlyTrigger(1, SimpleTrigger.REPEAT_INDEFINITELY); - } - - /** - *

- * Make a trigger that will fire every second, indefinitely. - *

- * - *

- * The generated trigger will not have its group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @param trigName the trigger's name - * @return the new trigger - */ - public static Trigger makeSecondlyTrigger(String trigName) { - return makeSecondlyTrigger( - trigName, 1, SimpleTrigger.REPEAT_INDEFINITELY); - } - - - /** - *

- * Make a trigger that will fire every N seconds, indefinitely. - *

- * - *

- * The generated trigger will not have its name, group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @param intervalInSeconds the number of seconds between firings - * @return the new trigger - */ - public static Trigger makeSecondlyTrigger(int intervalInSeconds) { - return makeSecondlyTrigger( - intervalInSeconds, SimpleTrigger.REPEAT_INDEFINITELY); - } - - /** - *

- * Make a trigger that will fire every N seconds, with the given number of - * repeats. - *

- * - *

- * The generated trigger will not have its name, group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @param intervalInSeconds the number of seconds between firings - * @param repeatCount the number of times to repeat the firing - * @return the new trigger - */ - public static Trigger makeSecondlyTrigger( - int intervalInSeconds, int repeatCount) { - SimpleTrigger trig = new SimpleTrigger(); - - trig.setRepeatInterval(intervalInSeconds * 1000l); - trig.setRepeatCount(repeatCount); - - return trig; - } - - /** - *

- * Make a trigger that will fire every N seconds, with the given number of - * repeats. - *

- * - *

- * The generated trigger will not have its group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @param trigName the trigger's name - * @param intervalInSeconds the number of seconds between firings - * @param repeatCount the number of times to repeat the firing - * @return the new trigger - */ - public static Trigger makeSecondlyTrigger( - String trigName, int intervalInSeconds, int repeatCount) { - Trigger trig = makeSecondlyTrigger(intervalInSeconds, repeatCount); - trig.setName(trigName); - return trig; - } - - /** - *

- * Make a trigger that will fire every minute, indefinitely. - *

- * - *

- * The generated trigger will not have its name, group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @return the new trigger - */ - public static Trigger makeMinutelyTrigger() { - return makeMinutelyTrigger(1, SimpleTrigger.REPEAT_INDEFINITELY); - } - - /** - *

- * Make a trigger that will fire every minute, indefinitely. - *

- * - *

- * The generated trigger will not have its group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @param trigName the trigger's name - * @return the new trigger - */ - public static Trigger makeMinutelyTrigger(String trigName) { - return makeMinutelyTrigger( - trigName, 1, SimpleTrigger.REPEAT_INDEFINITELY); - } - - /** - *

- * Make a trigger that will fire every N minutes, indefinitely. - *

- * - *

- * The generated trigger will not have its name, group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @param intervalInMinutes the number of minutes between firings - * @return the new trigger - */ - public static Trigger makeMinutelyTrigger(int intervalInMinutes) { - return makeMinutelyTrigger( - intervalInMinutes, SimpleTrigger.REPEAT_INDEFINITELY); - } - - /** - *

- * Make a trigger that will fire every N minutes, with the given number of - * repeats. - *

- * - *

- * The generated trigger will not have its name, group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @param intervalInMinutes the number of minutes between firings - * @param repeatCount the number of times to repeat the firing - * @return the new trigger - */ - public static Trigger makeMinutelyTrigger( - int intervalInMinutes, int repeatCount) { - SimpleTrigger trig = new SimpleTrigger(); - - trig.setRepeatInterval(intervalInMinutes * MILLISECONDS_IN_MINUTE); - trig.setRepeatCount(repeatCount); - - trig.setStartTime(new Date()); - - return trig; - } - - /** - *

- * Make a trigger that will fire every N minutes, with the given number of - * repeats. - *

- * - *

- * The generated trigger will not have its group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @param trigName the trigger's name - * @param intervalInMinutes the number of minutes between firings - * @param repeatCount the number of times to repeat the firing - * @return the new trigger - */ - public static Trigger makeMinutelyTrigger( - String trigName, int intervalInMinutes, int repeatCount) { - Trigger trig = makeMinutelyTrigger(intervalInMinutes, repeatCount); - trig.setName(trigName); - return trig; - } - - /** - *

- * Make a trigger that will fire every hour, indefinitely. - *

- * - *

- * The generated trigger will not have its name, group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @return the new trigger - */ - public static Trigger makeHourlyTrigger() { - return makeHourlyTrigger(1, SimpleTrigger.REPEAT_INDEFINITELY); - } - - /** - *

- * Make a trigger that will fire every hour, indefinitely. - *

- * - *

- * The generated trigger will not have its group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @param trigName the trigger's name - * @return the new trigger - */ - public static Trigger makeHourlyTrigger(String trigName) { - return makeHourlyTrigger( - trigName, 1, SimpleTrigger.REPEAT_INDEFINITELY); - } - - /** - *

- * Make a trigger that will fire every N hours, indefinitely. - *

- * - *

- * The generated trigger will not have its name, group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @param intervalInHours the number of hours between firings - * @return the new trigger - */ - public static Trigger makeHourlyTrigger(int intervalInHours) { - return makeHourlyTrigger( - intervalInHours, SimpleTrigger.REPEAT_INDEFINITELY); - } - - /** - *

- * Make a trigger that will fire every N hours, with the given number of - * repeats. - *

- * - *

- * The generated trigger will not have its name, group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @param intervalInHours the number of hours between firings - * @param repeatCount the number of times to repeat the firing - * @return the new trigger - */ - public static Trigger makeHourlyTrigger( - int intervalInHours, int repeatCount) { - SimpleTrigger trig = new SimpleTrigger(); - - trig.setRepeatInterval(intervalInHours * MILLISECONDS_IN_HOUR); - trig.setRepeatCount(repeatCount); - - trig.setStartTime(new Date()); - - return trig; - } - - /** - *

- * Make a trigger that will fire every N hours, with the given number of - * repeats. - *

- * - *

- * The generated trigger will not have its group, - * or end-time set. The Start time defaults to 'now'. - *

- * - * @param trigName the trigger's name - * @param intervalInHours the number of hours between firings - * @param repeatCount the number of times to repeat the firing - * @return the new trigger - */ - public static Trigger makeHourlyTrigger( - String trigName, int intervalInHours, int repeatCount) { - Trigger trig =makeHourlyTrigger(intervalInHours, repeatCount); - trig.setName(trigName); - return trig; - } - - /** - *

- * Returns a date that is rounded to the next even hour above the given - * date. - *

- * - *

- * For example an input date with a time of 08:13:54 would result in a date - * with the time of 09:00:00. If the date's time is in the 23rd hour, the - * date's 'day' will be promoted, and the time will be set to 00:00:00. - *

- * - * @param date - * the Date to round, if null the current time will - * be used - * @return the new rounded date - */ - public static Date getEvenHourDate(Date date) { - if (date == null) date = new Date(); - - Calendar c = Calendar.getInstance(); - c.setTime(date); - c.setLenient(true); - - c.set(Calendar.HOUR_OF_DAY, c.get(Calendar.HOUR_OF_DAY) + 1); - c.set(Calendar.MINUTE, 0); - c.set(Calendar.SECOND, 0); - c.set(Calendar.MILLISECOND, 0); - - return c.getTime(); - } - - /** - *

- * Returns a date that is rounded to the previous even hour below the given - * date. - *

- * - *

- * For example an input date with a time of 08:13:54 would result in a date - * with the time of 08:00:00. - *

- * - * @param date - * the Date to round, if null the current time will - * be used - * @return the new rounded date - */ - public static Date getEvenHourDateBefore(Date date) { - if (date == null) date = new Date(); - - Calendar c = Calendar.getInstance(); - c.setTime(date); - - c.set(Calendar.MINUTE, 0); - c.set(Calendar.SECOND, 0); - c.set(Calendar.MILLISECOND, 0); - - return c.getTime(); - } - - /** - *

- * Returns a date that is rounded to the next even minute above the given - * date. - *

- * - *

- * For example an input date with a time of 08:13:54 would result in a date - * with the time of 08:14:00. If the date's time is in the 59th minute, - * then the hour (and possibly the day) will be promoted. - *

- * - * @param date - * the Date to round, if null the current time will - * be used - * @return the new rounded date - */ - public static Date getEvenMinuteDate(Date date) { - if (date == null) date = new Date(); - - Calendar c = Calendar.getInstance(); - c.setTime(date); - c.setLenient(true); - - c.set(Calendar.MINUTE, c.get(Calendar.MINUTE) + 1); - c.set(Calendar.SECOND, 0); - c.set(Calendar.MILLISECOND, 0); - - return c.getTime(); - } - - /** - *

- * Returns a date that is rounded to the previous even minute below the - * given date. - *

- * - *

- * For example an input date with a time of 08:13:54 would result in a date - * with the time of 08:13:00. - *

- * - * @param date - * the Date to round, if null the current time will - * be used - * @return the new rounded date - */ - public static Date getEvenMinuteDateBefore(Date date) { - if (date == null) date = new Date(); - - Calendar c = Calendar.getInstance(); - c.setTime(date); - - c.set(Calendar.SECOND, 0); - c.set(Calendar.MILLISECOND, 0); - - return c.getTime(); - } - - /** - *

- * Returns a date that is rounded to the next even second above the given - * date. - *

- * - * @param date - * the Date to round, if null the current time will - * be used - * @return the new rounded date - */ - public static Date getEvenSecondDate(Date date) { - if (date == null) date = new Date(); - - Calendar c = Calendar.getInstance(); - c.setTime(date); - c.setLenient(true); - - c.set(Calendar.SECOND, c.get(Calendar.SECOND) + 1); - c.set(Calendar.MILLISECOND, 0); - - return c.getTime(); - } - - /** - *

- * Returns a date that is rounded to the previous even second below the - * given date. - *

- * - *

- * For example an input date with a time of 08:13:54.341 would result in a - * date with the time of 08:13:00.000. - *

- * - * @param date - * the Date to round, if null the current time will - * be used - * @return the new rounded date - */ - public static Date getEvenSecondDateBefore(Date date) { - if (date == null) date = new Date(); - - Calendar c = Calendar.getInstance(); - c.setTime(date); - - c.set(Calendar.MILLISECOND, 0); - - return c.getTime(); - } - - /** - *

- * Returns a date that is rounded to the next even multiple of the given - * minute. - *

- * - *

- * For example an input date with a time of 08:13:54, and an input - * minute-base of 5 would result in a date with the time of 08:15:00. The - * same input date with an input minute-base of 10 would result in a date - * with the time of 08:20:00. But a date with the time 08:53:31 and an - * input minute-base of 45 would result in 09:00:00, because the even-hour - * is the next 'base' for 45-minute intervals. - *

- * - *

- * More examples: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Input TimeMinute-BaseResult Time
11:16:412011:20:00
11:36:412011:40:00
11:46:412012:00:00
11:26:413011:30:00
11:36:413012:00:00
11:16:411711:17:00
11:17:411711:34:00
11:52:411712:00:00
11:52:41511:55:00
11:57:41512:00:00
11:17:41012:00:00
11:17:41111:08:00
- *

- * - * @param date - * the Date to round, if null the current time will - * be used - * @param minuteBase - * the base-minute to set the time on - * @return the new rounded date - * - * @see #getNextGivenSecondDate(Date, int) - */ - public static Date getNextGivenMinuteDate(Date date, int minuteBase) { - if (minuteBase < 0 || minuteBase > 59) - throw new IllegalArgumentException( - "minuteBase must be >=0 and <= 59"); - - if (date == null) date = new Date(); - - Calendar c = Calendar.getInstance(); - c.setTime(date); - c.setLenient(true); - - if (minuteBase == 0) { - c.set(Calendar.HOUR_OF_DAY, c.get(Calendar.HOUR_OF_DAY) + 1); - c.set(Calendar.MINUTE, 0); - c.set(Calendar.SECOND, 0); - c.set(Calendar.MILLISECOND, 0); - - return c.getTime(); - } - - int minute = c.get(Calendar.MINUTE); - - int arItr = minute / minuteBase; - - int nextMinuteOccurance = minuteBase * (arItr + 1); - - if (nextMinuteOccurance < 60) { - c.set(Calendar.MINUTE, nextMinuteOccurance); - c.set(Calendar.SECOND, 0); - c.set(Calendar.MILLISECOND, 0); - - return c.getTime(); - } else { - c.set(Calendar.HOUR_OF_DAY, c.get(Calendar.HOUR_OF_DAY) + 1); - c.set(Calendar.MINUTE, 0); - c.set(Calendar.SECOND, 0); - c.set(Calendar.MILLISECOND, 0); - - return c.getTime(); - } - } - - /** - *

- * Returns a date that is rounded to the next even multiple of the given - * minute. - *

- * - *

- * The rules for calculating the second are the same as those for - * calculating the minute in the method - * getNextGivenMinuteDate(..). - *

- * - * @param date the Date to round, if null the current time will - * be used - * @param secondBase the base-second to set the time on - * @return the new rounded date - * - * @see #getNextGivenMinuteDate(Date, int) - */ - public static Date getNextGivenSecondDate(Date date, int secondBase) { - if (secondBase < 0 || secondBase > 59) - throw new IllegalArgumentException( - "secondBase must be >=0 and <= 59"); - - if (date == null) date = new Date(); - - Calendar c = Calendar.getInstance(); - c.setTime(date); - c.setLenient(true); - - if (secondBase == 0) { - c.set(Calendar.MINUTE, c.get(Calendar.MINUTE) + 1); - c.set(Calendar.SECOND, 0); - c.set(Calendar.MILLISECOND, 0); - - return c.getTime(); - } - - int second = c.get(Calendar.SECOND); - - int arItr = second / secondBase; - - int nextSecondOccurance = secondBase * (arItr + 1); - - if (nextSecondOccurance < 60) { - c.set(Calendar.SECOND, nextSecondOccurance); - c.set(Calendar.MILLISECOND, 0); - - return c.getTime(); - } else { - c.set(Calendar.MINUTE, c.get(Calendar.MINUTE) + 1); - c.set(Calendar.SECOND, 0); - c.set(Calendar.MILLISECOND, 0); - - return c.getTime(); - } - } - - /** - *

- * Get a Date object that represents the given time, on - * today's date. - *

- * - * @param second - * The value (0-59) to give the seconds field of the date - * @param minute - * The value (0-59) to give the minutes field of the date - * @param hour - * The value (0-23) to give the hours field of the date - * @return the new date - */ - public static Date getDateOf(int second, int minute, int hour) { - validateSecond(second); - validateMinute(minute); - validateHour(hour); - - Date date = new Date(); - - Calendar c = Calendar.getInstance(); - c.setTime(date); - c.setLenient(true); - - c.set(Calendar.HOUR_OF_DAY, hour); - c.set(Calendar.MINUTE, minute); - c.set(Calendar.SECOND, second); - c.set(Calendar.MILLISECOND, 0); - - return c.getTime(); - } - - /** - *

- * Get a Date object that represents the given time, on the - * given date. - *

- * - * @param second - * The value (0-59) to give the seconds field of the date - * @param minute - * The value (0-59) to give the minutes field of the date - * @param hour - * The value (0-23) to give the hours field of the date - * @param dayOfMonth - * The value (1-31) to give the day of month field of the date - * @param month - * The value (1-12) to give the month field of the date - * @return the new date - */ - public static Date getDateOf(int second, int minute, int hour, - int dayOfMonth, int month) { - validateSecond(second); - validateMinute(minute); - validateHour(hour); - validateDayOfMonth(dayOfMonth); - validateMonth(month); - - Date date = new Date(); - - Calendar c = Calendar.getInstance(); - c.setTime(date); - - c.set(Calendar.MONTH, month - 1); - c.set(Calendar.DAY_OF_MONTH, dayOfMonth); - c.set(Calendar.HOUR_OF_DAY, hour); - c.set(Calendar.MINUTE, minute); - c.set(Calendar.SECOND, second); - c.set(Calendar.MILLISECOND, 0); - - return c.getTime(); - } - - /** - *

- * Get a Date object that represents the given time, on the - * given date. - *

- * - * @param second - * The value (0-59) to give the seconds field of the date - * @param minute - * The value (0-59) to give the minutes field of the date - * @param hour - * The value (0-23) to give the hours field of the date - * @param dayOfMonth - * The value (1-31) to give the day of month field of the date - * @param month - * The value (1-12) to give the month field of the date - * @param year - * The value (1970-2099) to give the year field of the date - * @return the new date - */ - public static Date getDateOf(int second, int minute, int hour, - int dayOfMonth, int month, int year) { - validateSecond(second); - validateMinute(minute); - validateHour(hour); - validateDayOfMonth(dayOfMonth); - validateMonth(month); - validateYear(year); - - Date date = new Date(); - - Calendar c = Calendar.getInstance(); - c.setTime(date); - - c.set(Calendar.YEAR, year); - c.set(Calendar.MONTH, month - 1); - c.set(Calendar.DAY_OF_MONTH, dayOfMonth); - c.set(Calendar.HOUR_OF_DAY, hour); - c.set(Calendar.MINUTE, minute); - c.set(Calendar.SECOND, second); - c.set(Calendar.MILLISECOND, 0); - - return c.getTime(); - } - - /** - * Returns a list of Dates that are the next fire times of a - * Trigger. * The input trigger will be cloned before any work is done, so you need * not worry about its state being altered by this method. * @@ -1223,28 +109,38 @@ * The calendar to apply to the trigger's schedule * @param numTimes * The number of next fire times to produce - * @return List of java.util.Date objects + * @return the computed Date, or null if the trigger (as configured) will not fire that many times. */ - public static List computeFireTimes(Trigger trigg, org.quartz.Calendar cal, + public static Date computeEndTimeToAllowParticularNumberOfFirings(OperableTrigger trigg, org.quartz.Calendar cal, int numTimes) { - LinkedList lst = new LinkedList(); - Trigger t = (Trigger) trigg.clone(); + OperableTrigger t = (OperableTrigger) trigg.clone(); if (t.getNextFireTime() == null) { t.computeFirstFireTime(cal); } - + + int c = 0; + Date endTime = null; + for (int i = 0; i < numTimes; i++) { Date d = t.getNextFireTime(); if (d != null) { - lst.add(d); + c++; t.triggered(cal); - } else + if(c == numTimes) + endTime = d; + } else { break; + } } - - return java.util.Collections.unmodifiableList(lst); + + if(endTime == null) + return null; + + endTime = new Date(endTime.getTime() + 1000L); + + return endTime; } /** @@ -1256,7 +152,7 @@ * *

* NOTE: if this is a trigger that has previously fired within the given - * date range, then firings which have already occured will not be listed + * date range, then firings which have already occurred will not be listed * in the output List. *

* @@ -1270,96 +166,36 @@ * The ending date at which to stop finding fire times * @return List of java.util.Date objects */ - public static List computeFireTimesBetween(Trigger trigg, + public static List computeFireTimesBetween(OperableTrigger trigg, org.quartz.Calendar cal, Date from, Date to) { - LinkedList lst = new LinkedList(); + LinkedList lst = new LinkedList(); - Trigger t = (Trigger) trigg.clone(); + OperableTrigger t = (OperableTrigger) trigg.clone(); if (t.getNextFireTime() == null) { t.setStartTime(from); t.setEndTime(to); t.computeFirstFireTime(cal); } - // TODO: this method could be more efficient by using logic specific - // to the type of trigger ... while (true) { Date d = t.getNextFireTime(); if (d != null) { if (d.before(from)) { t.triggered(cal); continue; } - if (d.after(to)) break; + if (d.after(to)) { + break; + } lst.add(d); t.triggered(cal); - } else + } else { break; + } } return java.util.Collections.unmodifiableList(lst); } - /** - * Translate a date & time from a users timezone to the another - * (probably server) timezone to assist in creating a simple trigger with - * the right date & time. - * - * @param date the date to translate - * @param src the original time-zone - * @param dest the destination time-zone - * @return the translated date - */ - public static Date translateTime(Date date, TimeZone src, TimeZone dest) { - - Date newDate = new Date(); - - int offset = ( - getOffset(date.getTime(), dest) - getOffset(date.getTime(), src) - ); - - newDate.setTime(date.getTime() - offset); - - return newDate; - } - - /** - * Gets the offset from UT for the given date in the given timezone, - * taking into account daylight savings. - * - *

- * Equivalent of TimeZone.getOffset(date) in JDK 1.4, but Quartz is trying - * to support JDK 1.3. - *

- * - * @param date the date (in milliseconds) that is the base for the offset - * @param tz the time-zone to calculate to offset to - * @return the offset - */ - public static int getOffset(long date, TimeZone tz) { - - if (tz.inDaylightTime(new Date(date))) { - return tz.getRawOffset() + getDSTSavings(tz); - } - - return tz.getRawOffset(); - } - - /** - *

- * Equivalent of TimeZone.getDSTSavings() in JDK 1.4, but Quartz is trying - * to support JDK 1.3. - *

- * - * @param tz the target time-zone - * @return the amount of saving time in milliseconds - */ - public static int getDSTSavings(TimeZone tz) { - - if (tz.useDaylightTime()) { - return 3600000; - } - return 0; - } } Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/UICronTrigger.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/UnableToInterruptJobException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/UnableToInterruptJobException.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/UnableToInterruptJobException.java 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/UnableToInterruptJobException.java 15 Dec 2014 10:09:46 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,23 +16,19 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ - package org.quartz; /** - *

* An exception that is thrown to indicate that a call to * InterruptableJob.interrupt() failed without interrupting the Job. - *

* * @see org.quartz.InterruptableJob#interrupt() * * @author James House */ public class UnableToInterruptJobException extends SchedulerException { + + private static final long serialVersionUID = -490863760696463776L; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -56,7 +52,7 @@ * Create a UnableToInterruptJobException with the given cause. *

*/ - public UnableToInterruptJobException(Exception cause) { + public UnableToInterruptJobException(Throwable cause) { super(cause); } Index: 3rdParty_sources/quartz/org/quartz/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/package.html,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/package.html 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/package.html 15 Dec 2014 10:09:47 -0000 1.1.2.1 @@ -8,8 +8,32 @@


-See the Quartz project - at Open Symphony for more information. +

See the Quartz project for more information.

+ +

Quartz provides a builder-style API for constructing scheduling-related +entities via a Domain-Specific Language (DSL). The DSL can best be +utilized through the usage of static imports of the methods on the classes +TriggerBuilder, JobBuilder, +DateBuilder, JobKey, TriggerKey +and the various ScheduleBuilder implementations.

+ +

Client code can then use the DSL to write code such as this:

+
+        JobDetail job = newJob(MyJob.class)
+            .withIdentity("myJob")
+            .build();
+            
+        Trigger trigger = newTrigger() 
+            .withIdentity(triggerKey("myTrigger", "myTriggerGroup"))
+            .withSchedule(simpleSchedule()
+                .withIntervalInHours(1)
+                .repeatForever())
+            .startAt(futureDate(10, MINUTES))
+            .build();
+        
+        scheduler.scheduleJob(job, trigger);
+
+ \ No newline at end of file Index: 3rdParty_sources/quartz/org/quartz/quartz.properties =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/quartz.properties,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/quartz.properties 17 Aug 2012 15:10:17 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/quartz.properties 15 Dec 2014 10:09:47 -0000 1.1.2.1 @@ -3,17 +3,17 @@ # properties file is not explicitly specified. # -org.quartz.scheduler.instanceName = DefaultQuartzScheduler -org.quartz.scheduler.rmi.export = false -org.quartz.scheduler.rmi.proxy = false -org.quartz.scheduler.wrapJobExecutionInUserTransaction = false +org.quartz.scheduler.instanceName: DefaultQuartzScheduler +org.quartz.scheduler.rmi.export: false +org.quartz.scheduler.rmi.proxy: false +org.quartz.scheduler.wrapJobExecutionInUserTransaction: false -org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool -org.quartz.threadPool.threadCount = 10 -org.quartz.threadPool.threadPriority = 5 -org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true +org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool +org.quartz.threadPool.threadCount: 10 +org.quartz.threadPool.threadPriority: 5 +org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true -org.quartz.jobStore.misfireThreshold = 60000 +org.quartz.jobStore.misfireThreshold: 60000 -org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore +org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/commonj/WorkManagerThreadExecutor.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/core/JobRunShell.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/core/JobRunShell.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/core/JobRunShell.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/core/JobRunShell.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,37 +1,36 @@ -/* - * Copyright 2004-2005 OpenSymphony - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations +/* + * Copyright 2001-2009 Terracotta, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations * under the License. - * + * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.core; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.quartz.Job; import org.quartz.JobDetail; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; -import org.quartz.JobPersistenceException; import org.quartz.Scheduler; import org.quartz.SchedulerException; -import org.quartz.Trigger; +import org.quartz.Trigger.CompletedExecutionInstruction; +import org.quartz.impl.JobExecutionContextImpl; +import org.quartz.listeners.SchedulerListenerSupport; +import org.quartz.spi.OperableTrigger; import org.quartz.spi.TriggerFiredBundle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** *

@@ -41,372 +40,343 @@ * the Trigger with the Job's completion code, * etc. *

- * + * *

* A JobRunShell instance is created by a JobRunShellFactory * on behalf of the QuartzSchedulerThread which then runs the * shell in a thread from the configured ThreadPool when the * scheduler determines that a Job has been triggered. *

- * + * * @see JobRunShellFactory * @see org.quartz.core.QuartzSchedulerThread * @see org.quartz.Job * @see org.quartz.Trigger - * + * * @author James House */ -public class JobRunShell implements Runnable { +public class JobRunShell extends SchedulerListenerSupport implements Runnable { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Data members. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - protected JobExecutionContext jec = null; + protected JobExecutionContextImpl jec = null; protected QuartzScheduler qs = null; + + protected TriggerFiredBundle firedTriggerBundle = null; protected Scheduler scheduler = null; - protected SchedulingContext schdCtxt = null; + protected volatile boolean shutdownRequested = false; - protected JobRunShellFactory jobRunShellFactory = null; + private final Logger log = LoggerFactory.getLogger(getClass()); - protected boolean shutdownRequested = false; - - protected Log log = LogFactory.getLog(getClass()); - /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Constructors. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** *

* Create a JobRunShell instance with the given settings. *

- * - * @param jobRunShellFactory - * A handle to the JobRunShellFactory that produced - * this JobRunShell. + * * @param scheduler * The Scheduler instance that should be made * available within the JobExecutionContext. - * @param schdCtxt - * the SchedulingContext that should be used by the - * JobRunShell when making updates to the JobStore. */ - public JobRunShell(JobRunShellFactory jobRunShellFactory, - Scheduler scheduler, SchedulingContext schdCtxt) { - this.jobRunShellFactory = jobRunShellFactory; + public JobRunShell(Scheduler scheduler, TriggerFiredBundle bndle) { this.scheduler = scheduler; - this.schdCtxt = schdCtxt; + this.firedTriggerBundle = bndle; } /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Interface. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - private static Log getLog() - { - return LogFactory.getLog(JobRunShell.class); + @Override + public void schedulerShuttingdown() { + requestShutdown(); } - - public void initialize(QuartzScheduler qs, TriggerFiredBundle firedBundle) - throws SchedulerException { - this.qs = qs; + @Override + protected Logger getLog() { + return log; + } + + public void initialize(QuartzScheduler sched) + throws SchedulerException { + this.qs = sched; + Job job = null; - JobDetail jobDetail = firedBundle.getJobDetail(); + JobDetail jobDetail = firedTriggerBundle.getJobDetail(); try { - job = qs.getJobFactory().newJob(firedBundle); + job = sched.getJobFactory().newJob(firedTriggerBundle, scheduler); } catch (SchedulerException se) { - qs.notifySchedulerListenersError( + sched.notifySchedulerListenersError( "An error occured instantiating job to be executed. job= '" - + jobDetail.getFullName() + "'", se); + + jobDetail.getKey() + "'", se); throw se; - } catch (Exception e) { - SchedulerException se = new SchedulerException( - "Problem instantiating class '" - + jobDetail.getJobClass().getName() + "'", e); - qs.notifySchedulerListenersError( - "An error occured instantiating job to be executed. job= '" - + jobDetail.getFullName() + "'", se); - throw se; } catch (Throwable ncdfe) { // such as NoClassDefFoundError SchedulerException se = new SchedulerException( "Problem instantiating class '" - + jobDetail.getJobClass().getName() + "' - " + ncdfe); - qs.notifySchedulerListenersError( + + jobDetail.getJobClass().getName() + "' - ", ncdfe); + sched.notifySchedulerListenersError( "An error occured instantiating job to be executed. job= '" - + jobDetail.getFullName() + "'", se); + + jobDetail.getKey() + "'", se); throw se; } - this.jec = new JobExecutionContext(scheduler, firedBundle, job); + this.jec = new JobExecutionContextImpl(scheduler, firedTriggerBundle, job); } public void requestShutdown() { shutdownRequested = true; } public void run() { - Trigger trigger = jec.getTrigger(); - JobDetail jobDetail = jec.getJobDetail(); + qs.addInternalSchedulerListener(this); - do { + try { + OperableTrigger trigger = (OperableTrigger) jec.getTrigger(); + JobDetail jobDetail = jec.getJobDetail(); - JobExecutionException jobExEx = null; - Job job = jec.getJobInstance(); + do { - try { - begin(); - } catch (SchedulerException se) { - qs.notifySchedulerListenersError("Error executing Job (" - + jec.getJobDetail().getFullName() - + ": couldn't begin execution.", se); - break; - } + JobExecutionException jobExEx = null; + Job job = jec.getJobInstance(); - // notify job & trigger listeners... - try { - if (!notifyListenersBeginning(jec)) break; - } - catch(VetoedException ve) { try { - complete(true); + begin(); } catch (SchedulerException se) { - qs.notifySchedulerListenersError("Error during veto of Job (" - + jec.getJobDetail().getFullName() - + ": couldn't finalize execution.", se); + qs.notifySchedulerListenersError("Error executing Job (" + + jec.getJobDetail().getKey() + + ": couldn't begin execution.", se); + break; } - break; - } - long startTime = System.currentTimeMillis(); - long endTime = startTime; - - // execute the job - try { - log.debug("Calling execute on job " + jobDetail.getFullName()); - job.execute(jec); - endTime = System.currentTimeMillis(); - } catch (JobExecutionException jee) { - endTime = System.currentTimeMillis(); - jobExEx = jee; - getLog().info("Job " + jobDetail.getFullName() + - " threw a JobExecutionException: ", jobExEx); - } catch (Exception e) { - endTime = System.currentTimeMillis(); - getLog().error("Job " + jobDetail.getFullName() + - " threw an unhandled Exception: ", e); - SchedulerException se = new SchedulerException( - "Job threw an unhandled exception.", e); - se.setErrorCode(SchedulerException.ERR_JOB_EXECUTION_THREW_EXCEPTION); - qs.notifySchedulerListenersError("Job (" - + jec.getJobDetail().getFullName() - + " threw an exception.", se); - jobExEx = new JobExecutionException(se, false); - jobExEx.setErrorCode(JobExecutionException.ERR_JOB_EXECUTION_THREW_EXCEPTION); - } - - jec.setJobRunTime(endTime - startTime); + // notify job & trigger listeners... + try { + if (!notifyListenersBeginning(jec)) { + break; + } + } catch(VetoedException ve) { + try { + CompletedExecutionInstruction instCode = trigger.executionComplete(jec, null); + qs.notifyJobStoreJobVetoed(trigger, jobDetail, instCode); + + // QTZ-205 + // Even if trigger got vetoed, we still needs to check to see if it's the trigger's finalized run or not. + if (jec.getTrigger().getNextFireTime() == null) { + qs.notifySchedulerListenersFinalized(jec.getTrigger()); + } - // notify all job listeners - if (!notifyJobListenersComplete(jec, jobExEx)) break; + complete(true); + } catch (SchedulerException se) { + qs.notifySchedulerListenersError("Error during veto of Job (" + + jec.getJobDetail().getKey() + + ": couldn't finalize execution.", se); + } + break; + } - int instCode = Trigger.INSTRUCTION_NOOP; + long startTime = System.currentTimeMillis(); + long endTime = startTime; - // update the trigger - try { - instCode = trigger.executionComplete(jec, jobExEx); - } catch (Exception e) { - // If this happens, there's a bug in the trigger... - SchedulerException se = new SchedulerException( - "Trigger threw an unhandled exception.", e); - se.setErrorCode(SchedulerException.ERR_TRIGGER_THREW_EXCEPTION); - qs.notifySchedulerListenersError( - "Please report this error to the Quartz developers.", - se); - } + // execute the job + try { + log.debug("Calling execute on job " + jobDetail.getKey()); + job.execute(jec); + endTime = System.currentTimeMillis(); + } catch (JobExecutionException jee) { + endTime = System.currentTimeMillis(); + jobExEx = jee; + getLog().info("Job " + jobDetail.getKey() + + " threw a JobExecutionException: ", jobExEx); + } catch (Throwable e) { + endTime = System.currentTimeMillis(); + getLog().error("Job " + jobDetail.getKey() + + " threw an unhandled Exception: ", e); + SchedulerException se = new SchedulerException( + "Job threw an unhandled exception.", e); + qs.notifySchedulerListenersError("Job (" + + jec.getJobDetail().getKey() + + " threw an exception.", se); + jobExEx = new JobExecutionException(se, false); + } - // notify all trigger listeners - if (!notifyTriggerListenersComplete(jec, instCode)) break; + jec.setJobRunTime(endTime - startTime); - // update job/trigger or re-execute job - if (instCode == Trigger.INSTRUCTION_RE_EXECUTE_JOB) { - jec.incrementRefireCount(); + // notify all job listeners + if (!notifyJobListenersComplete(jec, jobExEx)) { + break; + } + + CompletedExecutionInstruction instCode = CompletedExecutionInstruction.NOOP; + + // update the trigger try { - complete(false); + instCode = trigger.executionComplete(jec, jobExEx); + } catch (Exception e) { + // If this happens, there's a bug in the trigger... + SchedulerException se = new SchedulerException( + "Trigger threw an unhandled exception.", e); + qs.notifySchedulerListenersError( + "Please report this error to the Quartz developers.", + se); + } + + // notify all trigger listeners + if (!notifyTriggerListenersComplete(jec, instCode)) { + break; + } + + // update job/trigger or re-execute job + if (instCode == CompletedExecutionInstruction.RE_EXECUTE_JOB) { + jec.incrementRefireCount(); + try { + complete(false); + } catch (SchedulerException se) { + qs.notifySchedulerListenersError("Error executing Job (" + + jec.getJobDetail().getKey() + + ": couldn't finalize execution.", se); + } + continue; + } + + try { + complete(true); } catch (SchedulerException se) { qs.notifySchedulerListenersError("Error executing Job (" - + jec.getJobDetail().getFullName() + + jec.getJobDetail().getKey() + ": couldn't finalize execution.", se); + continue; } - continue; - } - try { - complete(true); - } catch (SchedulerException se) { - qs.notifySchedulerListenersError("Error executing Job (" - + jec.getJobDetail().getFullName() - + ": couldn't finalize execution.", se); - continue; - } + qs.notifyJobStoreJobComplete(trigger, jobDetail, instCode); + break; + } while (true); - try { - qs.notifyJobStoreJobComplete(schdCtxt, trigger, jobDetail, - instCode); - } catch (JobPersistenceException jpe) { - qs.notifySchedulerListenersError( - "An error occured while marking executed job complete. job= '" - + jobDetail.getFullName() + "'", jpe); - if (!completeTriggerRetryLoop(trigger, jobDetail, instCode)) - ; - return; - } - - break; - } while (true); - - qs.notifySchedulerThread(); - - jobRunShellFactory.returnJobRunShell(this); + } finally { + qs.removeInternalSchedulerListener(this); + } } protected void begin() throws SchedulerException { } protected void complete(boolean successfulExecution) - throws SchedulerException { + throws SchedulerException { } public void passivate() { jec = null; qs = null; } - private boolean notifyListenersBeginning(JobExecutionContext jec) throws VetoedException { - + private boolean notifyListenersBeginning(JobExecutionContext jobExCtxt) throws VetoedException { + boolean vetoed = false; - + // notify all trigger listeners try { - vetoed = qs.notifyTriggerListenersFired(jec); + vetoed = qs.notifyTriggerListenersFired(jobExCtxt); } catch (SchedulerException se) { qs.notifySchedulerListenersError( "Unable to notify TriggerListener(s) while firing trigger " + "(Trigger and Job will NOT be fired!). trigger= " - + jec.getTrigger().getFullName() + " job= " - + jec.getJobDetail().getFullName(), se); + + jobExCtxt.getTrigger().getKey() + " job= " + + jobExCtxt.getJobDetail().getKey(), se); return false; } if(vetoed) { try { - qs.notifyJobListenersWasVetoed(jec); + qs.notifyJobListenersWasVetoed(jobExCtxt); } catch (SchedulerException se) { qs.notifySchedulerListenersError( "Unable to notify JobListener(s) of vetoed execution " + "while firing trigger (Trigger and Job will NOT be " + "fired!). trigger= " - + jec.getTrigger().getFullName() + " job= " - + jec.getJobDetail().getFullName(), se); + + jobExCtxt.getTrigger().getKey() + " job= " + + jobExCtxt.getJobDetail().getKey(), se); } throw new VetoedException(); } - + // notify all job listeners try { - qs.notifyJobListenersToBeExecuted(jec); + qs.notifyJobListenersToBeExecuted(jobExCtxt); } catch (SchedulerException se) { qs.notifySchedulerListenersError( "Unable to notify JobListener(s) of Job to be executed: " + "(Job will NOT be executed!). trigger= " - + jec.getTrigger().getFullName() + " job= " - + jec.getJobDetail().getFullName(), se); + + jobExCtxt.getTrigger().getKey() + " job= " + + jobExCtxt.getJobDetail().getKey(), se); return false; } return true; } - private boolean notifyJobListenersComplete(JobExecutionContext jec, - JobExecutionException jobExEx) { + private boolean notifyJobListenersComplete(JobExecutionContext jobExCtxt, JobExecutionException jobExEx) { try { - qs.notifyJobListenersWasExecuted(jec, jobExEx); + qs.notifyJobListenersWasExecuted(jobExCtxt, jobExEx); } catch (SchedulerException se) { qs.notifySchedulerListenersError( "Unable to notify JobListener(s) of Job that was executed: " + "(error will be ignored). trigger= " - + jec.getTrigger().getFullName() + " job= " - + jec.getJobDetail().getFullName(), se); + + jobExCtxt.getTrigger().getKey() + " job= " + + jobExCtxt.getJobDetail().getKey(), se); return false; } return true; } - private boolean notifyTriggerListenersComplete(JobExecutionContext jec, - int instCode) { + private boolean notifyTriggerListenersComplete(JobExecutionContext jobExCtxt, CompletedExecutionInstruction instCode) { try { - qs.notifyTriggerListenersComplete(jec, instCode); + qs.notifyTriggerListenersComplete(jobExCtxt, instCode); } catch (SchedulerException se) { qs.notifySchedulerListenersError( "Unable to notify TriggerListener(s) of Job that was executed: " + "(error will be ignored). trigger= " - + jec.getTrigger().getFullName() + " job= " - + jec.getJobDetail().getFullName(), se); + + jobExCtxt.getTrigger().getKey() + " job= " + + jobExCtxt.getJobDetail().getKey(), se); return false; } - if (jec.getTrigger().getNextFireTime() == null) - qs.notifySchedulerListenersFinalized(jec.getTrigger()); + if (jobExCtxt.getTrigger().getNextFireTime() == null) { + qs.notifySchedulerListenersFinalized(jobExCtxt.getTrigger()); + } return true; } - public boolean completeTriggerRetryLoop(Trigger trigger, - JobDetail jobDetail, int instCode) { - while (!shutdownRequested) { - try { - Thread.sleep(5 * 1000l); // retry every 5 seconds (the db - // connection must be failed) - qs.notifyJobStoreJobComplete(schdCtxt, trigger, jobDetail, - instCode); - return true; - } catch (JobPersistenceException jpe) { - qs.notifySchedulerListenersError( - "An error occured while marking executed job complete. job= '" - + jobDetail.getFullName() + "'", jpe); - } catch (InterruptedException ignore) { - } - } - return false; - } + static class VetoedException extends Exception { - - class VetoedException extends Exception - { - public VetoedException() - { + private static final long serialVersionUID = 1539955697495918463L; + + public VetoedException() { } } -} \ No newline at end of file + +} Index: 3rdParty_sources/quartz/org/quartz/core/JobRunShellFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/core/JobRunShellFactory.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/core/JobRunShellFactory.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/core/JobRunShellFactory.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,29 +16,19 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.core; import org.quartz.Scheduler; import org.quartz.SchedulerConfigException; import org.quartz.SchedulerException; +import org.quartz.spi.TriggerFiredBundle; /** *

* Responsible for creating the instances of {@link JobRunShell} * to be used within the {@link QuartzScheduler} instance. *

* - *

- * Although this interface looks a lot like an 'object pool', implementations - * do not have to support the re-use of instances. If an implementation does - * not wish to pool instances, then the borrowJobRunShell() - * method would simply create a new instance, and the returnJobRunShell - * method would do nothing. - *

- * * @author James House */ public interface JobRunShellFactory { @@ -55,28 +45,17 @@ *

* Initialize the factory, providing a handle to the Scheduler * that should be made available within the JobRunShell and - * the JobExecutionCOntext s within it, and a handle to the - * SchedulingContext that the shell will use in its own - * operations with the JobStore. + * the JobExecutionContext s within it. *

*/ - public void initialize(Scheduler scheduler, SchedulingContext schedCtxt) - throws SchedulerConfigException; + void initialize(Scheduler scheduler) + throws SchedulerConfigException; /** *

* Called by the {@link org.quartz.core.QuartzSchedulerThread} * to obtain instances of {@link JobRunShell}. *

*/ - public JobRunShell borrowJobRunShell() throws SchedulerException; - - /** - *

- * Called by the {@link org.quartz.core.QuartzSchedulerThread} - * to return instances of {@link JobRunShell}. - *

- */ - public void returnJobRunShell(JobRunShell jobRunShell); - + JobRunShell createJobRunShell(TriggerFiredBundle bundle) throws SchedulerException; } \ No newline at end of file Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/core/ListenerManagerImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/core/NullSampledStatisticsImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/core/QuartzScheduler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/core/QuartzScheduler.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/core/QuartzScheduler.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/core/QuartzScheduler.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,58 +16,76 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.core; -import java.io.IOException; import java.io.InputStream; +import java.lang.management.ManagementFactory; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; import java.util.ArrayList; -import java.util.Collections; +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Properties; import java.util.Random; import java.util.Set; +import java.util.Timer; +import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicInteger; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import javax.management.MBeanServer; +import javax.management.ObjectName; + import org.quartz.Calendar; import org.quartz.InterruptableJob; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; +import org.quartz.JobKey; import org.quartz.JobListener; -import org.quartz.JobPersistenceException; +import org.quartz.ListenerManager; +import org.quartz.Matcher; import org.quartz.ObjectAlreadyExistsException; import org.quartz.Scheduler; import org.quartz.SchedulerContext; import org.quartz.SchedulerException; import org.quartz.SchedulerListener; +import org.quartz.SchedulerMetaData; import org.quartz.Trigger; +import static org.quartz.TriggerBuilder.*; +import org.quartz.TriggerKey; import org.quartz.TriggerListener; import org.quartz.UnableToInterruptJobException; +import org.quartz.Trigger.CompletedExecutionInstruction; +import org.quartz.Trigger.TriggerState; +import org.quartz.core.jmx.QuartzSchedulerMBean; import org.quartz.impl.SchedulerRepository; -import org.quartz.simpl.SimpleJobFactory; +import org.quartz.impl.StdSchedulerFactory; +import org.quartz.impl.matchers.GroupMatcher; +import org.quartz.listeners.SchedulerListenerSupport; +import org.quartz.simpl.PropertySettingJobFactory; import org.quartz.spi.JobFactory; +import org.quartz.spi.OperableTrigger; import org.quartz.spi.SchedulerPlugin; import org.quartz.spi.SchedulerSignaler; +import org.quartz.spi.ThreadExecutor; +import org.quartz.utils.UpdateChecker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** *

* This is the heart of Quartz, an indirect implementation of the {@link org.quartz.Scheduler} * interface, containing methods to schedule {@link org.quartz.Job}s, * register {@link org.quartz.JobListener} instances, etc. - *

// TODO: more docs... + *

* * @see org.quartz.Scheduler * @see org.quartz.core.QuartzSchedulerThread @@ -92,17 +110,32 @@ static { Properties props = new Properties(); + InputStream is = null; try { - InputStream is = - QuartzScheduler.class.getResourceAsStream("/build.properties"); + is = QuartzScheduler.class.getResourceAsStream("quartz-build.properties"); if(is != null) { props.load(is); - VERSION_MAJOR = props.getProperty("version.major"); - VERSION_MINOR = props.getProperty("version.minor"); - VERSION_ITERATION = props.getProperty("version.iter"); + String version = props.getProperty("version"); + if (version != null) { + String[] versionComponents = version.split("\\."); + VERSION_MAJOR = versionComponents[0]; + VERSION_MINOR = versionComponents[1]; + if(versionComponents.length > 2) + VERSION_ITERATION = versionComponents[2]; + else + VERSION_ITERATION = "0"; + } else { + (LoggerFactory.getLogger(QuartzScheduler.class)).error( + "Can't parse Quartz version from quartz-build.properties"); + } } - } catch (IOException e) { - getLog().error("Error loading version info from build.properties.", e); + } catch (Exception e) { + (LoggerFactory.getLogger(QuartzScheduler.class)).error( + "Error loading version info from quartz-build.properties.", e); + } finally { + if(is != null) { + try { is.close(); } catch(Exception ignore) {} + } } } @@ -123,19 +156,15 @@ private SchedulerContext context = new SchedulerContext(); - private HashMap jobListeners = new HashMap(10); + private ListenerManager listenerManager = new ListenerManagerImpl(); + + private HashMap internalJobListeners = new HashMap(10); - private ArrayList globalJobListeners = new ArrayList(10); + private HashMap internalTriggerListeners = new HashMap(10); - private HashMap triggerListeners = new HashMap(10); + private ArrayList internalSchedulerListeners = new ArrayList(10); - private ArrayList globalTriggerListeners = new ArrayList(10); - - private ArrayList schedulerListeners = new ArrayList(10); - - private ArrayList schedulerPlugins = new ArrayList(10); - - private JobFactory jobFactory = new SimpleJobFactory(); + private JobFactory jobFactory = new PropertySettingJobFactory(); ExecutingJobsManager jobMgr = null; @@ -145,14 +174,27 @@ private Random random = new Random(); - private ArrayList holdToPreventGC = new ArrayList(5); + private ArrayList holdToPreventGC = new ArrayList(5); private boolean signalOnSchedulingChange = true; - private boolean closed = false; + private volatile boolean closed = false; + private volatile boolean shuttingDown = false; + private boolean boundRemotely = false; + private QuartzSchedulerMBean jmxBean = null; + private Date initialStart = null; + + /** Update timer that must be cancelled upon shutdown. */ + private final Timer updateTimer; + private final Logger log = LoggerFactory.getLogger(getClass()); + + // private static final Map MGMT_SVR_BY_BIND = new + // HashMap(); + // private String registeredManagementServerBind; + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -169,32 +211,106 @@ * * @see QuartzSchedulerResources */ - public QuartzScheduler(QuartzSchedulerResources resources, - SchedulingContext ctxt, long idleWaitTime, long dbRetryInterval) - throws SchedulerException { + public QuartzScheduler(QuartzSchedulerResources resources, long idleWaitTime, @Deprecated long dbRetryInterval) + throws SchedulerException { this.resources = resources; - try { - bind(); - } catch (Exception re) { - throw new SchedulerException( - "Unable to bind scheduler to RMI Registry.", re); + if (resources.getJobStore() instanceof JobListener) { + addInternalJobListener((JobListener)resources.getJobStore()); } - this.schedThread = new QuartzSchedulerThread(this, resources, ctxt); - if (idleWaitTime > 0) this.schedThread.setIdleWaitTime(idleWaitTime); - if (dbRetryInterval > 0) - this.schedThread.setDbFailureRetryInterval(dbRetryInterval); + this.schedThread = new QuartzSchedulerThread(this, resources); + ThreadExecutor schedThreadExecutor = resources.getThreadExecutor(); + schedThreadExecutor.execute(this.schedThread); + if (idleWaitTime > 0) { + this.schedThread.setIdleWaitTime(idleWaitTime); + } jobMgr = new ExecutingJobsManager(); - addGlobalJobListener(jobMgr); + addInternalJobListener(jobMgr); errLogger = new ErrorLogger(); - addSchedulerListener(errLogger); + addInternalSchedulerListener(errLogger); - signaler = new SchedulerSignalerImpl(this); + signaler = new SchedulerSignalerImpl(this, this.schedThread); + if(shouldRunUpdateCheck()) + updateTimer = scheduleUpdateCheck(); + else + updateTimer = null; + getLog().info("Quartz Scheduler v." + getVersion() + " created."); } + public void initialize() throws SchedulerException { + + try { + bind(); + } catch (Exception re) { + throw new SchedulerException( + "Unable to bind scheduler to RMI Registry.", re); + } + + if (resources.getJMXExport()) { + try { + registerJMX(); + } catch (Exception e) { + throw new SchedulerException( + "Unable to register scheduler with MBeanServer.", e); + } + } + + // ManagementRESTServiceConfiguration managementRESTServiceConfiguration + // = resources.getManagementRESTServiceConfiguration(); + // + // if (managementRESTServiceConfiguration != null && + // managementRESTServiceConfiguration.isEnabled()) { + // try { + // /** + // * ManagementServer will only be instantiated and started if one + // * isn't already running on the configured port for this class + // * loader space. + // */ + // synchronized (QuartzScheduler.class) { + // if + // (!MGMT_SVR_BY_BIND.containsKey(managementRESTServiceConfiguration.getBind())) + // { + // Class managementServerImplClass = + // Class.forName("org.quartz.management.ManagementServerImpl"); + // Class managementRESTServiceConfigurationClass[] = new Class[] { + // managementRESTServiceConfiguration.getClass() }; + // Constructor managementRESTServiceConfigurationConstructor = + // managementServerImplClass + // .getConstructor(managementRESTServiceConfigurationClass); + // Object arglist[] = new Object[] { managementRESTServiceConfiguration + // }; + // ManagementServer embeddedRESTServer = ((ManagementServer) + // managementRESTServiceConfigurationConstructor.newInstance(arglist)); + // embeddedRESTServer.start(); + // MGMT_SVR_BY_BIND.put(managementRESTServiceConfiguration.getBind(), + // embeddedRESTServer); + // } + // registeredManagementServerBind = + // managementRESTServiceConfiguration.getBind(); + // ManagementServer embeddedRESTServer = + // MGMT_SVR_BY_BIND.get(registeredManagementServerBind); + // embeddedRESTServer.register(this); + // } + // } catch (Exception e) { + // throw new + // SchedulerException("Unable to start the scheduler management REST service", + // e); + // } + // } + + + getLog().info("Scheduler meta-data: " + + (new SchedulerMetaData(getSchedulerName(), + getSchedulerInstanceId(), getClass(), boundRemotely, runningSince() != null, + isInStandbyMode(), isShutdown(), runningSince(), + numJobsExecuted(), getJobStoreClass(), + supportsPersistence(), isClustered(), getThreadPoolClass(), + getThreadPoolSize(), getVersion())).toString()); + } + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -211,6 +327,14 @@ public static String getVersionMajor() { return VERSION_MAJOR; } + + private boolean shouldRunUpdateCheck() { + if(resources.isRunUpdateCheck() && !Boolean.getBoolean(StdSchedulerFactory.PROP_SCHED_SKIP_UPDATE_CHECK) && + !Boolean.getBoolean("org.terracotta.quartz.skipUpdateCheck")) { + return true; + } + return false; + } public static String getVersionMinor() { return VERSION_MINOR; @@ -224,28 +348,61 @@ return signaler; } - public static Log getLog() { - return LogFactory.getLog(QuartzScheduler.class); + public Logger getLog() { + return log; } + + /** + * Update checker scheduler - fires every week + */ + private Timer scheduleUpdateCheck() { + Timer rval = new Timer(true); + rval.scheduleAtFixedRate(new UpdateChecker(), 1000, 7 * 24 * 60 * 60 * 1000L); + return rval; + } /** + * Register the scheduler in the local MBeanServer. + */ + private void registerJMX() throws Exception { + String jmxObjectName = resources.getJMXObjectName(); + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + jmxBean = new QuartzSchedulerMBeanImpl(this); + mbs.registerMBean(jmxBean, new ObjectName(jmxObjectName)); + } + + /** + * Unregister the scheduler from the local MBeanServer. + */ + private void unregisterJMX() throws Exception { + String jmxObjectName = resources.getJMXObjectName(); + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + mbs.unregisterMBean(new ObjectName(jmxObjectName)); + jmxBean.setSampledStatisticsEnabled(false); + getLog().info("Scheduler unregistered from name '" + jmxObjectName + "' in the local MBeanServer."); + } + + /** *

* Bind the scheduler to an RMI registry. *

*/ private void bind() throws RemoteException { String host = resources.getRMIRegistryHost(); // don't export if we're not configured to do so... - if (host == null || host.length() == 0) return; + if (host == null || host.length() == 0) { + return; + } RemotableQuartzScheduler exportable = null; - if(resources.getRMIServerPort() > 0) + if(resources.getRMIServerPort() > 0) { exportable = (RemotableQuartzScheduler) UnicastRemoteObject .exportObject(this, resources.getRMIServerPort()); - else + } else { exportable = (RemotableQuartzScheduler) UnicastRemoteObject .exportObject(this); + } Registry registry = null; @@ -283,9 +440,13 @@ .getRMIRegistryHost(), resources.getRMIRegistryPort()); } - registry.rebind(resources.getUniqueIdentifier(), exportable); + String bindName = resources.getRMIBindName(); + + registry.rebind(bindName, exportable); + + boundRemotely = true; - getLog().info("Scheduler bound to RMI registry."); + getLog().info("Scheduler bound to RMI registry under name '" + bindName + "'"); } /** @@ -296,18 +457,22 @@ private void unBind() throws RemoteException { String host = resources.getRMIRegistryHost(); // don't un-export if we're not configured to do so... - if (host == null || host.length() == 0) return; + if (host == null || host.length() == 0) { + return; + } Registry registry = LocateRegistry.getRegistry(resources .getRMIRegistryHost(), resources.getRMIRegistryPort()); + String bindName = resources.getRMIBindName(); + try { - registry.unbind(resources.getUniqueIdentifier()); + registry.unbind(bindName); UnicastRemoteObject.unexportObject(this, true); } catch (java.rmi.NotBoundException nbe) { } - getLog().info("Scheduler un-bound from RMI registry."); + getLog().info("Scheduler un-bound from name '" + bindName + "' in RMI registry"); } /** @@ -330,13 +495,16 @@ /** *

- * Returns the name of the QuartzScheduler. + * Returns the name of the thread group for Quartz's main threads. *

*/ public ThreadGroup getSchedulerThreadGroup() { if (threadGroup == null) { threadGroup = new ThreadGroup("QuartzScheduler:" + getSchedulerName()); + if (resources.getMakeSchedulerThreadDaemon()) { + threadGroup.setDaemon(true); + } } return threadGroup; @@ -369,7 +537,7 @@ /////////////////////////////////////////////////////////////////////////// /// - /// Schedululer State Management Methods + /// Scheduler State Management Methods /// /////////////////////////////////////////////////////////////////////////// @@ -385,22 +553,51 @@ */ public void start() throws SchedulerException { - if (closed) - throw new SchedulerException( - "The Scheduler cannot be restarted after shutdown() has been called."); + if (shuttingDown|| closed) { + throw new SchedulerException( + "The Scheduler cannot be restarted after shutdown() has been called."); + } - schedThread.togglePause(false); + // QTZ-212 : calling new schedulerStarting() method on the listeners + // right after entering start() + notifySchedulerListenersStarting(); if (initialStart == null) { initialStart = new Date(); this.resources.getJobStore().schedulerStarted(); startPlugins(); + } else { + resources.getJobStore().schedulerResumed(); } + schedThread.togglePause(false); + getLog().info( "Scheduler " + resources.getUniqueIdentifier() + " started."); + + notifySchedulerListenersStarted(); } + public void startDelayed(final int seconds) throws SchedulerException + { + if (shuttingDown || closed) { + throw new SchedulerException( + "The Scheduler cannot be restarted after shutdown() has been called."); + } + + Thread t = new Thread(new Runnable() { + public void run() { + try { Thread.sleep(seconds * 1000L); } + catch(InterruptedException ignore) {} + try { start(); } + catch(SchedulerException se) { + getLog().error("Unable to start secheduler after startup delay.", se); + } + } + }); + t.start(); + } + /** *

* Temporarily halts the QuartzScheduler's firing of {@link org.quartz.Trigger}s. @@ -411,9 +608,11 @@ *

*/ public void standby() { + resources.getJobStore().schedulerPaused(); schedThread.togglePause(true); getLog().info( "Scheduler " + resources.getUniqueIdentifier() + " paused."); + notifySchedulerListenersInStandbyMode(); } /** @@ -426,22 +625,28 @@ } public Date runningSince() { - return initialStart; + if(initialStart == null) + return null; + return new Date(initialStart.getTime()); } public int numJobsExecuted() { return jobMgr.getNumJobsFired(); } - public Class getJobStoreClass() { + public Class getJobStoreClass() { return resources.getJobStore().getClass(); } public boolean supportsPersistence() { return resources.getJobStore().supportsPersistence(); } - public Class getThreadPoolClass() { + public boolean isClustered() { + return resources.getJobStore().isClustered(); + } + + public Class getThreadPoolClass() { return resources.getThreadPool().getClass(); } @@ -480,43 +685,89 @@ */ public void shutdown(boolean waitForJobsToComplete) { - if(closed == true) + if(shuttingDown || closed) { return; + } + shuttingDown = true; + getLog().info( "Scheduler " + resources.getUniqueIdentifier() + " shutting down."); + // boolean removeMgmtSvr = false; + // if (registeredManagementServerBind != null) { + // ManagementServer standaloneRestServer = + // MGMT_SVR_BY_BIND.get(registeredManagementServerBind); + // + // try { + // standaloneRestServer.unregister(this); + // + // if (!standaloneRestServer.hasRegistered()) { + // removeMgmtSvr = true; + // standaloneRestServer.stop(); + // } + // } catch (Exception e) { + // getLog().warn("Failed to shutdown the ManagementRESTService", e); + // } finally { + // if (removeMgmtSvr) { + // MGMT_SVR_BY_BIND.remove(registeredManagementServerBind); + // } + // + // registeredManagementServerBind = null; + // } + // } + standby(); + schedThread.halt(waitForJobsToComplete); + + notifySchedulerListenersShuttingdown(); + + if( (resources.isInterruptJobsOnShutdown() && !waitForJobsToComplete) || + (resources.isInterruptJobsOnShutdownWithWait() && waitForJobsToComplete)) { + List jobs = getCurrentlyExecutingJobs(); + for(JobExecutionContext job: jobs) { + if(job.getJobInstance() instanceof InterruptableJob) + try { + ((InterruptableJob)job.getJobInstance()).interrupt(); + } catch (Throwable e) { + // do nothing, this was just a courtesy effort + getLog().warn("Encountered error when interrupting job {} during shutdown: {}", job.getJobDetail().getKey(), e); + } + } + } + + resources.getThreadPool().shutdown(waitForJobsToComplete); + closed = true; - schedThread.halt(); + if (resources.getJMXExport()) { + try { + unregisterJMX(); + } catch (Exception e) { + } + } - resources.getThreadPool().shutdown(waitForJobsToComplete); - - if (waitForJobsToComplete) { - while (jobMgr.getNumJobsCurrentlyExecuting() > 0) - try { - Thread.sleep(100); - } catch (Exception ignore) { - } + if(boundRemotely) { + try { + unBind(); + } catch (RemoteException re) { + } } + + shutdownPlugins(); resources.getJobStore().shutdown(); notifySchedulerListenersShutdown(); - shutdownPlugins(); - SchedulerRepository.getInstance().remove(resources.getName()); holdToPreventGC.clear(); - try { - unBind(); - } catch (RemoteException re) { - } - + if(updateTimer != null) + updateTimer.cancel(); + getLog().info( "Scheduler " + resources.getUniqueIdentifier() + " shutdown complete."); @@ -531,25 +782,40 @@ return closed; } + public boolean isShuttingDown() { + return shuttingDown; + } + + public boolean isStarted() { + return !shuttingDown && !closed && !isInStandbyMode() && initialStart != null; + } + public void validateState() throws SchedulerException { - if (isShutdown()) - throw new SchedulerException("The Scheduler has been shutdown."); + if (isShutdown()) { + throw new SchedulerException("The Scheduler has been shutdown."); + } // other conditions to check (?) } /** *

* Return a list of JobExecutionContext objects that - * represent all currently executing Jobs. + * represent all currently executing Jobs in this Scheduler instance. *

* *

+ * This method is not cluster aware. That is, it will only return Jobs + * currently executing in this Scheduler instance, not across the entire + * cluster. + *

+ * + *

* Note that the list returned is an 'instantaneous' snap-shot, and that as * soon as it's returned, the true list of executing jobs may be different. *

*/ - public List getCurrentlyExecutingJobs() { + public List getCurrentlyExecutingJobs() { return jobMgr.getExecutingJobs(); } @@ -575,43 +841,51 @@ * if the Job or Trigger cannot be added to the Scheduler, or * there is an internal Scheduler error. */ - public Date scheduleJob(SchedulingContext ctxt, JobDetail jobDetail, + public Date scheduleJob(JobDetail jobDetail, Trigger trigger) throws SchedulerException { validateState(); - jobDetail.validate(); + if (jobDetail == null) { + throw new SchedulerException("JobDetail cannot be null"); + } + + if (trigger == null) { + throw new SchedulerException("Trigger cannot be null"); + } + + if (jobDetail.getKey() == null) { + throw new SchedulerException("Job's key cannot be null"); + } - if (trigger.getJobName() == null) { - trigger.setJobName(jobDetail.getName()); - trigger.setJobGroup(jobDetail.getGroup()); - } else if (trigger.getJobName() != null - && !trigger.getJobName().equals(jobDetail.getName())) { + if (jobDetail.getJobClass() == null) { + throw new SchedulerException("Job's class cannot be null"); + } + + OperableTrigger trig = (OperableTrigger)trigger; + + if (trigger.getJobKey() == null) { + trig.setJobKey(jobDetail.getKey()); + } else if (!trigger.getJobKey().equals(jobDetail.getKey())) { throw new SchedulerException( - "Trigger does not reference given job!", - SchedulerException.ERR_CLIENT_ERROR); - } else if (trigger.getJobGroup() != null - && !trigger.getJobGroup().equals(jobDetail.getGroup())) { - throw new SchedulerException( - "Trigger does not reference given job!", - SchedulerException.ERR_CLIENT_ERROR); + "Trigger does not reference given job!"); } - trigger.validate(); + trig.validate(); Calendar cal = null; if (trigger.getCalendarName() != null) { - cal = resources.getJobStore().retrieveCalendar(ctxt, - trigger.getCalendarName()); + cal = resources.getJobStore().retrieveCalendar(trigger.getCalendarName()); } - Date ft = trigger.computeFirstFireTime(cal); + Date ft = trig.computeFirstFireTime(cal); - if (ft == null) - throw new SchedulerException( - "Based on configured schedule, the given trigger will never fire.", - SchedulerException.ERR_CLIENT_ERROR); + if (ft == null) { + throw new SchedulerException( + "Based on configured schedule, the given trigger '" + trigger.getKey() + "' will never fire."); + } - resources.getJobStore().storeJobAndTrigger(ctxt, jobDetail, trigger); - notifySchedulerThread(); + resources.getJobStore().storeJobAndTrigger(jobDetail, trig); + notifySchedulerListenersJobAdded(jobDetail); + notifySchedulerThread(trigger.getNextFireTime().getTime()); notifySchedulerListenersSchduled(trigger); return ft; @@ -628,30 +902,35 @@ * added to the Scheduler, or there is an internal Scheduler * error. */ - public Date scheduleJob(SchedulingContext ctxt, Trigger trigger) - throws SchedulerException { + public Date scheduleJob(Trigger trigger) + throws SchedulerException { validateState(); - trigger.validate(); + if (trigger == null) { + throw new SchedulerException("Trigger cannot be null"); + } + OperableTrigger trig = (OperableTrigger)trigger; + + trig.validate(); + Calendar cal = null; if (trigger.getCalendarName() != null) { - cal = resources.getJobStore().retrieveCalendar(ctxt, - trigger.getCalendarName()); - if(cal == null) + cal = resources.getJobStore().retrieveCalendar(trigger.getCalendarName()); + if(cal == null) { throw new SchedulerException( - "Calendar not found: " + trigger.getCalendarName(), - SchedulerException.ERR_PERSISTENCE_CALENDAR_DOES_NOT_EXIST); + "Calendar not found: " + trigger.getCalendarName()); + } } - Date ft = trigger.computeFirstFireTime(cal); + Date ft = trig.computeFirstFireTime(cal); - if (ft == null) - throw new SchedulerException( - "Based on configured schedule, the given trigger will never fire.", - SchedulerException.ERR_CLIENT_ERROR); + if (ft == null) { + throw new SchedulerException( + "Based on configured schedule, the given trigger '" + trigger.getKey() + "' will never fire."); + } - resources.getJobStore().storeTrigger(ctxt, trigger, false); - notifySchedulerThread(); + resources.getJobStore().storeTrigger(trig, false); + notifySchedulerThread(trigger.getNextFireTime().getTime()); notifySchedulerListenersSchduled(trigger); return ft; @@ -675,16 +954,21 @@ * durable, or a Job with the same name already exists, and * replace is false. */ - public void addJob(SchedulingContext ctxt, JobDetail jobDetail, - boolean replace) throws SchedulerException { + public void addJob(JobDetail jobDetail, boolean replace) throws SchedulerException { + addJob(jobDetail, replace, false); + } + + public void addJob(JobDetail jobDetail, boolean replace, boolean storeNonDurableWhileAwaitingScheduling) throws SchedulerException { validateState(); - if (!jobDetail.isDurable() && !replace) - throw new SchedulerException( - "Jobs added with no trigger must be durable.", - SchedulerException.ERR_CLIENT_ERROR); + if (!storeNonDurableWhileAwaitingScheduling && !jobDetail.isDurable()) { + throw new SchedulerException( + "Jobs added with no trigger must be durable."); + } - resources.getJobStore().storeJob(ctxt, jobDetail, replace); + resources.getJobStore().storeJob(jobDetail, replace); + notifySchedulerThread(0L); + notifySchedulerListenersJobAdded(jobDetail); } /** @@ -697,34 +981,118 @@ * @throws SchedulerException * if there is an internal Scheduler error. */ - public boolean deleteJob(SchedulingContext ctxt, String jobName, - String groupName) throws SchedulerException { + public boolean deleteJob(JobKey jobKey) throws SchedulerException { validateState(); - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; + boolean result = false; - return resources.getJobStore().removeJob(ctxt, jobName, groupName); + List triggers = getTriggersOfJob(jobKey); + for (Trigger trigger : triggers) { + if (!unscheduleJob(trigger.getKey())) { + StringBuilder sb = new StringBuilder().append( + "Unable to unschedule trigger [").append( + trigger.getKey()).append("] while deleting job [") + .append(jobKey).append( + "]"); + throw new SchedulerException(sb.toString()); + } + result = true; + } + + result = resources.getJobStore().removeJob(jobKey) || result; + if (result) { + notifySchedulerThread(0L); + notifySchedulerListenersJobDeleted(jobKey); + } + return result; } + public boolean deleteJobs(List jobKeys) throws SchedulerException { + validateState(); + + boolean result = false; + + result = resources.getJobStore().removeJobs(jobKeys); + notifySchedulerThread(0L); + for(JobKey key: jobKeys) + notifySchedulerListenersJobDeleted(key); + return result; + } + + public void scheduleJobs(Map> triggersAndJobs, boolean replace) throws SchedulerException { + validateState(); + + // make sure all triggers refer to their associated job + for(Entry> e: triggersAndJobs.entrySet()) { + JobDetail job = e.getKey(); + if(job == null) // there can be one of these (for adding a bulk set of triggers for pre-existing jobs) + continue; + Set triggers = e.getValue(); + if(triggers == null) // this is possible because the job may be durable, and not yet be having triggers + continue; + for(Trigger trigger: triggers) { + OperableTrigger opt = (OperableTrigger)trigger; + opt.setJobKey(job.getKey()); + + opt.validate(); + + Calendar cal = null; + if (trigger.getCalendarName() != null) { + cal = resources.getJobStore().retrieveCalendar(trigger.getCalendarName()); + if(cal == null) { + throw new SchedulerException( + "Calendar '" + trigger.getCalendarName() + "' not found for trigger: " + trigger.getKey()); + } + } + Date ft = opt.computeFirstFireTime(cal); + + if (ft == null) { + throw new SchedulerException( + "Based on configured schedule, the given trigger will never fire."); + } + } + } + + resources.getJobStore().storeJobsAndTriggers(triggersAndJobs, replace); + notifySchedulerThread(0L); + for(JobDetail job: triggersAndJobs.keySet()) + notifySchedulerListenersJobAdded(job); + } + + public void scheduleJob(JobDetail jobDetail, Set triggersForJob, + boolean replace) throws SchedulerException { + Map> triggersAndJobs = new HashMap>(); + triggersAndJobs.put(jobDetail, triggersForJob); + scheduleJobs(triggersAndJobs, replace); + } + + public boolean unscheduleJobs(List triggerKeys) throws SchedulerException { + validateState(); + + boolean result = false; + + result = resources.getJobStore().removeTriggers(triggerKeys); + notifySchedulerThread(0L); + for(TriggerKey key: triggerKeys) + notifySchedulerListenersUnscheduled(key); + return result; + } + /** *

* Remove the indicated {@link org.quartz.Trigger} from the * scheduler. *

*/ - public boolean unscheduleJob(SchedulingContext ctxt, String triggerName, - String groupName) throws SchedulerException { + public boolean unscheduleJob(TriggerKey triggerKey) throws SchedulerException { validateState(); - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; - - if (resources.getJobStore().removeTrigger(ctxt, triggerName, groupName)) { - notifySchedulerThread(); - notifySchedulerListenersUnschduled(triggerName, groupName); - } else + if (resources.getJobStore().removeTrigger(triggerKey)) { + notifySchedulerThread(0L); + notifySchedulerListenersUnscheduled(triggerKey); + } else { return false; + } return true; } @@ -736,44 +1104,52 @@ * given name, and store the new given one - which must be associated * with the same job. *

- * - * @param triggerName - * The name of the Trigger to be removed. - * @param groupName - * The group name of the Trigger to be removed. * @param newTrigger * The new Trigger to be stored. + * * @return null if a Trigger with the given * name & group was not found and removed from the store, otherwise * the first fire time of the newly scheduled trigger. */ - public Date rescheduleJob(SchedulingContext ctxt, String triggerName, - String groupName, Trigger newTrigger) throws SchedulerException { + public Date rescheduleJob(TriggerKey triggerKey, + Trigger newTrigger) throws SchedulerException { validateState(); - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; + if (triggerKey == null) { + throw new IllegalArgumentException("triggerKey cannot be null"); + } + if (newTrigger == null) { + throw new IllegalArgumentException("newTrigger cannot be null"); + } - newTrigger.validate(); + OperableTrigger trig = (OperableTrigger)newTrigger; + Trigger oldTrigger = getTrigger(triggerKey); + if (oldTrigger == null) { + return null; + } else { + trig.setJobKey(oldTrigger.getJobKey()); + } + trig.validate(); Calendar cal = null; if (newTrigger.getCalendarName() != null) { - cal = resources.getJobStore().retrieveCalendar(ctxt, + cal = resources.getJobStore().retrieveCalendar( newTrigger.getCalendarName()); } - Date ft = newTrigger.computeFirstFireTime(cal); + Date ft = trig.computeFirstFireTime(cal); - if (ft == null) + if (ft == null) { throw new SchedulerException( - "Based on configured schedule, the given trigger will never fire.", - SchedulerException.ERR_CLIENT_ERROR); + "Based on configured schedule, the given trigger will never fire."); + } - if (resources.getJobStore().replaceTrigger(ctxt, triggerName, groupName, newTrigger)) { - notifySchedulerThread(); - notifySchedulerListenersUnschduled(triggerName, groupName); + if (resources.getJobStore().replaceTrigger(triggerKey, trig)) { + notifySchedulerThread(newTrigger.getNextFireTime().getTime()); + notifySchedulerListenersUnscheduled(triggerKey); notifySchedulerListenersSchduled(newTrigger); - } else + } else { return null; + } return ft; @@ -782,7 +1158,9 @@ private String newTriggerId() { long r = random.nextLong(); - if (r < 0) r = -r; + if (r < 0) { + r = -r; + } return "MT_" + Long.toString(r, 30 + (int) (System.currentTimeMillis() % 7)); } @@ -793,104 +1171,87 @@ * now) - with a non-volatile trigger. *

*/ - public void triggerJob(SchedulingContext ctxt, String jobName, - String groupName, JobDataMap data) throws SchedulerException { + @SuppressWarnings("deprecation") + public void triggerJob(JobKey jobKey, JobDataMap data) throws SchedulerException { validateState(); - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; - - Trigger trig = new org.quartz.SimpleTrigger(newTriggerId(), - Scheduler.DEFAULT_MANUAL_TRIGGERS, jobName, groupName, - new Date(), null, 0, 0); - trig.setVolatility(false); + OperableTrigger trig = (OperableTrigger) newTrigger().withIdentity(newTriggerId(), Scheduler.DEFAULT_GROUP).forJob(jobKey).build(); trig.computeFirstFireTime(null); - if(data != null) + if(data != null) { trig.setJobDataMap(data); + } boolean collision = true; while (collision) { try { - resources.getJobStore().storeTrigger(ctxt, trig, false); + resources.getJobStore().storeTrigger(trig, false); collision = false; } catch (ObjectAlreadyExistsException oaee) { - trig.setName(newTriggerId()); + trig.setKey(new TriggerKey(newTriggerId(), Scheduler.DEFAULT_GROUP)); } } - notifySchedulerThread(); + notifySchedulerThread(trig.getNextFireTime().getTime()); notifySchedulerListenersSchduled(trig); } /** *

- * Trigger the identified {@link org.quartz.Job} (execute it - * now) - with a volatile trigger. + * Store and schedule the identified {@link org.quartz.spi.OperableTrigger} *

*/ - public void triggerJobWithVolatileTrigger(SchedulingContext ctxt, - String jobName, String groupName, JobDataMap data) throws SchedulerException { + public void triggerJob(OperableTrigger trig) throws SchedulerException { validateState(); - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; - - Trigger trig = new org.quartz.SimpleTrigger(newTriggerId(), - Scheduler.DEFAULT_MANUAL_TRIGGERS, jobName, groupName, - new Date(), null, 0, 0); - trig.setVolatility(true); trig.computeFirstFireTime(null); - if(data != null) - trig.setJobDataMap(data); - + boolean collision = true; while (collision) { try { - resources.getJobStore().storeTrigger(ctxt, trig, false); + resources.getJobStore().storeTrigger(trig, false); collision = false; } catch (ObjectAlreadyExistsException oaee) { - trig.setName(newTriggerId()); + trig.setKey(new TriggerKey(newTriggerId(), Scheduler.DEFAULT_GROUP)); } } - notifySchedulerThread(); + notifySchedulerThread(trig.getNextFireTime().getTime()); notifySchedulerListenersSchduled(trig); } - + /** *

* Pause the {@link Trigger} with the given name. *

* */ - public void pauseTrigger(SchedulingContext ctxt, String triggerName, - String groupName) throws SchedulerException { + public void pauseTrigger(TriggerKey triggerKey) throws SchedulerException { validateState(); - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; - - resources.getJobStore().pauseTrigger(ctxt, triggerName, groupName); - notifySchedulerThread(); - notifySchedulerListenersPausedTrigger(triggerName, groupName); + resources.getJobStore().pauseTrigger(triggerKey); + notifySchedulerThread(0L); + notifySchedulerListenersPausedTrigger(triggerKey); } /** *

- * Pause all of the {@link Trigger}s in the given group. + * Pause all of the {@link Trigger}s in the matching groups. *

* */ - public void pauseTriggerGroup(SchedulingContext ctxt, String groupName) - throws SchedulerException { + public void pauseTriggers(GroupMatcher matcher) + throws SchedulerException { validateState(); - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; - - resources.getJobStore().pauseTriggerGroup(ctxt, groupName); - notifySchedulerThread(); - notifySchedulerListenersPausedTrigger(null, groupName); + if(matcher == null) { + matcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP); + } + + Collection pausedGroups = resources.getJobStore().pauseTriggers(matcher); + notifySchedulerThread(0L); + for (String pausedGroup : pausedGroups) { + notifySchedulerListenersPausedTriggers(pausedGroup); + } } /** @@ -900,35 +1261,34 @@ *

* */ - public void pauseJob(SchedulingContext ctxt, String jobName, - String groupName) throws SchedulerException { + public void pauseJob(JobKey jobKey) throws SchedulerException { validateState(); - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; - - resources.getJobStore().pauseJob(ctxt, jobName, groupName); - notifySchedulerThread(); - notifySchedulerListenersPausedJob(jobName, groupName); + resources.getJobStore().pauseJob(jobKey); + notifySchedulerThread(0L); + notifySchedulerListenersPausedJob(jobKey); } /** *

* Pause all of the {@link org.quartz.JobDetail}s in the - * given group - by pausing all of their Triggers. + * matching groups - by pausing all of their Triggers. *

* */ - public void pauseJobGroup(SchedulingContext ctxt, String groupName) - throws SchedulerException { + public void pauseJobs(GroupMatcher groupMatcher) + throws SchedulerException { validateState(); - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; + if(groupMatcher == null) { + groupMatcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP); + } - resources.getJobStore().pauseJobGroup(ctxt, groupName); - notifySchedulerThread(); - notifySchedulerListenersPausedJob(null, groupName); + Collection pausedGroups = resources.getJobStore().pauseJobs(groupMatcher); + notifySchedulerThread(0L); + for (String pausedGroup : pausedGroups) { + notifySchedulerListenersPausedJobs(pausedGroup); + } } /** @@ -943,22 +1303,18 @@ *

* */ - public void resumeTrigger(SchedulingContext ctxt, String triggerName, - String groupName) throws SchedulerException { + public void resumeTrigger(TriggerKey triggerKey) throws SchedulerException { validateState(); - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; - - resources.getJobStore().resumeTrigger(ctxt, triggerName, groupName); - notifySchedulerThread(); - notifySchedulerListenersResumedTrigger(triggerName, groupName); + resources.getJobStore().resumeTrigger(triggerKey); + notifySchedulerThread(0L); + notifySchedulerListenersResumedTrigger(triggerKey); } /** *

* Resume (un-pause) all of the {@link Trigger}s in the - * given group. + * matching groups. *

* *

@@ -967,20 +1323,23 @@ *

* */ - public void resumeTriggerGroup(SchedulingContext ctxt, String groupName) - throws SchedulerException { + public void resumeTriggers(GroupMatcher matcher) + throws SchedulerException { validateState(); - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; - - resources.getJobStore().resumeTriggerGroup(ctxt, groupName); - notifySchedulerThread(); - notifySchedulerListenersResumedTrigger(null, groupName); + if(matcher == null) { + matcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP); + } + + Collection pausedGroups = resources.getJobStore().resumeTriggers(matcher); + notifySchedulerThread(0L); + for (String pausedGroup : pausedGroups) { + notifySchedulerListenersResumedTriggers(pausedGroup); + } } - public Set getPausedTriggerGroups(SchedulingContext ctxt) throws SchedulerException { - return resources.getJobStore().getPausedTriggerGroups(ctxt); + public Set getPausedTriggerGroups() throws SchedulerException { + return resources.getJobStore().getPausedTriggerGroups(); } /** @@ -996,22 +1355,18 @@ *

* */ - public void resumeJob(SchedulingContext ctxt, String jobName, - String groupName) throws SchedulerException { + public void resumeJob(JobKey jobKey) throws SchedulerException { validateState(); - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; - - resources.getJobStore().resumeJob(ctxt, jobName, groupName); - notifySchedulerThread(); - notifySchedulerListenersResumedJob(jobName, groupName); + resources.getJobStore().resumeJob(jobKey); + notifySchedulerThread(0L); + notifySchedulerListenersResumedJob(jobKey); } /** *

* Resume (un-pause) all of the {@link org.quartz.JobDetail}s - * in the given group. + * in the matching groups. *

* *

@@ -1021,39 +1376,42 @@ *

* */ - public void resumeJobGroup(SchedulingContext ctxt, String groupName) - throws SchedulerException { + public void resumeJobs(GroupMatcher matcher) + throws SchedulerException { validateState(); - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; + if(matcher == null) { + matcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP); + } - resources.getJobStore().resumeJobGroup(ctxt, groupName); - notifySchedulerThread(); - notifySchedulerListenersResumedJob(null, groupName); + Collection resumedGroups = resources.getJobStore().resumeJobs(matcher); + notifySchedulerThread(0L); + for (String pausedGroup : resumedGroups) { + notifySchedulerListenersResumedJobs(pausedGroup); + } } /** *

- * Pause all triggers - equivalent of calling pauseTriggerGroup(group) - * on every group. + * Pause all triggers - equivalent of calling pauseTriggers(GroupMatcher) + * with a matcher matching all known groups. *

* *

* When resumeAll() is called (to un-pause), trigger misfire * instructions WILL be applied. *

* - * @see #resumeAll(SchedulingContext) - * @see #pauseTriggerGroup(SchedulingContext, String) - * @see #pause() + * @see #resumeAll() + * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher) + * @see #standby() */ - public void pauseAll(SchedulingContext ctxt) throws SchedulerException { + public void pauseAll() throws SchedulerException { validateState(); - resources.getJobStore().pauseAll(ctxt); - notifySchedulerThread(); - notifySchedulerListenersPausedTrigger(null, null); + resources.getJobStore().pauseAll(); + notifySchedulerThread(0L); + notifySchedulerListenersPausedTriggers(null); } /** @@ -1067,42 +1425,43 @@ * Trigger's misfire instruction will be applied. *

* - * @see #pauseAll(SchedulingContext) + * @see #pauseAll() */ - public void resumeAll(SchedulingContext ctxt) throws SchedulerException { + public void resumeAll() throws SchedulerException { validateState(); - resources.getJobStore().resumeAll(ctxt); - notifySchedulerThread(); - notifySchedulerListenersResumedTrigger(null, null); + resources.getJobStore().resumeAll(); + notifySchedulerThread(0L); + notifySchedulerListenersResumedTrigger(null); } /** *

* Get the names of all known {@link org.quartz.Job} groups. *

*/ - public String[] getJobGroupNames(SchedulingContext ctxt) - throws SchedulerException { + public List getJobGroupNames() + throws SchedulerException { validateState(); - return resources.getJobStore().getJobGroupNames(ctxt); + return resources.getJobStore().getJobGroupNames(); } /** *

* Get the names of all the {@link org.quartz.Job}s in the - * given group. + * matching groups. *

*/ - public String[] getJobNames(SchedulingContext ctxt, String groupName) - throws SchedulerException { + public Set getJobKeys(GroupMatcher matcher) + throws SchedulerException { validateState(); - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; + if(matcher == null) { + matcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP); + } - return resources.getJobStore().getJobNames(ctxt, groupName); + return resources.getJobStore().getJobKeys(matcher); } /** @@ -1111,15 +1470,10 @@ * identified {@link org.quartz.JobDetail}. *

*/ - public Trigger[] getTriggersOfJob(SchedulingContext ctxt, String jobName, - String groupName) throws SchedulerException { + public List getTriggersOfJob(JobKey jobKey) throws SchedulerException { validateState(); - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; - - return resources.getJobStore().getTriggersForJob(ctxt, jobName, - groupName); + return resources.getJobStore().getTriggersForJob(jobKey); } /** @@ -1128,27 +1482,28 @@ * groups. *

*/ - public String[] getTriggerGroupNames(SchedulingContext ctxt) - throws SchedulerException { + public List getTriggerGroupNames() + throws SchedulerException { validateState(); - return resources.getJobStore().getTriggerGroupNames(ctxt); + return resources.getJobStore().getTriggerGroupNames(); } /** *

* Get the names of all the {@link org.quartz.Trigger}s in - * the given group. + * the matching groups. *

*/ - public String[] getTriggerNames(SchedulingContext ctxt, String groupName) - throws SchedulerException { + public Set getTriggerKeys(GroupMatcher matcher) + throws SchedulerException { validateState(); - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; + if(matcher == null) { + matcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP); + } - return resources.getJobStore().getTriggerNames(ctxt, groupName); + return resources.getJobStore().getTriggerKeys(matcher); } /** @@ -1157,14 +1512,10 @@ * instance with the given name and group. *

*/ - public JobDetail getJobDetail(SchedulingContext ctxt, String jobName, - String jobGroup) throws SchedulerException { + public JobDetail getJobDetail(JobKey jobKey) throws SchedulerException { validateState(); - if(jobGroup == null) - jobGroup = Scheduler.DEFAULT_GROUP; - - return resources.getJobStore().retrieveJob(ctxt, jobName, jobGroup); + return resources.getJobStore().retrieveJob(jobKey); } /** @@ -1173,36 +1524,67 @@ * group. *

*/ - public Trigger getTrigger(SchedulingContext ctxt, String triggerName, - String triggerGroup) throws SchedulerException { + public Trigger getTrigger(TriggerKey triggerKey) throws SchedulerException { validateState(); - if(triggerGroup == null) - triggerGroup = Scheduler.DEFAULT_GROUP; + return resources.getJobStore().retrieveTrigger(triggerKey); + } + + /** + * Determine whether a {@link Job} with the given identifier already + * exists within the scheduler. + * + * @param jobKey the identifier to check for + * @return true if a Job exists with the given identifier + * @throws SchedulerException + */ + public boolean checkExists(JobKey jobKey) throws SchedulerException { + validateState(); + + return resources.getJobStore().checkExists(jobKey); - return resources.getJobStore().retrieveTrigger(ctxt, triggerName, - triggerGroup); } + + /** + * Determine whether a {@link Trigger} with the given identifier already + * exists within the scheduler. + * + * @param triggerKey the identifier to check for + * @return true if a Trigger exists with the given identifier + * @throws SchedulerException + */ + public boolean checkExists(TriggerKey triggerKey) throws SchedulerException { + validateState(); + return resources.getJobStore().checkExists(triggerKey); + + } + /** + * Clears (deletes!) all scheduling data - all {@link Job}s, {@link Trigger}s + * {@link Calendar}s. + * + * @throws SchedulerException + */ + public void clear() throws SchedulerException { + validateState(); + + resources.getJobStore().clearAllSchedulingData(); + notifySchedulerListenersUnscheduled(null); + } + + + /** *

* Get the current state of the identified {@link Trigger}. *

- * - * @see Trigger#STATE_NORMAL - * @see Trigger#STATE_PAUSED - * @see Trigger#STATE_COMPLETE - * @see Trigger#STATE_ERROR +J * + * @see TriggerState */ - public int getTriggerState(SchedulingContext ctxt, String triggerName, - String triggerGroup) throws SchedulerException { + public TriggerState getTriggerState(TriggerKey triggerKey) throws SchedulerException { validateState(); - if(triggerGroup == null) - triggerGroup = Scheduler.DEFAULT_GROUP; - - return resources.getJobStore().getTriggerState(ctxt, triggerName, - triggerGroup); + return resources.getJobStore().getTriggerState(triggerKey); } /** @@ -1215,11 +1597,10 @@ * the same name already exists, and replace is * false. */ - public void addCalendar(SchedulingContext ctxt, String calName, - Calendar calendar, boolean replace, boolean updateTriggers) throws SchedulerException { + public void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers) throws SchedulerException { validateState(); - resources.getJobStore().storeCalendar(ctxt, calName, calendar, replace, updateTriggers); + resources.getJobStore().storeCalendar(calName, calendar, replace, updateTriggers); } /** @@ -1231,324 +1612,278 @@ * @throws SchedulerException * if there is an internal Scheduler error. */ - public boolean deleteCalendar(SchedulingContext ctxt, String calName) - throws SchedulerException { + public boolean deleteCalendar(String calName) + throws SchedulerException { validateState(); - return resources.getJobStore().removeCalendar(ctxt, calName); + return resources.getJobStore().removeCalendar(calName); } /** *

* Get the {@link Calendar} instance with the given name. *

*/ - public Calendar getCalendar(SchedulingContext ctxt, String calName) - throws SchedulerException { + public Calendar getCalendar(String calName) + throws SchedulerException { validateState(); - return resources.getJobStore().retrieveCalendar(ctxt, calName); + return resources.getJobStore().retrieveCalendar(calName); } /** *

* Get the names of all registered {@link Calendar}s. *

*/ - public String[] getCalendarNames(SchedulingContext ctxt) - throws SchedulerException { + public List getCalendarNames() + throws SchedulerException { validateState(); - return resources.getJobStore().getCalendarNames(ctxt); + return resources.getJobStore().getCalendarNames(); } + public ListenerManager getListenerManager() { + return listenerManager; + } + /** *

* Add the given {@link org.quartz.JobListener} to the - * Scheduler'sglobal list. + * Scheduler's internal list. *

- * - *

- * Listeners in the 'global' list receive notification of execution events - * for ALL {@link org.quartz.Job}s. - *

*/ - public void addGlobalJobListener(JobListener jobListener) { + public void addInternalJobListener(JobListener jobListener) { if (jobListener.getName() == null - || jobListener.getName().length() == 0) - throw new IllegalArgumentException( - "JobListener name cannot be empty."); - - globalJobListeners.add(jobListener); + || jobListener.getName().length() == 0) { + throw new IllegalArgumentException( + "JobListener name cannot be empty."); + } + + synchronized (internalJobListeners) { + internalJobListeners.put(jobListener.getName(), jobListener); + } } /** *

- * Add the given {@link org.quartz.JobListener} to the - * Scheduler's list, of registered JobListeners. - */ - public void addJobListener(JobListener jobListener) { - if (jobListener.getName() == null - || jobListener.getName().length() == 0) - throw new IllegalArgumentException( - "JobListener name cannot be empty."); - - jobListeners.put(jobListener.getName(), jobListener); - } - - /** - *

- * Remove the given {@link org.quartz.JobListener} from the - * Scheduler's list of global listeners. + * Remove the identified {@link JobListener} from the Scheduler's + * list of internal listeners. *

* - * @return true if the identifed listener was found in the list, and + * @return true if the identified listener was found in the list, and * removed. */ - public boolean removeGlobalJobListener(JobListener jobListener) { - return globalJobListeners.remove(jobListener); + public boolean removeInternalJobListener(String name) { + synchronized (internalJobListeners) { + return (internalJobListeners.remove(name) != null); + } } - + /** *

- * Remove the identifed {@link org.quartz.JobListener} from - * the Scheduler's list of registered listeners. + * Get a List containing all of the {@link org.quartz.JobListener}s + * in the Scheduler's internal list. *

- * - * @return true if the identifed listener was found in the list, and - * removed. */ - public boolean removeJobListener(String name) { - Object o = jobListeners.remove(name); - - if (o != null) return true; - - return false; + public List getInternalJobListeners() { + synchronized (internalJobListeners) { + return java.util.Collections.unmodifiableList(new LinkedList(internalJobListeners.values())); + } } /** *

- * Get a List containing all of the {@link org.quartz.JobListener} - * s in the Scheduler'sglobal list. - *

- */ - public List getGlobalJobListeners() { - return new LinkedList(globalJobListeners); - } - - /** - *

- * Get a Set containing the names of all the non-global{@link org.quartz.JobListener} - * s registered with the Scheduler. - *

- */ - public Set getJobListenerNames() { - return Collections.unmodifiableSet(jobListeners.keySet()); - } - - /** - *

- * Get the non-global{@link org.quartz.JobListener} + * Get the internal {@link org.quartz.JobListener} * that has the given name. *

*/ - public JobListener getJobListener(String name) { - return (JobListener) jobListeners.get(name); + public JobListener getInternalJobListener(String name) { + synchronized (internalJobListeners) { + return internalJobListeners.get(name); + } } - + /** *

* Add the given {@link org.quartz.TriggerListener} to the - * Scheduler'sglobal list. + * Scheduler's internal list. *

- * - *

- * Listeners in the 'global' list receive notification of execution events - * for ALL {@link org.quartz.Trigger}s. - *

*/ - public void addGlobalTriggerListener(TriggerListener triggerListener) { + public void addInternalTriggerListener(TriggerListener triggerListener) { if (triggerListener.getName() == null - || triggerListener.getName().length() == 0) - throw new IllegalArgumentException( - "TriggerListener name cannot be empty."); + || triggerListener.getName().length() == 0) { + throw new IllegalArgumentException( + "TriggerListener name cannot be empty."); + } - globalTriggerListeners.add(triggerListener); + synchronized (internalTriggerListeners) { + internalTriggerListeners.put(triggerListener.getName(), triggerListener); + } } /** *

- * Add the given {@link org.quartz.TriggerListener} to the - * Scheduler's list, of registered TriggerListeners. - */ - public void addTriggerListener(TriggerListener triggerListener) { - if (triggerListener.getName() == null - || triggerListener.getName().length() == 0) - throw new IllegalArgumentException( - "TriggerListener name cannot be empty."); - - triggerListeners.put(triggerListener.getName(), triggerListener); - } - - /** - *

- * Remove the given {@link org.quartz.TriggerListener} from - * the Scheduler's list of global listeners. + * Remove the identified {@link TriggerListener} from the Scheduler's + * list of internal listeners. *

* - * @return true if the identifed listener was found in the list, and + * @return true if the identified listener was found in the list, and * removed. */ - public boolean removeGlobalTriggerListener(TriggerListener triggerListener) { - return globalTriggerListeners.remove(triggerListener); + public boolean removeinternalTriggerListener(String name) { + synchronized (internalTriggerListeners) { + return (internalTriggerListeners.remove(name) != null); + } } /** *

- * Remove the identifed {@link org.quartz.TriggerListener} - * from the Scheduler's list of registered listeners. + * Get a list containing all of the {@link org.quartz.TriggerListener}s + * in the Scheduler's internal list. *

- * - * @return true if the identifed listener was found in the list, and - * removed. */ - public boolean removeTriggerListener(String name) { - Object o = triggerListeners.remove(name); - - if (o != null) return true; - - return false; + public List getInternalTriggerListeners() { + synchronized (internalTriggerListeners) { + return java.util.Collections.unmodifiableList(new LinkedList(internalTriggerListeners.values())); + } } /** *

- * Get a list containing all of the {@link org.quartz.TriggerListener} - * s in the Scheduler'sglobal list. + * Get the internal {@link TriggerListener} that + * has the given name. *

*/ - public List getGlobalTriggerListeners() { - return new LinkedList(globalTriggerListeners); + public TriggerListener getInternalTriggerListener(String name) { + synchronized (internalTriggerListeners) { + return internalTriggerListeners.get(name); + } } /** *

- * Get a Set containing the names of all the non-global{@link org.quartz.TriggerListener} - * s registered with the Scheduler. - *

- */ - public Set getTriggerListenerNames() { - return Collections.unmodifiableSet(triggerListeners.keySet()); - } - - /** - *

- * Get the non-global{@link org.quartz.TriggerListener} - * that has the given name. - *

- */ - public TriggerListener getTriggerListener(String name) { - return (TriggerListener) triggerListeners.get(name); - } - - /** - *

* Register the given {@link SchedulerListener} with the - * Scheduler. + * Scheduler's list of internal listeners. *

*/ - public void addSchedulerListener(SchedulerListener schedulerListener) { - schedulerListeners.add(schedulerListener); + public void addInternalSchedulerListener(SchedulerListener schedulerListener) { + synchronized (internalSchedulerListeners) { + internalSchedulerListeners.add(schedulerListener); + } } /** *

* Remove the given {@link SchedulerListener} from the - * Scheduler. + * Scheduler's list of internal listeners. *

* - * @return true if the identifed listener was found in the list, and + * @return true if the identified listener was found in the list, and * removed. */ - public boolean removeSchedulerListener(SchedulerListener schedulerListener) { - return schedulerListeners.remove(schedulerListener); + public boolean removeInternalSchedulerListener(SchedulerListener schedulerListener) { + synchronized (internalSchedulerListeners) { + return internalSchedulerListeners.remove(schedulerListener); + } } /** *

- * Get a List containing all of the {@link SchedulerListener} - * s registered with the Scheduler. + * Get a List containing all of the internal {@link SchedulerListener}s + * registered with the Scheduler. *

*/ - public List getSchedulerListeners() { - return (List) schedulerListeners.clone(); + public List getInternalSchedulerListeners() { + synchronized (internalSchedulerListeners) { + return java.util.Collections.unmodifiableList(new ArrayList(internalSchedulerListeners)); + } } - protected void notifyJobStoreJobComplete(SchedulingContext ctxt, - Trigger trigger, JobDetail detail, int instCode) - throws JobPersistenceException { - - resources.getJobStore().triggeredJobComplete(ctxt, trigger, detail, - instCode); + protected void notifyJobStoreJobComplete(OperableTrigger trigger, JobDetail detail, CompletedExecutionInstruction instCode) { + resources.getJobStore().triggeredJobComplete(trigger, detail, instCode); } - protected void notifySchedulerThread() { - if (isSignalOnSchedulingChange()) schedThread.signalSchedulingChange(); + protected void notifyJobStoreJobVetoed(OperableTrigger trigger, JobDetail detail, CompletedExecutionInstruction instCode) { + resources.getJobStore().triggeredJobComplete(trigger, detail, instCode); } - private List buildTriggerListenerList(String[] additionalLstnrs) - throws SchedulerException { - List triggerListeners = getGlobalTriggerListeners(); - for (int i = 0; i < additionalLstnrs.length; i++) { - TriggerListener tl = getTriggerListener(additionalLstnrs[i]); - - if (tl != null) triggerListeners.add(tl); - else - throw new SchedulerException("TriggerListener '" - + additionalLstnrs[i] + "' not found.", - SchedulerException.ERR_TRIGGER_LISTENER_NOT_FOUND); + protected void notifySchedulerThread(long candidateNewNextFireTime) { + if (isSignalOnSchedulingChange()) { + signaler.signalSchedulingChange(candidateNewNextFireTime); } + } - return triggerListeners; + private List buildTriggerListenerList() + throws SchedulerException { + List allListeners = new LinkedList(); + allListeners.addAll(getListenerManager().getTriggerListeners()); + allListeners.addAll(getInternalTriggerListeners()); + + return allListeners; } - private List buildJobListenerList(String[] additionalLstnrs) - throws SchedulerException { - List jobListeners = getGlobalJobListeners(); - for (int i = 0; i < additionalLstnrs.length; i++) { - JobListener jl = getJobListener(additionalLstnrs[i]); + private List buildJobListenerList() + throws SchedulerException { + List allListeners = new LinkedList(); + allListeners.addAll(getListenerManager().getJobListeners()); + allListeners.addAll(getInternalJobListeners()); - if (jl != null) jobListeners.add(jl); - else - throw new SchedulerException("JobListener '" - + additionalLstnrs[i] + "' not found.", - SchedulerException.ERR_JOB_LISTENER_NOT_FOUND); + return allListeners; + } + + private List buildSchedulerListenerList() { + List allListeners = new LinkedList(); + allListeners.addAll(getListenerManager().getSchedulerListeners()); + allListeners.addAll(getInternalSchedulerListeners()); + + return allListeners; + } + + private boolean matchJobListener(JobListener listener, JobKey key) { + List> matchers = getListenerManager().getJobListenerMatchers(listener.getName()); + if(matchers == null) + return true; + for(Matcher matcher: matchers) { + if(matcher.isMatch(key)) + return true; } + return false; + } - return jobListeners; + private boolean matchTriggerListener(TriggerListener listener, TriggerKey key) { + List> matchers = getListenerManager().getTriggerListenerMatchers(listener.getName()); + if(matchers == null) + return true; + for(Matcher matcher: matchers) { + if(matcher.isMatch(key)) + return true; + } + return false; } public boolean notifyTriggerListenersFired(JobExecutionContext jec) - throws SchedulerException { - // build a list of all trigger listeners that are to be notified... - List triggerListeners = buildTriggerListenerList(jec.getTrigger() - .getTriggerListenerNames()); + throws SchedulerException { boolean vetoedExecution = false; + // build a list of all trigger listeners that are to be notified... + List triggerListeners = buildTriggerListenerList(); + // notify all trigger listeners in the list - java.util.Iterator itr = triggerListeners.iterator(); - while (itr.hasNext()) { - TriggerListener tl = (TriggerListener) itr.next(); + for(TriggerListener tl: triggerListeners) { try { + if(!matchTriggerListener(tl, jec.getTrigger().getKey())) + continue; tl.triggerFired(jec.getTrigger(), jec); - if(tl.vetoJobExecution(jec.getTrigger(), jec)) + if(tl.vetoJobExecution(jec.getTrigger(), jec)) { vetoedExecution = true; + } } catch (Exception e) { SchedulerException se = new SchedulerException( "TriggerListener '" + tl.getName() + "' threw exception: " + e.getMessage(), e); - se.setErrorCode(SchedulerException.ERR_TRIGGER_LISTENER); throw se; } } @@ -1558,88 +1893,80 @@ public void notifyTriggerListenersMisfired(Trigger trigger) - throws SchedulerException { + throws SchedulerException { // build a list of all trigger listeners that are to be notified... - List triggerListeners = buildTriggerListenerList(trigger - .getTriggerListenerNames()); + List triggerListeners = buildTriggerListenerList(); // notify all trigger listeners in the list - java.util.Iterator itr = triggerListeners.iterator(); - while (itr.hasNext()) { - TriggerListener tl = (TriggerListener) itr.next(); + for(TriggerListener tl: triggerListeners) { try { + if(!matchTriggerListener(tl, trigger.getKey())) + continue; tl.triggerMisfired(trigger); } catch (Exception e) { SchedulerException se = new SchedulerException( "TriggerListener '" + tl.getName() + "' threw exception: " + e.getMessage(), e); - se.setErrorCode(SchedulerException.ERR_TRIGGER_LISTENER); throw se; } } } public void notifyTriggerListenersComplete(JobExecutionContext jec, - int instCode) throws SchedulerException { + CompletedExecutionInstruction instCode) throws SchedulerException { // build a list of all trigger listeners that are to be notified... - List triggerListeners = buildTriggerListenerList(jec.getTrigger() - .getTriggerListenerNames()); + List triggerListeners = buildTriggerListenerList(); // notify all trigger listeners in the list - java.util.Iterator itr = triggerListeners.iterator(); - while (itr.hasNext()) { - TriggerListener tl = (TriggerListener) itr.next(); + for(TriggerListener tl: triggerListeners) { try { + if(!matchTriggerListener(tl, jec.getTrigger().getKey())) + continue; tl.triggerComplete(jec.getTrigger(), jec, instCode); } catch (Exception e) { SchedulerException se = new SchedulerException( "TriggerListener '" + tl.getName() + "' threw exception: " + e.getMessage(), e); - se.setErrorCode(SchedulerException.ERR_TRIGGER_LISTENER); throw se; } } } public void notifyJobListenersToBeExecuted(JobExecutionContext jec) - throws SchedulerException { + throws SchedulerException { // build a list of all job listeners that are to be notified... - List jobListeners = buildJobListenerList(jec.getJobDetail() - .getJobListenerNames()); + List jobListeners = buildJobListenerList(); // notify all job listeners - java.util.Iterator itr = jobListeners.iterator(); - while (itr.hasNext()) { - JobListener jl = (JobListener) itr.next(); + for(JobListener jl: jobListeners) { try { + if(!matchJobListener(jl, jec.getJobDetail().getKey())) + continue; jl.jobToBeExecuted(jec); } catch (Exception e) { SchedulerException se = new SchedulerException( "JobListener '" + jl.getName() + "' threw exception: " + e.getMessage(), e); - se.setErrorCode(SchedulerException.ERR_JOB_LISTENER); throw se; } } } public void notifyJobListenersWasVetoed(JobExecutionContext jec) - throws SchedulerException { + throws SchedulerException { // build a list of all job listeners that are to be notified... - List jobListeners = buildJobListenerList(jec.getJobDetail() - .getJobListenerNames()); + List jobListeners = buildJobListenerList(); // notify all job listeners - java.util.Iterator itr = jobListeners.iterator(); - while (itr.hasNext()) { - JobListener jl = (JobListener) itr.next(); + for(JobListener jl: jobListeners) { try { + if(!matchJobListener(jl, jec.getJobDetail().getKey())) + continue; jl.jobExecutionVetoed(jec); } catch (Exception e) { SchedulerException se = new SchedulerException( "JobListener '" + jl.getName() + "' threw exception: " + e.getMessage(), e); - se.setErrorCode(SchedulerException.ERR_JOB_LISTENER); throw se; } } @@ -1648,33 +1975,29 @@ public void notifyJobListenersWasExecuted(JobExecutionContext jec, JobExecutionException je) throws SchedulerException { // build a list of all job listeners that are to be notified... - List jobListeners = buildJobListenerList(jec.getJobDetail() - .getJobListenerNames()); + List jobListeners = buildJobListenerList(); // notify all job listeners - java.util.Iterator itr = jobListeners.iterator(); - while (itr.hasNext()) { - JobListener jl = (JobListener) itr.next(); + for(JobListener jl: jobListeners) { try { + if(!matchJobListener(jl, jec.getJobDetail().getKey())) + continue; jl.jobWasExecuted(jec, je); } catch (Exception e) { SchedulerException se = new SchedulerException( "JobListener '" + jl.getName() + "' threw exception: " + e.getMessage(), e); - se.setErrorCode(SchedulerException.ERR_JOB_LISTENER); throw se; } } } public void notifySchedulerListenersError(String msg, SchedulerException se) { // build a list of all scheduler listeners that are to be notified... - List schedListeners = getSchedulerListeners(); + List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners - java.util.Iterator itr = schedListeners.iterator(); - while (itr.hasNext()) { - SchedulerListener sl = (SchedulerListener) itr.next(); + for(SchedulerListener sl: schedListeners) { try { sl.schedulerError(msg, se); } catch (Exception e) { @@ -1690,140 +2013,237 @@ public void notifySchedulerListenersSchduled(Trigger trigger) { // build a list of all scheduler listeners that are to be notified... - List schedListeners = getSchedulerListeners(); + List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners - java.util.Iterator itr = schedListeners.iterator(); - while (itr.hasNext()) { - SchedulerListener sl = (SchedulerListener) itr.next(); + for(SchedulerListener sl: schedListeners) { try { sl.jobScheduled(trigger); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of scheduled job." - + " Triger=" + trigger.getFullName(), e); + + " Triger=" + trigger.getKey(), e); } } } - public void notifySchedulerListenersUnschduled(String triggerName, - String triggerGroup) { + public void notifySchedulerListenersUnscheduled(TriggerKey triggerKey) { // build a list of all scheduler listeners that are to be notified... - List schedListeners = getSchedulerListeners(); + List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners - java.util.Iterator itr = schedListeners.iterator(); - while (itr.hasNext()) { - SchedulerListener sl = (SchedulerListener) itr.next(); + for(SchedulerListener sl: schedListeners) { try { - sl.jobUnscheduled(triggerName, triggerGroup); + if(triggerKey == null) + sl.schedulingDataCleared(); + else + sl.jobUnscheduled(triggerKey); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of unscheduled job." - + " Triger=" + triggerGroup + "." - + triggerName, e); + + " Triger=" + (triggerKey == null ? "ALL DATA" : triggerKey), e); } } } public void notifySchedulerListenersFinalized(Trigger trigger) { // build a list of all scheduler listeners that are to be notified... - List schedListeners = getSchedulerListeners(); + List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners - java.util.Iterator itr = schedListeners.iterator(); - while (itr.hasNext()) { - SchedulerListener sl = (SchedulerListener) itr.next(); + for(SchedulerListener sl: schedListeners) { try { sl.triggerFinalized(trigger); } catch (Exception e) { getLog().error( "Error while notifying SchedulerListener of finalized trigger." - + " Triger=" + trigger.getFullName(), e); + + " Triger=" + trigger.getKey(), e); } } } - public void notifySchedulerListenersPausedTrigger(String name, String group) { - // build a list of all job listeners that are to be notified... - List schedListeners = getSchedulerListeners(); + public void notifySchedulerListenersPausedTrigger(TriggerKey triggerKey) { + // build a list of all scheduler listeners that are to be notified... + List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners - java.util.Iterator itr = schedListeners.iterator(); - while (itr.hasNext()) { - SchedulerListener sl = (SchedulerListener) itr.next(); + for(SchedulerListener sl: schedListeners) { try { - sl.triggersPaused(name, group); + sl.triggerPaused(triggerKey); } catch (Exception e) { getLog().error( - "Error while notifying SchedulerListener of paused trigger/group." - + " Triger=" + group + "." + name, e); + "Error while notifying SchedulerListener of paused trigger: " + + triggerKey, e); } } } - public void notifySchedulerListenersResumedTrigger(String name, String group) { - // build a list of all job listeners that are to be notified... - List schedListeners = getSchedulerListeners(); + public void notifySchedulerListenersPausedTriggers(String group) { + // build a list of all scheduler listeners that are to be notified... + List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners - java.util.Iterator itr = schedListeners.iterator(); - while (itr.hasNext()) { - SchedulerListener sl = (SchedulerListener) itr.next(); + for(SchedulerListener sl: schedListeners) { try { - sl.triggersResumed(name, group); + sl.triggersPaused(group); } catch (Exception e) { getLog().error( - "Error while notifying SchedulerListener of resumed trigger/group." - + " Triger=" + group + "." + name, e); + "Error while notifying SchedulerListener of paused trigger group." + + group, e); } } } + + public void notifySchedulerListenersResumedTrigger(TriggerKey key) { + // build a list of all scheduler listeners that are to be notified... + List schedListeners = buildSchedulerListenerList(); - public void notifySchedulerListenersPausedJob(String name, String group) { - // build a list of all job listeners that are to be notified... - List schedListeners = getSchedulerListeners(); + // notify all scheduler listeners + for(SchedulerListener sl: schedListeners) { + try { + sl.triggerResumed(key); + } catch (Exception e) { + getLog().error( + "Error while notifying SchedulerListener of resumed trigger: " + + key, e); + } + } + } + public void notifySchedulerListenersResumedTriggers(String group) { + // build a list of all scheduler listeners that are to be notified... + List schedListeners = buildSchedulerListenerList(); + // notify all scheduler listeners - java.util.Iterator itr = schedListeners.iterator(); - while (itr.hasNext()) { - SchedulerListener sl = (SchedulerListener) itr.next(); + for(SchedulerListener sl: schedListeners) { try { - sl.jobsPaused(name, group); + sl.triggersResumed(group); } catch (Exception e) { getLog().error( - "Error while notifying SchedulerListener of paused job/group." - + " Job=" + group + "." + name, e); + "Error while notifying SchedulerListener of resumed group: " + + group, e); } } } - public void notifySchedulerListenersResumedJob(String name, String group) { - // build a list of all job listeners that are to be notified... - List schedListeners = getSchedulerListeners(); + public void notifySchedulerListenersPausedJob(JobKey key) { + // build a list of all scheduler listeners that are to be notified... + List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners - java.util.Iterator itr = schedListeners.iterator(); - while (itr.hasNext()) { - SchedulerListener sl = (SchedulerListener) itr.next(); + for(SchedulerListener sl: schedListeners) { try { - sl.jobsResumed(name, group); + sl.jobPaused(key); } catch (Exception e) { getLog().error( - "Error while notifying SchedulerListener of resumed job/group." - + " Job=" + group + "." + name, e); + "Error while notifying SchedulerListener of paused job: " + + key, e); } } } + public void notifySchedulerListenersPausedJobs(String group) { + // build a list of all scheduler listeners that are to be notified... + List schedListeners = buildSchedulerListenerList(); + + // notify all scheduler listeners + for(SchedulerListener sl: schedListeners) { + try { + sl.jobsPaused(group); + } catch (Exception e) { + getLog().error( + "Error while notifying SchedulerListener of paused job group: " + + group, e); + } + } + } + + public void notifySchedulerListenersResumedJob(JobKey key) { + // build a list of all scheduler listeners that are to be notified... + List schedListeners = buildSchedulerListenerList(); + + // notify all scheduler listeners + for(SchedulerListener sl: schedListeners) { + try { + sl.jobResumed(key); + } catch (Exception e) { + getLog().error( + "Error while notifying SchedulerListener of resumed job: " + + key, e); + } + } + } + + public void notifySchedulerListenersResumedJobs(String group) { + // build a list of all scheduler listeners that are to be notified... + List schedListeners = buildSchedulerListenerList(); + + // notify all scheduler listeners + for(SchedulerListener sl: schedListeners) { + try { + sl.jobsResumed(group); + } catch (Exception e) { + getLog().error( + "Error while notifying SchedulerListener of resumed job group: " + + group, e); + } + } + } + + public void notifySchedulerListenersInStandbyMode() { + // build a list of all scheduler listeners that are to be notified... + List schedListeners = buildSchedulerListenerList(); + + // notify all scheduler listeners + for(SchedulerListener sl: schedListeners) { + try { + sl.schedulerInStandbyMode(); + } catch (Exception e) { + getLog().error( + "Error while notifying SchedulerListener of inStandByMode.", + e); + } + } + } + + public void notifySchedulerListenersStarted() { + // build a list of all scheduler listeners that are to be notified... + List schedListeners = buildSchedulerListenerList(); + + // notify all scheduler listeners + for(SchedulerListener sl: schedListeners) { + try { + sl.schedulerStarted(); + } catch (Exception e) { + getLog().error( + "Error while notifying SchedulerListener of startup.", + e); + } + } + } + + public void notifySchedulerListenersStarting() { + // build a list of all scheduler listeners that are to be notified... + List schedListeners = buildSchedulerListenerList(); + + // notify all scheduler listeners + for (SchedulerListener sl : schedListeners) { + try { + sl.schedulerStarting(); + } catch (Exception e) { + getLog().error( + "Error while notifying SchedulerListener of startup.", + e); + } + } + } + public void notifySchedulerListenersShutdown() { - // build a list of all job listeners that are to be notified... - List schedListeners = getSchedulerListeners(); + // build a list of all scheduler listeners that are to be notified... + List schedListeners = buildSchedulerListenerList(); // notify all scheduler listeners - java.util.Iterator itr = schedListeners.iterator(); - while (itr.hasNext()) { - SchedulerListener sl = (SchedulerListener) itr.next(); + for(SchedulerListener sl: schedListeners) { try { sl.schedulerShutdown(); } catch (Exception e) { @@ -1833,22 +2253,60 @@ } } } - /** - *

- * Add the given {@link org.quartz.spi.SchedulerPlugin} to - * the Scheduler. This method expects the plugin's - * "initialize" method to be invoked externally (either before or after - * this method is called). - */ - public void addSchedulerPlugin(SchedulerPlugin plugin) { - schedulerPlugins.add(plugin); + + public void notifySchedulerListenersShuttingdown() { + // build a list of all scheduler listeners that are to be notified... + List schedListeners = buildSchedulerListenerList(); + + // notify all scheduler listeners + for(SchedulerListener sl: schedListeners) { + try { + sl.schedulerShuttingdown(); + } catch (Exception e) { + getLog().error( + "Error while notifying SchedulerListener of shutdown.", + e); + } + } } + + public void notifySchedulerListenersJobAdded(JobDetail jobDetail) { + // build a list of all scheduler listeners that are to be notified... + List schedListeners = buildSchedulerListenerList(); + // notify all scheduler listeners + for(SchedulerListener sl: schedListeners) { + try { + sl.jobAdded(jobDetail); + } catch (Exception e) { + getLog().error( + "Error while notifying SchedulerListener of JobAdded.", + e); + } + } + } + public void notifySchedulerListenersJobDeleted(JobKey jobKey) { + // build a list of all scheduler listeners that are to be notified... + List schedListeners = buildSchedulerListenerList(); + + // notify all scheduler listeners + for(SchedulerListener sl: schedListeners) { + try { + sl.jobDeleted(jobKey); + } catch (Exception e) { + getLog().error( + "Error while notifying SchedulerListener of JobAdded.", + e); + } + } + } + public void setJobFactory(JobFactory factory) throws SchedulerException { - if(factory == null) + if(factory == null) { throw new IllegalArgumentException("JobFactory cannot be set to null!"); + } getLog().info("JobFactory set to: " + factory); @@ -1861,61 +2319,91 @@ /** - * Interrupt all instances of the identified InterruptableJob. + * Interrupt all instances of the identified InterruptableJob executing in + * this Scheduler instance. * - * @see org.quartz.core.RemotableQuartzScheduler#interrupt(java.lang.String, java.lang.String) + *

+ * This method is not cluster aware. That is, it will only interrupt + * instances of the identified InterruptableJob currently executing in this + * Scheduler instance, not across the entire cluster. + *

+ * + * @see org.quartz.core.RemotableQuartzScheduler#interrupt(JobKey) */ - public boolean interrupt(SchedulingContext ctxt, String jobName, String groupName) throws UnableToInterruptJobException { + public boolean interrupt(JobKey jobKey) throws UnableToInterruptJobException { - if(groupName == null) - groupName = Scheduler.DEFAULT_GROUP; + List jobs = getCurrentlyExecutingJobs(); - List jobs = getCurrentlyExecutingJobs(); - java.util.Iterator it = jobs.iterator(); - - JobExecutionContext jec = null; JobDetail jobDetail = null; Job job = null; boolean interrupted = false; - while (it.hasNext()) { - jec = (JobExecutionContext)it.next(); + for(JobExecutionContext jec : jobs) { jobDetail = jec.getJobDetail(); - if (jobName.equals(jobDetail.getName()) - && groupName.equals(jobDetail.getGroup())){ + if (jobKey.equals(jobDetail.getKey())) { job = jec.getJobInstance(); if (job instanceof InterruptableJob) { ((InterruptableJob)job).interrupt(); interrupted = true; } else { throw new UnableToInterruptJobException( - "Job '" - + jobName - + "' of group '" - + groupName - + "' can not be interrupted, since it does not implement " - + InterruptableJob.class.getName()); - + "Job " + jobDetail.getKey() + + " can not be interrupted, since it does not implement " + + InterruptableJob.class.getName()); } } } return interrupted; } + + /** + * Interrupt the identified InterruptableJob executing in this Scheduler instance. + * + *

+ * This method is not cluster aware. That is, it will only interrupt + * instances of the identified InterruptableJob currently executing in this + * Scheduler instance, not across the entire cluster. + *

+ * + * @see org.quartz.core.RemotableQuartzScheduler#interrupt(JobKey) + */ + public boolean interrupt(String fireInstanceId) throws UnableToInterruptJobException { + List jobs = getCurrentlyExecutingJobs(); + + Job job = null; + + for(JobExecutionContext jec : jobs) { + if (jec.getFireInstanceId().equals(fireInstanceId)) { + job = jec.getJobInstance(); + if (job instanceof InterruptableJob) { + ((InterruptableJob)job).interrupt(); + return true; + } else { + throw new UnableToInterruptJobException( + "Job " + jec.getJobDetail().getKey() + + " can not be interrupted, since it does not implement " + + InterruptableJob.class.getName()); + } + } + } + + return false; + } private void shutdownPlugins() { - java.util.Iterator itr = schedulerPlugins.iterator(); + java.util.Iterator itr = resources.getSchedulerPlugins().iterator(); while (itr.hasNext()) { - SchedulerPlugin plugin = (SchedulerPlugin) itr.next(); + SchedulerPlugin plugin = itr.next(); plugin.shutdown(); } } private void startPlugins() { - java.util.Iterator itr = schedulerPlugins.iterator(); + java.util.Iterator itr = resources.getSchedulerPlugins().iterator(); while (itr.hasNext()) { - SchedulerPlugin plugin = (SchedulerPlugin) itr.next(); + SchedulerPlugin plugin = itr.next(); plugin.start(); } } @@ -1928,96 +2416,15 @@ // ///////////////////////////////////////////////////////////////////////////// -class ErrorLogger implements SchedulerListener { - - public static Log getLog() { - return LogFactory.getLog(ErrorLogger.class); - } - +class ErrorLogger extends SchedulerListenerSupport { ErrorLogger() { } - - public void jobScheduled(Trigger trigger) { - // do nothing... - } - - public void jobUnscheduled(String triggerName, String triggerGroup) { - // do nothing... - } - - public void triggerFinalized(Trigger trigger) { - // do nothing... - } - - /** - *

- * Called by the {@link Scheduler} when a {@link Trigger} - * or group of {@link Trigger}s has been paused. - *

- * - *

- * If a group was paused, then the triggerName parameter - * will be null. - *

- */ - public void triggersPaused(String triggerName, String triggerGroup) { - // do nothing... - } - - /** - *

- * Called by the {@link Scheduler} when a {@link Trigger} - * or group of {@link Trigger}s has been un-paused. - *

- * - *

- * If a group was resumed, then the triggerName parameter - * will be null. - *

- */ - public void triggersResumed(String triggerName, String triggerGroup) { - // do nothing... - } - - /** - *

- * Called by the {@link Scheduler} when a {@link org.quartz.JobDetail} - * or group of {@link org.quartz.JobDetail}s has been - * paused. - *

- * - *

- * If a group was paused, then the jobName parameter will be - * null. - *

- */ - public void jobsPaused(String jobName, String jobGroup) { - // do nothing... - } - - /** - *

- * Called by the {@link Scheduler} when a {@link org.quartz.JobDetail} - * or group of {@link org.quartz.JobDetail}s has been - * un-paused. - *

- * - *

- * If a group was paused, then the jobName parameter will be - * null. - *

- */ - public void jobsResumed(String jobName, String jobGroup) { - // do nothing... - } - + + @Override public void schedulerError(String msg, SchedulerException cause) { getLog().error(msg, cause); } - public void schedulerShutdown() { - // do nothing... - } } ///////////////////////////////////////////////////////////////////////////// @@ -2027,9 +2434,9 @@ ///////////////////////////////////////////////////////////////////////////// class ExecutingJobsManager implements JobListener { - HashMap executingJobs = new HashMap(); + HashMap executingJobs = new HashMap(); - int numJobsFired = 0; + AtomicInteger numJobsFired = new AtomicInteger(0); ExecutingJobsManager() { } @@ -2045,28 +2452,28 @@ } public void jobToBeExecuted(JobExecutionContext context) { - numJobsFired++; + numJobsFired.incrementAndGet(); synchronized (executingJobs) { executingJobs - .put(context.getTrigger().getFireInstanceId(), context); + .put(((OperableTrigger)context.getTrigger()).getFireInstanceId(), context); } } public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) { synchronized (executingJobs) { - executingJobs.remove(context.getTrigger().getFireInstanceId()); + executingJobs.remove(((OperableTrigger)context.getTrigger()).getFireInstanceId()); } } public int getNumJobsFired() { - return numJobsFired; + return numJobsFired.get(); } - public List getExecutingJobs() { + public List getExecutingJobs() { synchronized (executingJobs) { - return java.util.Collections.unmodifiableList(new ArrayList( + return java.util.Collections.unmodifiableList(new ArrayList( executingJobs.values())); } } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/core/QuartzSchedulerMBeanImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/core/QuartzSchedulerResources.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/core/QuartzSchedulerResources.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/core/QuartzSchedulerResources.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/core/QuartzSchedulerResources.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,12 +16,15 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.core; +import java.util.ArrayList; +import java.util.List; + +import org.quartz.management.ManagementRESTServiceConfiguration; import org.quartz.spi.JobStore; +import org.quartz.spi.SchedulerPlugin; +import org.quartz.spi.ThreadExecutor; import org.quartz.spi.ThreadPool; /** @@ -70,6 +73,31 @@ private JobRunShellFactory jobRunShellFactory; + private List schedulerPlugins = new ArrayList(10); + + private boolean makeSchedulerThreadDaemon = false; + + private boolean threadsInheritInitializersClassLoadContext = false; + + private String rmiBindName; + + private boolean jmxExport; + + private String jmxObjectName; + + private ManagementRESTServiceConfiguration managementRESTServiceConfiguration; + + private ThreadExecutor threadExecutor; + + private boolean runUpdateCheck = true; + + private long batchTimeWindow = 0; + + private int maxBatchSize = 1; + + private boolean interruptJobsOnShutdown = false; + private boolean interruptJobsOnShutdownWithWait = false; + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -113,9 +141,10 @@ * if name is null or empty. */ public void setName(String name) { - if (name == null || name.trim().length() == 0) - throw new IllegalArgumentException( - "Scheduler name cannot be empty."); + if (name == null || name.trim().length() == 0) { + throw new IllegalArgumentException( + "Scheduler name cannot be empty."); + } this.name = name; @@ -143,9 +172,10 @@ * if name is null or empty. */ public void setInstanceId(String instanceId) { - if (instanceId == null || instanceId.trim().length() == 0) - throw new IllegalArgumentException( - "Scheduler instanceId cannot be empty."); + if (instanceId == null || instanceId.trim().length() == 0) { + throw new IllegalArgumentException( + "Scheduler instanceId cannot be empty."); + } this.instanceId = instanceId; } @@ -246,9 +276,10 @@ * if name is null or empty. */ public void setThreadName(String threadName) { - if (threadName == null || threadName.trim().length() == 0) - throw new IllegalArgumentException( - "Scheduler thread name cannot be empty."); + if (threadName == null || threadName.trim().length() == 0) { + throw new IllegalArgumentException( + "Scheduler thread name cannot be empty."); + } this.threadName = threadName; } @@ -264,19 +295,23 @@ */ public void setRMICreateRegistryStrategy(String rmiCreateRegistryStrategy) { if (rmiCreateRegistryStrategy == null - || rmiCreateRegistryStrategy.trim().length() == 0) rmiCreateRegistryStrategy = CREATE_REGISTRY_NEVER; - else if (rmiCreateRegistryStrategy.equalsIgnoreCase("true")) rmiCreateRegistryStrategy = CREATE_REGISTRY_AS_NEEDED; - else if (rmiCreateRegistryStrategy.equalsIgnoreCase("false")) rmiCreateRegistryStrategy = CREATE_REGISTRY_NEVER; - else if (rmiCreateRegistryStrategy - .equalsIgnoreCase(CREATE_REGISTRY_ALWAYS)) rmiCreateRegistryStrategy = CREATE_REGISTRY_ALWAYS; - else if (rmiCreateRegistryStrategy - .equalsIgnoreCase(CREATE_REGISTRY_AS_NEEDED)) rmiCreateRegistryStrategy = CREATE_REGISTRY_AS_NEEDED; - else if (rmiCreateRegistryStrategy - .equalsIgnoreCase(CREATE_REGISTRY_NEVER)) rmiCreateRegistryStrategy = CREATE_REGISTRY_NEVER; - else + || rmiCreateRegistryStrategy.trim().length() == 0) { + rmiCreateRegistryStrategy = CREATE_REGISTRY_NEVER; + } else if (rmiCreateRegistryStrategy.equalsIgnoreCase("true")) { + rmiCreateRegistryStrategy = CREATE_REGISTRY_AS_NEEDED; + } else if (rmiCreateRegistryStrategy.equalsIgnoreCase("false")) { + rmiCreateRegistryStrategy = CREATE_REGISTRY_NEVER; + } else if (rmiCreateRegistryStrategy.equalsIgnoreCase(CREATE_REGISTRY_ALWAYS)) { + rmiCreateRegistryStrategy = CREATE_REGISTRY_ALWAYS; + } else if (rmiCreateRegistryStrategy.equalsIgnoreCase(CREATE_REGISTRY_AS_NEEDED)) { + rmiCreateRegistryStrategy = CREATE_REGISTRY_AS_NEEDED; + } else if (rmiCreateRegistryStrategy.equalsIgnoreCase(CREATE_REGISTRY_NEVER)) { + rmiCreateRegistryStrategy = CREATE_REGISTRY_NEVER; + } else { throw new IllegalArgumentException( "Faild to set RMICreateRegistryStrategy - strategy unknown: '" + rmiCreateRegistryStrategy + "'"); + } this.rmiCreateRegistryStrategy = rmiCreateRegistryStrategy; } @@ -301,8 +336,9 @@ * if threadPool is null. */ public void setThreadPool(ThreadPool threadPool) { - if (threadPool == null) - throw new IllegalArgumentException("ThreadPool cannot be null."); + if (threadPool == null) { + throw new IllegalArgumentException("ThreadPool cannot be null."); + } this.threadPool = threadPool; } @@ -327,8 +363,9 @@ * if jobStore is null. */ public void setJobStore(JobStore jobStore) { - if (jobStore == null) - throw new IllegalArgumentException("JobStore cannot be null."); + if (jobStore == null) { + throw new IllegalArgumentException("JobStore cannot be null."); + } this.jobStore = jobStore; } @@ -353,11 +390,206 @@ * if jobRunShellFactory is null. */ public void setJobRunShellFactory(JobRunShellFactory jobRunShellFactory) { - if (jobRunShellFactory == null) - throw new IllegalArgumentException( - "JobRunShellFactory cannot be null."); + if (jobRunShellFactory == null) { + throw new IllegalArgumentException( + "JobRunShellFactory cannot be null."); + } this.jobRunShellFactory = jobRunShellFactory; } + /** + *

+ * Add the given {@link org.quartz.spi.SchedulerPlugin} for the + * {@link QuartzScheduler} to use. This method expects the plugin's + * "initialize" method to be invoked externally (either before or after + * this method is called). + *

+ */ + public void addSchedulerPlugin(SchedulerPlugin plugin) { + schedulerPlugins.add(plugin); + } + + /** + *

+ * Get the List of all + * {@link org.quartz.spi.SchedulerPlugin}s for the + * {@link QuartzScheduler} to use. + *

+ */ + public List getSchedulerPlugins() { + return schedulerPlugins; + } + + /** + * Get whether to mark the Quartz scheduling thread as daemon. + * + * @see Thread#setDaemon(boolean) + */ + public boolean getMakeSchedulerThreadDaemon() { + return makeSchedulerThreadDaemon; + } + + /** + * Set whether to mark the Quartz scheduling thread as daemon. + * + * @see Thread#setDaemon(boolean) + */ + public void setMakeSchedulerThreadDaemon(boolean makeSchedulerThreadDaemon) { + this.makeSchedulerThreadDaemon = makeSchedulerThreadDaemon; + } + + /** + * Get whether to set the class load context of spawned threads to that + * of the initializing thread. + */ + public boolean isThreadsInheritInitializersClassLoadContext() { + return threadsInheritInitializersClassLoadContext; + } + + /** + * Set whether to set the class load context of spawned threads to that + * of the initializing thread. + */ + public void setThreadsInheritInitializersClassLoadContext( + boolean threadsInheritInitializersClassLoadContext) { + this.threadsInheritInitializersClassLoadContext = threadsInheritInitializersClassLoadContext; + } + + /** + * Get the name under which to bind the QuartzScheduler in RMI. Will + * return the value of the uniqueIdentifier property if explict RMI bind + * name was never set. + * + * @see #getUniqueIdentifier() + */ + public String getRMIBindName() { + return (rmiBindName == null) ? getUniqueIdentifier() : rmiBindName; + } + + /** + * Set the name under which to bind the QuartzScheduler in RMI. If unset, + * defaults to the value of the uniqueIdentifier property. + * + * @see #getUniqueIdentifier() + */ + public void setRMIBindName(String rmiBindName) { + this.rmiBindName = rmiBindName; + } + + /** + * Get whether the QuartzScheduler should be registered with the local + * MBeanServer. + */ + public boolean getJMXExport() { + return jmxExport; + } + + /** + * Set whether the QuartzScheduler should be registered with the local + * MBeanServer. + */ + public void setJMXExport(boolean jmxExport) { + this.jmxExport = jmxExport; + } + + /** + * Get the name under which the QuartzScheduler should be registered with + * the local MBeanServer. If unset, defaults to the value calculated by + * generateJMXObjectName. + * + * @see #generateJMXObjectName(String, String) + */ + public String getJMXObjectName() { + return (jmxObjectName == null) ? generateJMXObjectName(name, instanceId) : jmxObjectName; + } + + /** + * Set the name under which the QuartzScheduler should be registered with + * the local MBeanServer. If unset, defaults to the value calculated by + * generateJMXObjectName. + * + * @see #generateJMXObjectName(String, String) + */ + public void setJMXObjectName(String jmxObjectName) { + this.jmxObjectName = jmxObjectName; + } + + /** + * Get the ThreadExecutor which runs the QuartzSchedulerThread + */ + public ThreadExecutor getThreadExecutor() { + return threadExecutor; + } + + /** + * Set the ThreadExecutor which runs the QuartzSchedulerThread + */ + public void setThreadExecutor(ThreadExecutor threadExecutor) { + this.threadExecutor = threadExecutor; + } + + /** + * Create the name under which this scheduler should be registered in JMX. + *

+ * The name is composed as: + * quartz:type=QuartzScheduler,name=[schedName],instance=[schedInstId] + *

+ */ + public static String generateJMXObjectName(String schedName, String schedInstId) { + return "quartz:type=QuartzScheduler" + ",name=" + + schedName.replaceAll(":|=|\n", ".") + + ",instance=" + schedInstId; + } + + public boolean isRunUpdateCheck() { + return runUpdateCheck; + } + + public void setRunUpdateCheck(boolean runUpdateCheck) { + this.runUpdateCheck = runUpdateCheck; + } + + public long getBatchTimeWindow() { + return batchTimeWindow; + } + + public void setBatchTimeWindow(long batchTimeWindow) { + this.batchTimeWindow = batchTimeWindow; + } + + public int getMaxBatchSize() { + return maxBatchSize; + } + + public void setMaxBatchSize(int maxBatchSize) { + this.maxBatchSize = maxBatchSize; + } + + public boolean isInterruptJobsOnShutdown() { + return interruptJobsOnShutdown; + } + + public void setInterruptJobsOnShutdown(boolean interruptJobsOnShutdown) { + this.interruptJobsOnShutdown = interruptJobsOnShutdown; + } + + public boolean isInterruptJobsOnShutdownWithWait() { + return interruptJobsOnShutdownWithWait; + } + + public void setInterruptJobsOnShutdownWithWait( + boolean interruptJobsOnShutdownWithWait) { + this.interruptJobsOnShutdownWithWait = interruptJobsOnShutdownWithWait; + } + + + public ManagementRESTServiceConfiguration getManagementRESTServiceConfiguration() { + return managementRESTServiceConfiguration; + } + + public void setManagementRESTServiceConfiguration(ManagementRESTServiceConfiguration managementRESTServiceConfiguration) { + this.managementRESTServiceConfiguration = managementRESTServiceConfiguration; + } + } Index: 3rdParty_sources/quartz/org/quartz/core/QuartzSchedulerThread.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/core/QuartzSchedulerThread.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/core/QuartzSchedulerThread.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/core/QuartzSchedulerThread.java 15 Dec 2014 10:09:47 -0000 1.1.2.1 @@ -1,72 +1,71 @@ -/* - * Copyright 2004-2005 OpenSymphony - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations +/* + * Copyright 2001-2009 Terracotta, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations * under the License. - * + * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.core; +import java.util.ArrayList; +import java.util.List; import java.util.Random; +import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.quartz.Job; import org.quartz.JobPersistenceException; import org.quartz.SchedulerException; import org.quartz.Trigger; +import org.quartz.Trigger.CompletedExecutionInstruction; +import org.quartz.spi.OperableTrigger; import org.quartz.spi.TriggerFiredBundle; +import org.quartz.spi.TriggerFiredResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** *

* The thread responsible for performing the work of firing {@link Trigger} * s that are registered with the {@link QuartzScheduler}. *

- * + * * @see QuartzScheduler - * @see Job + * @see org.quartz.Job * @see Trigger - * + * * @author James House */ public class QuartzSchedulerThread extends Thread { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Data members. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ private QuartzScheduler qs; private QuartzSchedulerResources qsRsrcs; - private Object pauseLock = new Object(); + private final Object sigLock = new Object(); - private Object idleLock = new Object(); - private boolean signaled; + private long signaledNextFireTime; private boolean paused; - private boolean halted; + private AtomicBoolean halted; - private SchedulingContext ctxt = null; - private Random random = new Random(System.currentTimeMillis()); // When the scheduler finds there is no current trigger to fire, how long @@ -77,13 +76,13 @@ private int idleWaitVariablness = 7 * 1000; - private long dbFailureRetryInterval = 15L * 1000L; + private final Logger log = LoggerFactory.getLogger(getClass()); /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Constructors. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -94,9 +93,8 @@ * with normal priority. *

*/ - QuartzSchedulerThread(QuartzScheduler qs, QuartzSchedulerResources qsRsrcs, - SchedulingContext ctxt) { - this(qs, qsRsrcs, ctxt, false, Thread.NORM_PRIORITY); + QuartzSchedulerThread(QuartzScheduler qs, QuartzSchedulerResources qsRsrcs) { + this(qs, qsRsrcs, qsRsrcs.getMakeSchedulerThreadDaemon(), Thread.NORM_PRIORITY); } /** @@ -106,28 +104,30 @@ * attributes. *

*/ - QuartzSchedulerThread(QuartzScheduler qs, QuartzSchedulerResources qsRsrcs, - SchedulingContext ctxt, boolean setDaemon, int threadPrio) { + QuartzSchedulerThread(QuartzScheduler qs, QuartzSchedulerResources qsRsrcs, boolean setDaemon, int threadPrio) { super(qs.getSchedulerThreadGroup(), qsRsrcs.getThreadName()); this.qs = qs; this.qsRsrcs = qsRsrcs; - this.ctxt = ctxt; this.setDaemon(setDaemon); + if(qsRsrcs.isThreadsInheritInitializersClassLoadContext()) { + log.info("QuartzSchedulerThread Inheriting ContextClassLoader of thread: " + Thread.currentThread().getName()); + this.setContextClassLoader(Thread.currentThread().getContextClassLoader()); + } + this.setPriority(threadPrio); // start the underlying thread, but put this object into the 'paused' // state // so processing doesn't start yet... paused = true; - halted = false; - this.start(); + halted = new AtomicBoolean(false); } /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Interface. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -136,14 +136,6 @@ idleWaitVariablness = (int) (waitTime * 0.2); } - private long getDbFailureRetryInterval() { - return dbFailureRetryInterval; - } - - public void setDbFailureRetryInterval(long dbFailureRetryInterval) { - this.dbFailureRetryInterval = dbFailureRetryInterval; - } - private long getRandomizedIdleWaitTime() { return idleWaitTime - random.nextInt(idleWaitVariablness); } @@ -154,13 +146,13 @@ *

*/ void togglePause(boolean pause) { - synchronized (pauseLock) { + synchronized (sigLock) { paused = pause; if (paused) { - signalSchedulingChange(); + signalSchedulingChange(0); } else { - pauseLock.notify(); + sigLock.notifyAll(); } } } @@ -170,16 +162,34 @@ * Signals the main processing loop to pause at the next possible point. *

*/ - void halt() { - synchronized (pauseLock) { - halted = true; + void halt(boolean wait) { + synchronized (sigLock) { + halted.set(true); if (paused) { - pauseLock.notify(); + sigLock.notifyAll(); } else { - signalSchedulingChange(); + signalSchedulingChange(0); } } + + if (wait) { + boolean interrupted = false; + try { + while (true) { + try { + join(); + break; + } catch (InterruptedException _) { + interrupted = true; + } + } + } finally { + if (interrupted) { + Thread.currentThread().interrupt(); + } + } + } } boolean isPaused() { @@ -192,287 +202,290 @@ * made - in order to interrupt any sleeping that may be occuring while * waiting for the fire time to arrive. *

+ * + * @param candidateNewNextFireTime the time (in millis) when the newly scheduled trigger + * will fire. If this method is being called do to some other even (rather + * than scheduling a trigger), the caller should pass zero (0). */ - void signalSchedulingChange() { - signaled = true; + public void signalSchedulingChange(long candidateNewNextFireTime) { + synchronized(sigLock) { + signaled = true; + signaledNextFireTime = candidateNewNextFireTime; + sigLock.notifyAll(); + } } + public void clearSignaledSchedulingChange() { + synchronized(sigLock) { + signaled = false; + signaledNextFireTime = 0; + } + } + + public boolean isScheduleChanged() { + synchronized(sigLock) { + return signaled; + } + } + + public long getSignaledNextFireTime() { + synchronized(sigLock) { + return signaledNextFireTime; + } + } + /** *

* The main processing loop of the QuartzSchedulerThread. *

*/ + @Override public void run() { boolean lastAcquireFailed = false; - - while (!halted) { - - signaled = false; - - try { - // check if we're supposed to pause... - synchronized (pauseLock) { - while (paused && !halted) { - try { - // wait until togglePause(false) is called... - pauseLock.wait(100L); - } catch (InterruptedException ignore) { + + while (!halted.get()) { + try { + // check if we're supposed to pause... + synchronized (sigLock) { + while (paused && !halted.get()) { + try { + // wait until togglePause(false) is called... + sigLock.wait(1000L); + } catch (InterruptedException ignore) { + } } - } - if (halted) { - break; + if (halted.get()) { + break; + } } - } - Trigger trigger = null; + int availThreadCount = qsRsrcs.getThreadPool().blockForAvailableThreads(); + if(availThreadCount > 0) { // will always be true, due to semantics of blockForAvailableThreads... - long now = System.currentTimeMillis(); + List triggers = null; - try { - trigger = qsRsrcs.getJobStore().acquireNextTrigger( - ctxt, now + idleWaitTime); - lastAcquireFailed = false; - } catch (JobPersistenceException jpe) { - if(!lastAcquireFailed) - qs.notifySchedulerListenersError( - "An error occured while scanning for the next trigger to fire.", - jpe); - lastAcquireFailed = true; - } - catch (RuntimeException e) { - if(!lastAcquireFailed) - getLog().error("quartzSchedulerThreadLoop: RuntimeException " - +e.getMessage(), e); - lastAcquireFailed = true; - } + long now = System.currentTimeMillis(); - if (trigger != null) { - - now = System.currentTimeMillis(); - long triggerTime = trigger.getNextFireTime().getTime(); - long timeUntilTrigger = triggerTime - now; - long spinInterval = 10; - - // this looping may seem a bit silly, but it's the - // current work-around - // for a dead-lock that can occur if the Thread.sleep() - // is replaced with - // a obj.wait() that gets notified when the signal is - // set... - // so to be able to detect the signal change without - // sleeping the entire - // timeUntilTrigger, we spin here... don't worry - // though, this spinning - // doesn't even register 0.2% cpu usage on a pentium 4. - int numPauses = (int) (timeUntilTrigger / spinInterval); - while (numPauses >= 0 && !signaled) { - + clearSignaledSchedulingChange(); try { - Thread.sleep(spinInterval); - } catch (InterruptedException ignore) { - } - - now = System.currentTimeMillis(); - timeUntilTrigger = triggerTime - now; - numPauses = (int) (timeUntilTrigger / spinInterval); - } - if (signaled) { - try { - qsRsrcs.getJobStore().releaseAcquiredTrigger( - ctxt, trigger); + triggers = qsRsrcs.getJobStore().acquireNextTriggers( + now + idleWaitTime, Math.min(availThreadCount, qsRsrcs.getMaxBatchSize()), qsRsrcs.getBatchTimeWindow()); + lastAcquireFailed = false; + if (log.isDebugEnabled()) + log.debug("batch acquisition of " + (triggers == null ? 0 : triggers.size()) + " triggers"); } catch (JobPersistenceException jpe) { - qs.notifySchedulerListenersError( - "An error occured while releasing trigger '" - + trigger.getFullName() + "'", + if(!lastAcquireFailed) { + qs.notifySchedulerListenersError( + "An error occurred while scanning for the next triggers to fire.", jpe); - // db connection must have failed... keep - // retrying until it's up... - releaseTriggerRetryLoop(trigger); + } + lastAcquireFailed = true; + continue; } catch (RuntimeException e) { - getLog().error( - "releaseTriggerRetryLoop: RuntimeException " - +e.getMessage(), e); - // db connection must have failed... keep - // retrying until it's up... - releaseTriggerRetryLoop(trigger); + if(!lastAcquireFailed) { + getLog().error("quartzSchedulerThreadLoop: RuntimeException " + +e.getMessage(), e); + } + lastAcquireFailed = true; + continue; } - signaled = false; - continue; - } - // set trigger to 'executing' - TriggerFiredBundle bndle = null; + if (triggers != null && !triggers.isEmpty()) { - try { - bndle = qsRsrcs.getJobStore().triggerFired(ctxt, - trigger); - } catch (SchedulerException se) { - qs.notifySchedulerListenersError( - "An error occured while firing trigger '" - + trigger.getFullName() + "'", se); - } catch (RuntimeException e) { - getLog().error( - "RuntimeException while firing trigger " + - trigger.getFullName(), e); - // db connection must have failed... keep - // retrying until it's up... - releaseTriggerRetryLoop(trigger); - } + now = System.currentTimeMillis(); + long triggerTime = triggers.get(0).getNextFireTime().getTime(); + long timeUntilTrigger = triggerTime - now; + while(timeUntilTrigger > 2) { + synchronized (sigLock) { + if (halted.get()) { + break; + } + if (!isCandidateNewTimeEarlierWithinReason(triggerTime, false)) { + try { + // we could have blocked a long while + // on 'synchronize', so we must recompute + now = System.currentTimeMillis(); + timeUntilTrigger = triggerTime - now; + if(timeUntilTrigger >= 1) + sigLock.wait(timeUntilTrigger); + } catch (InterruptedException ignore) { + } + } + } + if(releaseIfScheduleChangedSignificantly(triggers, triggerTime)) { + break; + } + now = System.currentTimeMillis(); + timeUntilTrigger = triggerTime - now; + } - // it's possible to get 'null' if the trigger was paused, - // blocked, or other similar occurances that prevent it being - // fired at this time... - if (bndle == null) { - try { - qsRsrcs.getJobStore().releaseAcquiredTrigger(ctxt, - trigger); - } catch (SchedulerException se) { - qs.notifySchedulerListenersError( - "An error occured while releasing trigger '" - + trigger.getFullName() + "'", se); - // db connection must have failed... keep retrying - // until it's up... - releaseTriggerRetryLoop(trigger); - } - continue; - } + // this happens if releaseIfScheduleChangedSignificantly decided to release triggers + if(triggers.isEmpty()) + continue; - // TODO: improvements: - // - // 1- get thread from pool before firing trigger. - // 2- make sure we can get a job runshell first as well, or - // don't let that throw an exception (right now it never does, - // bugthe signature says it can). - // 3- acquire more triggers at a time (based on num threads?) - - - JobRunShell shell = null; - try { - shell = qsRsrcs.getJobRunShellFactory().borrowJobRunShell(); - shell.initialize(qs, bndle); - } catch (SchedulerException se) { - try { - qsRsrcs.getJobStore().triggeredJobComplete(ctxt, - trigger, bndle.getJobDetail(), Trigger.INSTRUCTION_SET_ALL_JOB_TRIGGERS_ERROR); - } catch (SchedulerException se2) { - qs.notifySchedulerListenersError( - "An error occured while releasing trigger '" - + trigger.getFullName() + "'", se2); - // db connection must have failed... keep retrying - // until it's up... - errorTriggerRetryLoop(bndle); - } - continue; - } + // set triggers to 'executing' + List bndles = new ArrayList(); - qsRsrcs.getThreadPool().runInThread(shell); + boolean goAhead = true; + synchronized(sigLock) { + goAhead = !halted.get(); + } + if(goAhead) { + try { + List res = qsRsrcs.getJobStore().triggersFired(triggers); + if(res != null) + bndles = res; + } catch (SchedulerException se) { + qs.notifySchedulerListenersError( + "An error occurred while firing triggers '" + + triggers + "'", se); + //QTZ-179 : a problem occurred interacting with the triggers from the db + //we release them and loop again + for (int i = 0; i < triggers.size(); i++) { + qsRsrcs.getJobStore().releaseAcquiredTrigger(triggers.get(i)); + } + continue; + } - continue; - } + } - // this looping may seem a bit silly, but it's the current - // work-around - // for a dead-lock that can occur if the Thread.sleep() is replaced - // with - // a obj.wait() that gets notified when the signal is set... - // so to be able to detect the signal change without sleeping the - // entier - // getRandomizedIdleWaitTime(), we spin here... don't worry though, - // the - // CPU usage of this spinning can't even be measured on a pentium - // 4. - now = System.currentTimeMillis(); - long waitTime = now + getRandomizedIdleWaitTime(); - long timeUntilContinue = waitTime - now; - long spinInterval = 10; - int numPauses = (int) (timeUntilContinue / spinInterval); + for (int i = 0; i < bndles.size(); i++) { + TriggerFiredResult result = bndles.get(i); + TriggerFiredBundle bndle = result.getTriggerFiredBundle(); + Exception exception = result.getException(); - while (numPauses > 0 && !signaled) { + if (exception instanceof RuntimeException) { + getLog().error("RuntimeException while firing trigger " + triggers.get(i), exception); + qsRsrcs.getJobStore().releaseAcquiredTrigger(triggers.get(i)); + continue; + } - try { - Thread.sleep(10L); - } catch (InterruptedException ignore) { + // it's possible to get 'null' if the triggers was paused, + // blocked, or other similar occurrences that prevent it being + // fired at this time... or if the scheduler was shutdown (halted) + if (bndle == null) { + qsRsrcs.getJobStore().releaseAcquiredTrigger(triggers.get(i)); + continue; + } + + JobRunShell shell = null; + try { + shell = qsRsrcs.getJobRunShellFactory().createJobRunShell(bndle); + shell.initialize(qs); + } catch (SchedulerException se) { + qsRsrcs.getJobStore().triggeredJobComplete(triggers.get(i), bndle.getJobDetail(), CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_ERROR); + continue; + } + + if (qsRsrcs.getThreadPool().runInThread(shell) == false) { + // this case should never happen, as it is indicative of the + // scheduler being shutdown or a bug in the thread pool or + // a thread pool being used concurrently - which the docs + // say not to do... + getLog().error("ThreadPool.runInThread() return false!"); + qsRsrcs.getJobStore().triggeredJobComplete(triggers.get(i), bndle.getJobDetail(), CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_ERROR); + } + + } + + continue; // while (!halted) + } + } else { // if(availThreadCount > 0) + // should never happen, if threadPool.blockForAvailableThreads() follows contract + continue; // while (!halted) } - now = System.currentTimeMillis(); - timeUntilContinue = waitTime - now; - numPauses = (int) (timeUntilContinue / spinInterval); + long now = System.currentTimeMillis(); + long waitTime = now + getRandomizedIdleWaitTime(); + long timeUntilContinue = waitTime - now; + synchronized(sigLock) { + try { + if(!halted.get()) { + // QTZ-336 A job might have been completed in the mean time and we might have + // missed the scheduled changed signal by not waiting for the notify() yet + // Check that before waiting for too long in case this very job needs to be + // scheduled very soon + if (!isScheduleChanged()) { + sigLock.wait(timeUntilContinue); + } + } + } catch (InterruptedException ignore) { + } + } + + } catch(RuntimeException re) { + getLog().error("Runtime error occurred in main trigger firing loop.", re); } - } - catch(RuntimeException re) { - getLog().error("Runtime error occured in main trigger firing loop.", re); - } - } // loop... + } // while (!halted) // drop references to scheduler stuff to aid garbage collection... qs = null; qsRsrcs = null; } - public void errorTriggerRetryLoop(TriggerFiredBundle bndle) { - int retryCount = 0; - try { - while (!halted) { - try { - Thread.sleep(getDbFailureRetryInterval()); // retry every N - // seconds (the db - // connection must - // be failed) - retryCount++; - qsRsrcs.getJobStore().triggeredJobComplete(ctxt, - bndle.getTrigger(), bndle.getJobDetail(), Trigger.INSTRUCTION_SET_ALL_JOB_TRIGGERS_ERROR); - retryCount = 0; - break; - } catch (JobPersistenceException jpe) { - if(retryCount % 4 == 0) - qs.notifySchedulerListenersError( - "An error occured while releasing trigger '" - + bndle.getTrigger().getFullName() + "'", jpe); - } catch (RuntimeException e) { - getLog().error("releaseTriggerRetryLoop: RuntimeException "+e.getMessage(), e); - } catch (InterruptedException e) { - getLog().error("releaseTriggerRetryLoop: InterruptedException "+e.getMessage(), e); - } + private boolean releaseIfScheduleChangedSignificantly( + List triggers, long triggerTime) { + if (isCandidateNewTimeEarlierWithinReason(triggerTime, true)) { + // above call does a clearSignaledSchedulingChange() + for (OperableTrigger trigger : triggers) { + qsRsrcs.getJobStore().releaseAcquiredTrigger(trigger); } - } finally { - if(retryCount == 0) - getLog().info("releaseTriggerRetryLoop: connection restored."); + triggers.clear(); + return true; } + return false; } - - public void releaseTriggerRetryLoop(Trigger trigger) { - int retryCount = 0; - try { - while (!halted) { - try { - Thread.sleep(getDbFailureRetryInterval()); // retry every N - // seconds (the db - // connection must - // be failed) - retryCount++; - qsRsrcs.getJobStore().releaseAcquiredTrigger(ctxt, trigger); - retryCount = 0; - break; - } catch (JobPersistenceException jpe) { - if(retryCount % 4 == 0) - qs.notifySchedulerListenersError( - "An error occured while releasing trigger '" - + trigger.getFullName() + "'", jpe); - } catch (RuntimeException e) { - getLog().error("releaseTriggerRetryLoop: RuntimeException "+e.getMessage(), e); - } catch (InterruptedException e) { - getLog().error("releaseTriggerRetryLoop: InterruptedException "+e.getMessage(), e); - } + + private boolean isCandidateNewTimeEarlierWithinReason(long oldTime, boolean clearSignal) { + + // So here's the deal: We know due to being signaled that 'the schedule' + // has changed. We may know (if getSignaledNextFireTime() != 0) the + // new earliest fire time. We may not (in which case we will assume + // that the new time is earlier than the trigger we have acquired). + // In either case, we only want to abandon our acquired trigger and + // go looking for a new one if "it's worth it". It's only worth it if + // the time cost incurred to abandon the trigger and acquire a new one + // is less than the time until the currently acquired trigger will fire, + // otherwise we're just "thrashing" the job store (e.g. database). + // + // So the question becomes when is it "worth it"? This will depend on + // the job store implementation (and of course the particular database + // or whatever behind it). Ideally we would depend on the job store + // implementation to tell us the amount of time in which it "thinks" + // it can abandon the acquired trigger and acquire a new one. However + // we have no current facility for having it tell us that, so we make + // a somewhat educated but arbitrary guess ;-). + + synchronized(sigLock) { + + if (!isScheduleChanged()) + return false; + + boolean earlier = false; + + if(getSignaledNextFireTime() == 0) + earlier = true; + else if(getSignaledNextFireTime() < oldTime ) + earlier = true; + + if(earlier) { + // so the new time is considered earlier, but is it enough earlier? + long diff = oldTime - System.currentTimeMillis(); + if(diff < (qsRsrcs.getJobStore().supportsPersistence() ? 70L : 7L)) + earlier = false; } - } finally { - if(retryCount == 0) - getLog().info("releaseTriggerRetryLoop: connection restored."); + + if(clearSignal) { + clearSignaledSchedulingChange(); + } + + return earlier; } } - - public static Log getLog() { - return LogFactory.getLog(QuartzSchedulerThread.class); + + public Logger getLog() { + return log; } } // end of QuartzSchedulerThread Index: 3rdParty_sources/quartz/org/quartz/core/RemotableQuartzScheduler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/core/RemotableQuartzScheduler.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/core/RemotableQuartzScheduler.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/core/RemotableQuartzScheduler.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,27 +16,28 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.core; import java.rmi.Remote; import java.rmi.RemoteException; import java.util.Date; import java.util.List; +import java.util.Map; import java.util.Set; import org.quartz.Calendar; import org.quartz.JobDataMap; import org.quartz.JobDetail; -import org.quartz.JobListener; +import org.quartz.JobExecutionContext; +import org.quartz.JobKey; import org.quartz.SchedulerContext; import org.quartz.SchedulerException; -import org.quartz.SchedulerListener; import org.quartz.Trigger; -import org.quartz.TriggerListener; +import org.quartz.TriggerKey; import org.quartz.UnableToInterruptJobException; +import org.quartz.Trigger.TriggerState; +import org.quartz.impl.matchers.GroupMatcher; +import org.quartz.spi.OperableTrigger; /** * @author James House @@ -51,181 +52,124 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - public String getSchedulerName() throws RemoteException; + String getSchedulerName() throws RemoteException; - public String getSchedulerInstanceId() throws RemoteException; + String getSchedulerInstanceId() throws RemoteException; - public SchedulerContext getSchedulerContext() throws SchedulerException, - RemoteException; + SchedulerContext getSchedulerContext() throws SchedulerException, RemoteException; - public void start() throws SchedulerException, RemoteException; + void start() throws SchedulerException, RemoteException; - public void standby() throws RemoteException; + void startDelayed(int seconds) throws SchedulerException, RemoteException; + + void standby() throws RemoteException; - public boolean isInStandbyMode() throws RemoteException; + boolean isInStandbyMode() throws RemoteException; - public void shutdown() throws RemoteException; + void shutdown() throws RemoteException; - public void shutdown(boolean waitForJobsToComplete) throws RemoteException; + void shutdown(boolean waitForJobsToComplete) throws RemoteException; - public boolean isShutdown() throws RemoteException; + boolean isShutdown() throws RemoteException; - public Date runningSince() throws RemoteException; + Date runningSince() throws RemoteException; - public String getVersion() throws RemoteException; + String getVersion() throws RemoteException; - public int numJobsExecuted() throws RemoteException; + int numJobsExecuted() throws RemoteException; - public Class getJobStoreClass() throws RemoteException; + Class getJobStoreClass() throws RemoteException; - public boolean supportsPersistence() throws RemoteException; + boolean supportsPersistence() throws RemoteException; - public Class getThreadPoolClass() throws RemoteException; + boolean isClustered() throws RemoteException; - public int getThreadPoolSize() throws RemoteException; + Class getThreadPoolClass() throws RemoteException; - public List getCurrentlyExecutingJobs() throws SchedulerException, - RemoteException; + int getThreadPoolSize() throws RemoteException; - public Date scheduleJob(SchedulingContext ctxt, JobDetail jobDetail, - Trigger trigger) throws SchedulerException, RemoteException; - - public Date scheduleJob(SchedulingContext ctxt, Trigger trigger) - throws SchedulerException, RemoteException; - - public void addJob(SchedulingContext ctxt, JobDetail jobDetail, - boolean replace) throws SchedulerException, RemoteException; - - public boolean deleteJob(SchedulingContext ctxt, String jobName, - String groupName) throws SchedulerException, RemoteException; - - public boolean unscheduleJob(SchedulingContext ctxt, String triggerName, - String groupName) throws SchedulerException, RemoteException; - - public Date rescheduleJob(SchedulingContext ctxt, String triggerName, - String groupName, Trigger newTrigger) throws SchedulerException, RemoteException; - + void clear() throws SchedulerException, RemoteException; - public void triggerJob(SchedulingContext ctxt, String jobName, - String groupName, JobDataMap data) throws SchedulerException, RemoteException; + List getCurrentlyExecutingJobs() throws SchedulerException, RemoteException; - public void triggerJobWithVolatileTrigger(SchedulingContext ctxt, - String jobName, String groupName, JobDataMap data) throws SchedulerException, - RemoteException; + Date scheduleJob(JobDetail jobDetail, Trigger trigger) throws SchedulerException, RemoteException; - public void pauseTrigger(SchedulingContext ctxt, String triggerName, - String groupName) throws SchedulerException, RemoteException; + Date scheduleJob(Trigger trigger) throws SchedulerException, RemoteException; - public void pauseTriggerGroup(SchedulingContext ctxt, String groupName) - throws SchedulerException, RemoteException; + void addJob(JobDetail jobDetail, boolean replace) throws SchedulerException, RemoteException; - public void pauseJob(SchedulingContext ctxt, String jobName, - String groupName) throws SchedulerException, RemoteException; + void addJob(JobDetail jobDetail, boolean replace, boolean storeNonDurableWhileAwaitingScheduling) throws SchedulerException, RemoteException; - public void pauseJobGroup(SchedulingContext ctxt, String groupName) - throws SchedulerException, RemoteException; + boolean deleteJob(JobKey jobKey) throws SchedulerException, RemoteException; - public void resumeTrigger(SchedulingContext ctxt, String triggerName, - String groupName) throws SchedulerException, RemoteException; + boolean unscheduleJob(TriggerKey triggerKey) throws SchedulerException, RemoteException; - public void resumeTriggerGroup(SchedulingContext ctxt, String groupName) - throws SchedulerException, RemoteException; + Date rescheduleJob(TriggerKey triggerKey, Trigger newTrigger) throws SchedulerException, RemoteException; + + void triggerJob(JobKey jobKey, JobDataMap data) throws SchedulerException, RemoteException; - public Set getPausedTriggerGroups(SchedulingContext ctxt) - throws SchedulerException, RemoteException; + void triggerJob(OperableTrigger trig) throws SchedulerException, RemoteException; - public void resumeJob(SchedulingContext ctxt, String jobName, - String groupName) throws SchedulerException, RemoteException; + void pauseTrigger(TriggerKey triggerKey) throws SchedulerException, RemoteException; - public void resumeJobGroup(SchedulingContext ctxt, String groupName) - throws SchedulerException, RemoteException; + void pauseTriggers(GroupMatcher matcher) throws SchedulerException, RemoteException; - public void pauseAll(SchedulingContext ctxt) throws SchedulerException, - RemoteException; + void pauseJob(JobKey jobKey) throws SchedulerException, RemoteException; - public void resumeAll(SchedulingContext ctxt) throws SchedulerException, - RemoteException; + void pauseJobs(GroupMatcher matcher) throws SchedulerException, RemoteException; - public String[] getJobGroupNames(SchedulingContext ctxt) - throws SchedulerException, RemoteException; + void resumeTrigger(TriggerKey triggerKey) throws SchedulerException, RemoteException; - public String[] getJobNames(SchedulingContext ctxt, String groupName) - throws SchedulerException, RemoteException; + void resumeTriggers(GroupMatcher matcher) throws SchedulerException, RemoteException; - public Trigger[] getTriggersOfJob(SchedulingContext ctxt, String jobName, - String groupName) throws SchedulerException, RemoteException; + Set getPausedTriggerGroups() throws SchedulerException, RemoteException; + + void resumeJob(JobKey jobKey) throws SchedulerException, RemoteException; - public String[] getTriggerGroupNames(SchedulingContext ctxt) - throws SchedulerException, RemoteException; + void resumeJobs(GroupMatcher matcher) throws SchedulerException, RemoteException; - public String[] getTriggerNames(SchedulingContext ctxt, String groupName) - throws SchedulerException, RemoteException; + void pauseAll() throws SchedulerException, RemoteException; - public JobDetail getJobDetail(SchedulingContext ctxt, String jobName, - String jobGroup) throws SchedulerException, RemoteException; + void resumeAll() throws SchedulerException, RemoteException; - public Trigger getTrigger(SchedulingContext ctxt, String triggerName, - String triggerGroup) throws SchedulerException, RemoteException; + List getJobGroupNames() throws SchedulerException, RemoteException; - public int getTriggerState(SchedulingContext ctxt, String triggerName, - String triggerGroup) throws SchedulerException, RemoteException; + Set getJobKeys(GroupMatcher matcher) throws SchedulerException, RemoteException; - public void addCalendar(SchedulingContext ctxt, String calName, - Calendar calendar, boolean replace, boolean updateTriggers) throws SchedulerException, - RemoteException; + List getTriggersOfJob(JobKey jobKey) throws SchedulerException, RemoteException; - public boolean deleteCalendar(SchedulingContext ctxt, String calName) - throws SchedulerException, RemoteException; + List getTriggerGroupNames() throws SchedulerException, RemoteException; - public Calendar getCalendar(SchedulingContext ctxt, String calName) - throws SchedulerException, RemoteException; + Set getTriggerKeys(GroupMatcher matcher) throws SchedulerException, RemoteException; - public String[] getCalendarNames(SchedulingContext ctxt) - throws SchedulerException, RemoteException; + JobDetail getJobDetail(JobKey jobKey) throws SchedulerException, RemoteException; - public void addGlobalJobListener(JobListener jobListener) - throws RemoteException; + Trigger getTrigger(TriggerKey triggerKey) throws SchedulerException, RemoteException; - public void addJobListener(JobListener jobListener) throws RemoteException; + TriggerState getTriggerState(TriggerKey triggerKey) throws SchedulerException, RemoteException; - public boolean removeGlobalJobListener(JobListener jobListener) - throws RemoteException; + void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers) throws SchedulerException, RemoteException; - public boolean removeJobListener(String name) throws RemoteException; + boolean deleteCalendar(String calName) throws SchedulerException, RemoteException; - public List getGlobalJobListeners() throws RemoteException; + Calendar getCalendar(String calName) throws SchedulerException, RemoteException; - public Set getJobListenerNames() throws RemoteException; + List getCalendarNames() throws SchedulerException, RemoteException; - public JobListener getJobListener(String name) throws RemoteException; + boolean interrupt(JobKey jobKey) throws UnableToInterruptJobException,RemoteException; - public void addGlobalTriggerListener(TriggerListener triggerListener) - throws RemoteException; + boolean interrupt(String fireInstanceId) throws UnableToInterruptJobException,RemoteException; + + boolean checkExists(JobKey jobKey) throws SchedulerException,RemoteException; + + boolean checkExists(TriggerKey triggerKey) throws SchedulerException,RemoteException; + + public boolean deleteJobs(List jobKeys) throws SchedulerException,RemoteException; - public void addTriggerListener(TriggerListener triggerListener) - throws RemoteException; + public void scheduleJobs(Map> triggersAndJobs, boolean replace) throws SchedulerException,RemoteException; - public boolean removeGlobalTriggerListener(TriggerListener triggerListener) - throws RemoteException; + public void scheduleJob(JobDetail jobDetail, Set triggersForJob, boolean replace) throws SchedulerException,RemoteException; - public boolean removeTriggerListener(String name) throws RemoteException; - - public List getGlobalTriggerListeners() throws RemoteException; - - public Set getTriggerListenerNames() throws RemoteException; - - public TriggerListener getTriggerListener(String name) - throws RemoteException; - - public void addSchedulerListener(SchedulerListener schedulerListener) - throws RemoteException; - - public boolean removeSchedulerListener(SchedulerListener schedulerListener) - throws RemoteException; - - public List getSchedulerListeners() throws RemoteException; - - public boolean interrupt(SchedulingContext ctxt, String jobName, String groupName) throws UnableToInterruptJobException,RemoteException ; - - + public boolean unscheduleJobs(List triggerKeys) throws SchedulerException,RemoteException; + } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/core/SampledStatistics.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/core/SampledStatisticsImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/core/SchedulerSignalerImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/core/SchedulerSignalerImpl.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/core/SchedulerSignalerImpl.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/core/SchedulerSignalerImpl.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,11 +16,11 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.core; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.quartz.JobKey; import org.quartz.SchedulerException; import org.quartz.Trigger; import org.quartz.spi.SchedulerSignaler; @@ -33,6 +33,8 @@ */ public class SchedulerSignalerImpl implements SchedulerSignaler { + Logger log = LoggerFactory.getLogger(SchedulerSignalerImpl.class); + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -41,7 +43,8 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - private QuartzScheduler sched; + protected QuartzScheduler sched; + protected QuartzSchedulerThread schedThread; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -51,31 +54,45 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - SchedulerSignalerImpl(QuartzScheduler sched) { + public SchedulerSignalerImpl(QuartzScheduler sched, QuartzSchedulerThread schedThread) { this.sched = sched; + this.schedThread = schedThread; + + log.info("Initialized Scheduler Signaller of type: " + getClass()); } + /* + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Interface. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + public void notifyTriggerListenersMisfired(Trigger trigger) { try { sched.notifyTriggerListenersMisfired(trigger); } catch (SchedulerException se) { - QuartzScheduler.getLog().error( + sched.getLog().error( "Error notifying listeners of trigger misfire.", se); sched.notifySchedulerListenersError( "Error notifying listeners of trigger misfire.", se); } } - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Interface. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ + public void notifySchedulerListenersFinalized(Trigger trigger) { + sched.notifySchedulerListenersFinalized(trigger); + } - public void signalSchedulingChange() { - sched.notifySchedulerThread(); + public void signalSchedulingChange(long candidateNewNextFireTime) { + schedThread.signalSchedulingChange(candidateNewNextFireTime); } + public void notifySchedulerListenersJobDeleted(JobKey jobKey) { + sched.notifySchedulerListenersJobDeleted(jobKey); + } + + public void notifySchedulerListenersError(String string, SchedulerException jpe) { + sched.notifySchedulerListenersError(string, jpe); + } } Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/core/SchedulingContext.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/core/mbeans-descriptors.xml'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/core/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/core/package.html,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/core/package.html 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/core/package.html 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -8,8 +8,8 @@


-See the Quartz project - at Open Symphony for more information. +See the Quartz project + for more information. \ No newline at end of file Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/core/quartz-build.properties'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/core/jmx/CronTriggerSupport.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/core/jmx/JobDataMapSupport.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/core/jmx/JobDetailSupport.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/core/jmx/JobExecutionContextSupport.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/core/jmx/QuartzSchedulerMBean.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/core/jmx/SimpleTriggerSupport.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/core/jmx/TriggerSupport.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/ee/jmx/jboss/JBoss4RMIRemoteMBeanScheduler.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/ee/jmx/jboss/QuartzService.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/ee/jmx/jboss/QuartzServiceMBean.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/ee/jmx/jboss/doc-files/quartz-service.xml'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/ee/jta/JTAAnnotationAwareJobRunShellFactory.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/ee/jta/JTAJobRunShell.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/ee/jta/JTAJobRunShell.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/ee/jta/JTAJobRunShell.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/ee/jta/JTAJobRunShell.java 15 Dec 2014 10:09:54 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,9 +16,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.ee.jta; import javax.transaction.Status; @@ -28,8 +25,7 @@ import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.core.JobRunShell; -import org.quartz.core.JobRunShellFactory; -import org.quartz.core.SchedulingContext; +import org.quartz.spi.TriggerFiredBundle; /** *

@@ -51,11 +47,10 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + private final Integer transactionTimeout; private UserTransaction ut; - private UserTransactionHelper userTxHelper; - /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -69,14 +64,21 @@ * Create a JTAJobRunShell instance with the given settings. *

*/ - public JTAJobRunShell(JobRunShellFactory jobRunShellFactory, - Scheduler scheduler, SchedulingContext schdCtxt, - UserTransactionHelper userTxHelper) { - super(jobRunShellFactory, scheduler, schdCtxt); - - this.userTxHelper = userTxHelper; + public JTAJobRunShell(Scheduler scheduler, TriggerFiredBundle bndle) { + super(scheduler, bndle); + this.transactionTimeout = null; } + /** + *

+ * Create a JTAJobRunShell instance with the given settings. + *

+ */ + public JTAJobRunShell(Scheduler scheduler, TriggerFiredBundle bndle, int timeout) { + super(scheduler, bndle); + this.transactionTimeout = timeout; + } + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -85,57 +87,93 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + @Override protected void begin() throws SchedulerException { + // Don't get a new UserTransaction w/o making sure we cleaned up the old + // one. This is necessary because there are paths through JobRunShell.run() + // where begin() can be called multiple times w/o complete being called in + // between. + cleanupUserTransaction(); + + boolean beganSuccessfully = false; try { - log.debug("Looking up UserTransaction."); - ut = userTxHelper.lookup(); + getLog().debug("Looking up UserTransaction."); + ut = UserTransactionHelper.lookupUserTransaction(); + if (transactionTimeout != null) { + ut.setTransactionTimeout(transactionTimeout); + } - log.debug("Beginning UserTransaction."); + getLog().debug("Beginning UserTransaction."); ut.begin(); + + beganSuccessfully = true; } catch (SchedulerException se) { throw se; } catch (Exception nse) { throw new SchedulerException( "JTAJobRunShell could not start UserTransaction.", nse); + } finally { + if (beganSuccessfully == false) { + cleanupUserTransaction(); + } } } + @Override protected void complete(boolean successfulExecution) - throws SchedulerException { - - if (ut == null) return; - - try { - if (ut.getStatus() == Status.STATUS_MARKED_ROLLBACK) { - log.debug("UserTransaction marked for rollback only."); - successfulExecution = false; - } - } catch (SystemException e) { - throw new SchedulerException( - "JTAJobRunShell could not read UserTransaction status.", e); + throws SchedulerException { + if (ut == null) { + return; } - if (successfulExecution) { + try { try { - log.debug("Committing UserTransaction."); - ut.commit(); - } catch (Exception nse) { + if (ut.getStatus() == Status.STATUS_MARKED_ROLLBACK) { + getLog().debug("UserTransaction marked for rollback only."); + successfulExecution = false; + } + } catch (SystemException e) { throw new SchedulerException( - "JTAJobRunShell could not commit UserTransaction.", nse); + "JTAJobRunShell could not read UserTransaction status.", e); } - } else { - try { - log.debug("Rolling-back UserTransaction."); - ut.rollback(); - } catch (Exception nse) { - throw new SchedulerException( - "JTAJobRunShell could not rollback UserTransaction.", - nse); + + if (successfulExecution) { + try { + getLog().debug("Committing UserTransaction."); + ut.commit(); + } catch (Exception nse) { + throw new SchedulerException( + "JTAJobRunShell could not commit UserTransaction.", nse); + } + } else { + try { + getLog().debug("Rolling-back UserTransaction."); + ut.rollback(); + } catch (Exception nse) { + throw new SchedulerException( + "JTAJobRunShell could not rollback UserTransaction.", + nse); + } } + } finally { + cleanupUserTransaction(); } - - ut = null; } + /** + * Override passivate() to ensure we always cleanup the UserTransaction. + */ + @Override + public void passivate() { + cleanupUserTransaction(); + super.passivate(); + } + + private void cleanupUserTransaction() { + if (ut != null) { + UserTransactionHelper.returnUserTransaction(ut); + ut = null; + } + } } \ No newline at end of file Index: 3rdParty_sources/quartz/org/quartz/ee/jta/JTAJobRunShellFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/ee/jta/JTAJobRunShellFactory.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/ee/jta/JTAJobRunShellFactory.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/ee/jta/JTAJobRunShellFactory.java 15 Dec 2014 10:09:54 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,16 +16,14 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.ee.jta; import org.quartz.Scheduler; import org.quartz.SchedulerConfigException; +import org.quartz.SchedulerException; import org.quartz.core.JobRunShell; import org.quartz.core.JobRunShellFactory; -import org.quartz.core.SchedulingContext; +import org.quartz.spi.TriggerFiredBundle; /** *

@@ -53,10 +51,6 @@ private Scheduler scheduler; - private SchedulingContext schedCtxt; - - private UserTransactionHelper userTxHelper; - /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -65,8 +59,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - public JTAJobRunShellFactory(UserTransactionHelper userTxHelper) { - this.userTxHelper = userTxHelper; + public JTAJobRunShellFactory() { } /* @@ -86,10 +79,9 @@ * operations with the JobStore. *

*/ - public void initialize(Scheduler scheduler, SchedulingContext schedCtxt) - throws SchedulerConfigException { - this.scheduler = scheduler; - this.schedCtxt = schedCtxt; + public void initialize(Scheduler sched) + throws SchedulerConfigException { + this.scheduler = sched; } /** @@ -99,19 +91,11 @@ * {@link org.quartz.core.JobRunShell}
. *

*/ - public JobRunShell borrowJobRunShell() { - return new JTAJobRunShell(this, scheduler, schedCtxt, userTxHelper); + public JobRunShell createJobRunShell(TriggerFiredBundle bundle) + throws SchedulerException { + return new JTAJobRunShell(scheduler, bundle); } - /** - *

- * Called by the {@link org.quartz.core.QuartzSchedulerThread} - * to return instances of - * {@link org.quartz.core.JobRunShell}. - *

- */ - public void returnJobRunShell(JobRunShell jobRunShell) { - jobRunShell.passivate(); - } + } \ No newline at end of file Index: 3rdParty_sources/quartz/org/quartz/ee/jta/UserTransactionHelper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/ee/jta/UserTransactionHelper.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/ee/jta/UserTransactionHelper.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/ee/jta/UserTransactionHelper.java 15 Dec 2014 10:09:54 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,26 +16,34 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.ee.jta; import javax.naming.InitialContext; +import javax.transaction.HeuristicMixedException; +import javax.transaction.HeuristicRollbackException; +import javax.transaction.NotSupportedException; +import javax.transaction.RollbackException; +import javax.transaction.SystemException; import javax.transaction.UserTransaction; -import org.quartz.SchedulerConfigException; import org.quartz.SchedulerException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** *

* A helper for obtaining a handle to a UserTransaction... *

+ *

+ * To ensure proper cleanup of the InitalContext used to create/lookup + * the UserTransaction, be sure to always call returnUserTransaction() when + * you are done with the UserTransaction. + *

* * @author James House */ public class UserTransactionHelper { - + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -45,7 +53,6 @@ */ public static final String DEFAULT_USER_TX_LOCATION = "java:comp/UserTransaction"; - /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -54,12 +61,8 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - private InitialContext ctxt; - - private UserTransaction ut; - - private String userTxURL; - + private static String userTxURL = DEFAULT_USER_TX_LOCATION; + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -69,20 +72,9 @@ */ /** - *

- * Create a UserTransactionHelper instance with the given settings. - *

+ * Do not allow the creation of an all static utility class. */ - public UserTransactionHelper(String userTxURL) - throws SchedulerConfigException { - - try { - ctxt = new InitialContext(); - } catch (Exception e) { - throw new SchedulerConfigException( - "JTAJobRunShellFactory initialization failed.", e); - } - setUserTxLocation(userTxURL); + private UserTransactionHelper() { } /* @@ -93,7 +85,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - public String getUserTxLocation() { + public static String getUserTxLocation() { return userTxURL; } @@ -102,20 +94,128 @@ * be found. If not set, the default value is "java:comp/UserTransaction" - * which works for nearly all application servers. */ - public void setUserTxLocation(String userTxURL) { - if (userTxURL == null) userTxURL = DEFAULT_USER_TX_LOCATION; + public static void setUserTxLocation(String userTxURL) { + if (userTxURL != null) { + UserTransactionHelper.userTxURL = userTxURL; + } + } - this.userTxURL = userTxURL; + /** + * Create/Lookup a UserTransaction in the InitialContext via the + * name set in setUserTxLocation(). + */ + public static UserTransaction lookupUserTransaction() throws SchedulerException { + return new UserTransactionWithContext(); } + + /** + * Return a UserTransaction that was retrieved via getUserTransaction(). + * This will make sure that the InitalContext used to lookup/create the + * UserTransaction is properly cleaned up. + */ + public static void returnUserTransaction(UserTransaction userTransaction) { + if ((userTransaction != null) && + (userTransaction instanceof UserTransactionWithContext)) { + UserTransactionWithContext userTransactionWithContext = + (UserTransactionWithContext)userTransaction; + + userTransactionWithContext.closeContext(); + } + } - public UserTransaction lookup() throws SchedulerException { - try { - return (UserTransaction) ctxt.lookup(userTxURL); - } catch (Exception nse) { - throw new SchedulerException( + + /** + * This class wraps a UserTransaction with the InitialContext that was used + * to look it up, so that when the UserTransaction is returned to the + * UserTransactionHelper the InitialContext can be closed. + */ + private static class UserTransactionWithContext implements UserTransaction { + InitialContext context; + UserTransaction userTransaction; + + public UserTransactionWithContext() throws SchedulerException { + try { + context = new InitialContext(); + } catch (Throwable t) { + throw new SchedulerException( + "UserTransactionHelper failed to create InitialContext to lookup/create UserTransaction.", t); + } + + try { + userTransaction = (UserTransaction)context.lookup(userTxURL); + } catch (Throwable t) { + closeContext(); + throw new SchedulerException( "UserTransactionHelper could not lookup/create UserTransaction.", - nse); + t); + } + + if (userTransaction == null) { + closeContext(); + throw new SchedulerException( + "UserTransactionHelper could not lookup/create UserTransaction from the InitialContext."); + } } - } -} \ No newline at end of file + /** + * Close the InitialContext that was used to lookup/create the + * underlying UserTransaction. + */ + public void closeContext() { + try { + if (context != null) { + context.close(); + } + } catch (Throwable t) { + getLog().warn("Failed to close InitialContext used to get a UserTransaction.", t); + } + context = null; + } + + /** + * When we are being garbage collected, make sure we were properly + * returned to the UserTransactionHelper. + */ + @Override + protected void finalize() throws Throwable { + try { + if (context != null) { + getLog().warn("UserTransaction was never returned to the UserTransactionHelper."); + closeContext(); + } + } finally { + super.finalize(); + } + } + + private static Logger getLog() { + return LoggerFactory.getLogger(UserTransactionWithContext.class); + } + + // Wrapper methods that just delegate to the underlying UserTransaction + + public void begin() throws NotSupportedException, SystemException { + userTransaction.begin(); + } + + public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, IllegalStateException, SystemException { + userTransaction.commit(); + } + + public void rollback() throws IllegalStateException, SecurityException, SystemException { + userTransaction.rollback(); + } + + public void setRollbackOnly() throws IllegalStateException, SystemException { + userTransaction.setRollbackOnly(); + } + + public int getStatus() throws SystemException { + return userTransaction.getStatus(); + } + + public void setTransactionTimeout(int seconds) throws SystemException { + userTransaction.setTransactionTimeout(seconds); + } + } +} Index: 3rdParty_sources/quartz/org/quartz/ee/servlet/QuartzInitializerListener.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/ee/servlet/QuartzInitializerListener.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/ee/servlet/QuartzInitializerListener.java 17 Aug 2012 15:10:22 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/ee/servlet/QuartzInitializerListener.java 15 Dec 2014 10:09:55 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2010 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,16 +15,16 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.ee.servlet; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.quartz.Scheduler; +import org.quartz.SchedulerException; import org.quartz.impl.StdSchedulerFactory; /** @@ -37,56 +37,85 @@ * *
  *     <context-param>
- *         <param-name>config-file</param-name>
+ *         <param-name>quartz:config-file</param-name>
  *         <param-value>/some/path/my_quartz.properties</param-value>
  *     </context-param>
  *     <context-param>
- *         <param-name>shutdown-on-unload</param-name>
+ *         <param-name>quartz:shutdown-on-unload</param-name>
  *         <param-value>true</param-value>
  *     </context-param>
  *     <context-param>
- *         <param-name>start-scheduler-on-load</param-name>
+ *         <param-name>quartz:wait-on-shutdown</param-name>
  *         <param-value>true</param-value>
  *     </context-param>
- *
+ *     <context-param>
+ *         <param-name>quartz:start-on-load</param-name>
+ *         <param-value>true</param-value>
+ *     </context-param>
  *     
  *     <listener>
  *         <listener-class>
- *             org.quartz.ee.servlet.QuartzInitializerServletListener
+ *             org.quartz.ee.servlet.QuartzInitializerListener
  *         </listener-class>
  *     </listener>
  * 
* *

*

- * The init parameter 'config-file' can be used to specify the path (and + * The init parameter 'quartz:config-file' can be used to specify the path (and * filename) of your Quartz properties file. If you leave out this parameter, * the default ("quartz.properties") will be used. *

* *

- * The init parameter 'shutdown-on-unload' can be used to specify whether you - * want scheduler.shutdown() called when the servlet is unloaded (usually when + * The init parameter 'quartz:shutdown-on-unload' can be used to specify whether you + * want scheduler.shutdown() called when the listener is unloaded (usually when * the application server is being shutdown). Possible values are "true" or * "false". The default is "true". *

* *

- * The init parameter 'start-scheduler-on-load' can be used to specify whether - * you want the scheduler.start() method called when the servlet is first loaded. + * The init parameter 'quartz:wait-on-shutdown' has effect when + * 'quartz:shutdown-on-unload' is specified "true", and indicates whether you + * want scheduler.shutdown(true) called when the listener is unloaded (usually when + * the application server is being shutdown). Passing "true" to the shutdown() call + * causes the scheduler to wait for existing jobs to complete. Possible values are + * "true" or "false". The default is "false". + *

+ * + *

+ * The init parameter 'quartz:start-on-load' can be used to specify whether + * you want the scheduler.start() method called when the listener is first loaded. * If set to false, your application will need to call the start() method before - * teh scheduler begins to run and process jobs. Possible values are "true" or + * the scheduler begins to run and process jobs. Possible values are "true" or * "false". The default is "true", which means the scheduler is started. *

* * A StdSchedulerFactory instance is stored into the ServletContext. You can gain access * to the factory from a ServletContext instance like this: *
- * + *
  * StdSchedulerFactory factory = (StdSchedulerFactory) ctx
- *				.getAttribute(QuartzFactoryServlet.QUARTZ_FACTORY_KEY);
- * 
- * 
+ * .getAttribute(QuartzInitializerListener.QUARTZ_FACTORY_KEY);
+ *

+ * The init parameter 'quartz:servlet-context-factory-key' can be used to override the + * name under which the StdSchedulerFactory is stored into the ServletContext, in + * which case you will want to use this name rather than + * QuartzInitializerListener.QUARTZ_FACTORY_KEY in the above example. + *

+ * + *

+ * The init parameter 'quartz:scheduler-context-servlet-context-key' if set, the + * ServletContext will be stored in the SchedulerContext under the given key + * name (and will therefore be available to jobs during execution). + *

+ * + *

+ * The init parameter 'quartz:start-delay-seconds' can be used to specify the amount + * of time to wait after initializing the scheduler before scheduler.start() + * is called. + *

+ * * Once you have the factory instance, you can retrieve the Scheduler instance by calling * getScheduler() on the factory. * @@ -96,83 +125,144 @@ */ public class QuartzInitializerListener implements ServletContextListener { - public static final String QUARTZ_FACTORY_KEY = "org.quartz.impl.StdSchedulerFactory.KEY"; + public static final String QUARTZ_FACTORY_KEY = "org.quartz.impl.StdSchedulerFactory.KEY"; - private boolean performShutdown = true; + private boolean performShutdown = true; + private boolean waitOnShutdown = false; - private Scheduler scheduler = null; + private Scheduler scheduler = null; - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Interface. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ + private final Logger log = LoggerFactory.getLogger(getClass()); + + /* + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Interface. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ - public void contextInitialized(ServletContextEvent sce) { + public void contextInitialized(ServletContextEvent sce) { - System.out.println("Quartz Initializer Servlet loaded, initializing Scheduler..."); + log.info("Quartz Initializer Servlet loaded, initializing Scheduler..."); - ServletContext servletContext = sce.getServletContext(); - StdSchedulerFactory factory; - try { + ServletContext servletContext = sce.getServletContext(); + StdSchedulerFactory factory; + try { - String configFile = servletContext.getInitParameter("config-file"); - String shutdownPref = servletContext.getInitParameter("shutdown-on-unload"); + String configFile = servletContext.getInitParameter("quartz:config-file"); + if(configFile == null) + configFile = servletContext.getInitParameter("config-file"); // older name, for backward compatibility + String shutdownPref = servletContext.getInitParameter("quartz:shutdown-on-unload"); + if(shutdownPref == null) + shutdownPref = servletContext.getInitParameter("shutdown-on-unload"); + if (shutdownPref != null) { + performShutdown = Boolean.valueOf(shutdownPref).booleanValue(); + } + String shutdownWaitPref = servletContext.getInitParameter("quartz:wait-on-shutdown"); + if (shutdownPref != null) { + waitOnShutdown = Boolean.valueOf(shutdownWaitPref).booleanValue(); + } - if (shutdownPref != null) - performShutdown = Boolean.valueOf(shutdownPref).booleanValue(); + factory = getSchedulerFactory(configFile); - // get Properties - if (configFile != null) { - factory = new StdSchedulerFactory(configFile); - } else { - factory = new StdSchedulerFactory(); - } + // Always want to get the scheduler, even if it isn't starting, + // to make sure it is both initialized and registered. + scheduler = factory.getScheduler(); - // Should the Scheduler being started now or later - String startOnLoad = servletContext - .getInitParameter("start-scheduler-on-load"); - /* - * If the "start-scheduler-on-load" init-parameter is not specified, - * the scheduler will be started. This is to maintain backwards - * compatability. - */ - if (startOnLoad == null || (Boolean.valueOf(startOnLoad).booleanValue())) { - // Start now - scheduler = factory.getScheduler(); - scheduler.start(); - System.out.println("Scheduler has been started..."); - } else { - System.out.println("Scheduler has not been started. Use scheduler.start()"); - } + // Should the Scheduler being started now or later + String startOnLoad = servletContext.getInitParameter("quartz:start-on-load"); + if(startOnLoad == null) + startOnLoad = servletContext.getInitParameter("start-scheduler-on-load"); - System.out.println("Storing the Quartz Scheduler Factory in the servlet context at key: " - + QUARTZ_FACTORY_KEY); - servletContext.setAttribute(QUARTZ_FACTORY_KEY, factory); + int startDelay = 0; + String startDelayS = servletContext.getInitParameter("quartz:start-delay-seconds"); + if(startDelayS == null) + startDelayS = servletContext.getInitParameter("start-delay-seconds"); + try { + if(startDelayS != null && startDelayS.trim().length() > 0) + startDelay = Integer.parseInt(startDelayS); + } catch(Exception e) { + log.error("Cannot parse value of 'start-delay-seconds' to an integer: " + startDelayS + ", defaulting to 5 seconds."); + startDelay = 5; + } - } catch (Exception e) { - System.out.println("Quartz Scheduler failed to initialize: " + e.toString()); - e.printStackTrace(); - } - } + /* + * If the "quartz:start-on-load" init-parameter is not specified, + * the scheduler will be started. This is to maintain backwards + * compatability. + */ + if (startOnLoad == null || (Boolean.valueOf(startOnLoad).booleanValue())) { + if(startDelay <= 0) { + // Start now + scheduler.start(); + log.info("Scheduler has been started..."); + } + else { + // Start delayed + scheduler.startDelayed(startDelay); + log.info("Scheduler will start in " + startDelay + " seconds."); + } + } else { + log.info("Scheduler has not been started. Use scheduler.start()"); + } - public void contextDestroyed(ServletContextEvent sce) { + String factoryKey = servletContext.getInitParameter("quartz:servlet-context-factory-key"); + if(factoryKey == null) + factoryKey = servletContext.getInitParameter("servlet-context-factory-key"); + if (factoryKey == null) { + factoryKey = QUARTZ_FACTORY_KEY; + } - if (!performShutdown) - return; + log.info("Storing the Quartz Scheduler Factory in the servlet context at key: " + + factoryKey); + servletContext.setAttribute(factoryKey, factory); + + + String servletCtxtKey = servletContext.getInitParameter("quartz:scheduler-context-servlet-context-key"); + if(servletCtxtKey == null) + servletCtxtKey = servletContext.getInitParameter("scheduler-context-servlet-context-key"); + if (servletCtxtKey != null) { + log.info("Storing the ServletContext in the scheduler context at key: " + + servletCtxtKey); + scheduler.getContext().put(servletCtxtKey, servletContext); + } - try { - if (scheduler != null) - scheduler.shutdown(); - } catch (Exception e) { - System.out.println("Quartz Scheduler failed to shutdown cleanly: " + e.toString()); - e.printStackTrace(); - } + } catch (Exception e) { + log.error("Quartz Scheduler failed to initialize: " + e.toString()); + e.printStackTrace(); + } + } - System.out.println("Quartz Scheduler successful shutdown."); - } + protected StdSchedulerFactory getSchedulerFactory(String configFile) + throws SchedulerException { + StdSchedulerFactory factory; + // get Properties + if (configFile != null) { + factory = new StdSchedulerFactory(configFile); + } else { + factory = new StdSchedulerFactory(); + } + return factory; + } + public void contextDestroyed(ServletContextEvent sce) { + if (!performShutdown) { + return; + } + + try { + if (scheduler != null) { + scheduler.shutdown(waitOnShutdown); + } + } catch (Exception e) { + log.error("Quartz Scheduler failed to shutdown cleanly: " + e.toString()); + e.printStackTrace(); + } + + log.info("Quartz Scheduler successful shutdown."); + } + + } Index: 3rdParty_sources/quartz/org/quartz/ee/servlet/QuartzInitializerServlet.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/ee/servlet/QuartzInitializerServlet.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/ee/servlet/QuartzInitializerServlet.java 17 Aug 2012 15:10:22 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/ee/servlet/QuartzInitializerServlet.java 15 Dec 2014 10:09:55 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.ee.servlet; import java.io.IOException; @@ -29,6 +26,7 @@ import javax.servlet.http.HttpServletResponse; import org.quartz.Scheduler; +import org.quartz.SchedulerException; import org.quartz.impl.StdSchedulerFactory; /** @@ -37,6 +35,10 @@ * load-on-startup servlet in a web application. *

* + *

Using this start-up servlet may be preferred to using the {@link QuartzInitializerListener} + * in some situations - namely when you want to initialize more than one scheduler in the same + * application.

+ * *

* You'll want to add something like this to your WEB-INF/web.xml file: * @@ -62,12 +64,14 @@ * <param-name>shutdown-on-unload</param-name> * <param-value>true</param-value> * </init-param> - * * <init-param> + * <param-name>wait-on-shutdown</param-name> + * <param-value>true</param-value> + * </init-param> + * <init-param> * <param-name>start-scheduler-on-load</param-name> * <param-value>true</param-value> * </init-param> - * * </servlet> * * @@ -86,21 +90,47 @@ *

* *

+ * The init parameter 'wait-on-shutdown' has effect when + * 'shutdown-on-unload' is specified "true", and indicates whether you + * want scheduler.shutdown(true) called when the listener is unloaded (usually when + * the application server is being shutdown). Passing "true" to the shutdown() call + * causes the scheduler to wait for existing jobs to complete. Possible values are + * "true" or "false". The default is "false". + *

+ * + *

* The init parameter 'start-scheduler-on-load' can be used to specify whether * you want the scheduler.start() method called when the servlet is first loaded. * If set to false, your application will need to call the start() method before - * teh scheduler begins to run and process jobs. Possible values are "true" or + * the scheduler begins to run and process jobs. Possible values are "true" or * "false". The default is "true", which means the scheduler is started. *

* * A StdSchedulerFactory instance is stored into the ServletContext. You can gain access * to the factory from a ServletContext instance like this: *
- * - * StdSchedulerFactory factory = (StdSchedulerFactory) ctx - * .getAttribute(QuartzFactoryServlet.QUARTZ_FACTORY_KEY); - * - *
+ *
+ *     StdSchedulerFactory factory = (StdSchedulerFactory) ctx
+ *                .getAttribute(QuartzFactoryServlet.QUARTZ_FACTORY_KEY);
+ *

+ * The init parameter 'servlet-context-factory-key' can be used to override the + * name under which the StdSchedulerFactory is stored into the ServletContext, in + * which case you will want to use this name rather than + * QuartzFactoryServlet.QUARTZ_FACTORY_KEY in the above example. + *

+ * + *

+ * The init parameter 'scheduler-context-servlet-context-key' if set, the + * ServletContext will be stored in the SchedulerContext under the given key + * name (and will therefore be available to jobs during execution). + *

+ * + *

+ * The init parameter 'start-delay-seconds' can be used to specify the amount + * of time to wait after initializing the scheduler before scheduler.start() + * is called. + *

+ * * Once you have the factory instance, you can retrieve the Scheduler instance by calling * getScheduler() on the factory. * @@ -109,92 +139,151 @@ */ public class QuartzInitializerServlet extends HttpServlet { - public static final String QUARTZ_FACTORY_KEY = "org.quartz.impl.StdSchedulerFactory.KEY"; + /** + * + */ + private static final long serialVersionUID = 1L; - private boolean performShutdown = true; + public static final String QUARTZ_FACTORY_KEY = "org.quartz.impl.StdSchedulerFactory.KEY"; - private Scheduler scheduler = null; + private boolean performShutdown = true; + private boolean waitOnShutdown = false; - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Interface. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ + private transient Scheduler scheduler = null; - public void init(ServletConfig cfg) throws javax.servlet.ServletException { - super.init(cfg); - log("Quartz Initializer Servlet loaded, initializing Scheduler..."); + /* + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Interface. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ - StdSchedulerFactory factory; - try { + @Override + public void init(ServletConfig cfg) throws javax.servlet.ServletException { + super.init(cfg); - String configFile = cfg.getInitParameter("config-file"); - String shutdownPref = cfg.getInitParameter("shutdown-on-unload"); + log("Quartz Initializer Servlet loaded, initializing Scheduler..."); - if (shutdownPref != null) - performShutdown = Boolean.valueOf(shutdownPref).booleanValue(); + StdSchedulerFactory factory; + try { - // get Properties - if (configFile != null) { - factory = new StdSchedulerFactory(configFile); - } else { - factory = new StdSchedulerFactory(); - } + String configFile = cfg.getInitParameter("config-file"); + String shutdownPref = cfg.getInitParameter("shutdown-on-unload"); - // Should the Scheduler being started now or later - String startOnLoad = cfg - .getInitParameter("start-scheduler-on-load"); - /* - * If the "start-scheduler-on-load" init-parameter is not specified, - * the scheduler will be started. This is to maintain backwards - * compatability. - */ - if (startOnLoad == null || (Boolean.valueOf(startOnLoad).booleanValue())) { - // Start now - scheduler = factory.getScheduler(); - scheduler.start(); - log("Scheduler has been started..."); - } else { - log("Scheduler has not been started. Use scheduler.start()"); - } + if (shutdownPref != null) { + performShutdown = Boolean.valueOf(shutdownPref).booleanValue(); + } + String shutdownWaitPref = cfg.getInitParameter("wait-on-shutdown"); + if (shutdownPref != null) { + waitOnShutdown = Boolean.valueOf(shutdownWaitPref).booleanValue(); + } - log("Storing the Quartz Scheduler Factory in the servlet context at key: " - + QUARTZ_FACTORY_KEY); - cfg.getServletContext().setAttribute(QUARTZ_FACTORY_KEY, factory); + factory = getSchedulerFactory(configFile); + + // Always want to get the scheduler, even if it isn't starting, + // to make sure it is both initialized and registered. + scheduler = factory.getScheduler(); + + // Should the Scheduler being started now or later + String startOnLoad = cfg + .getInitParameter("start-scheduler-on-load"); - } catch (Exception e) { - log("Quartz Scheduler failed to initialize: " + e.toString()); - throw new ServletException(e); - } - } + int startDelay = 0; + String startDelayS = cfg.getInitParameter("start-delay-seconds"); + try { + if(startDelayS != null && startDelayS.trim().length() > 0) + startDelay = Integer.parseInt(startDelayS); + } catch(Exception e) { + log("Cannot parse value of 'start-delay-seconds' to an integer: " + startDelayS + ", defaulting to 5 seconds.", e); + startDelay = 5; + } + + /* + * If the "start-scheduler-on-load" init-parameter is not specified, + * the scheduler will be started. This is to maintain backwards + * compatability. + */ + if (startOnLoad == null || (Boolean.valueOf(startOnLoad).booleanValue())) { + if(startDelay <= 0) { + // Start now + scheduler.start(); + log("Scheduler has been started..."); + } + else { + // Start delayed + scheduler.startDelayed(startDelay); + log("Scheduler will start in " + startDelay + " seconds."); + } + } else { + log("Scheduler has not been started. Use scheduler.start()"); + } - public void destroy() { + String factoryKey = cfg.getInitParameter("servlet-context-factory-key"); + if (factoryKey == null) { + factoryKey = QUARTZ_FACTORY_KEY; + } + + log("Storing the Quartz Scheduler Factory in the servlet context at key: " + + factoryKey); + cfg.getServletContext().setAttribute(factoryKey, factory); + + + String servletCtxtKey = cfg.getInitParameter("scheduler-context-servlet-context-key"); + if (servletCtxtKey != null) { + log("Storing the ServletContext in the scheduler context at key: " + + servletCtxtKey); + scheduler.getContext().put(servletCtxtKey, cfg.getServletContext()); + } - if (!performShutdown) - return; + } catch (Exception e) { + log("Quartz Scheduler failed to initialize: " + e.toString()); + throw new ServletException(e); + } + } - try { - if (scheduler != null) - scheduler.shutdown(); - } catch (Exception e) { - log("Quartz Scheduler failed to shutdown cleanly: " + e.toString()); - e.printStackTrace(); - } + protected StdSchedulerFactory getSchedulerFactory(String configFile) + throws SchedulerException { + StdSchedulerFactory factory; + // get Properties + if (configFile != null) { + factory = new StdSchedulerFactory(configFile); + } else { + factory = new StdSchedulerFactory(); + } + return factory; + } - log("Quartz Scheduler successful shutdown."); - } + @Override + public void destroy() { - public void doPost(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - response.sendError(HttpServletResponse.SC_FORBIDDEN); - } + if (!performShutdown) { + return; + } - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - response.sendError(HttpServletResponse.SC_FORBIDDEN); - } + try { + if (scheduler != null) { + scheduler.shutdown(waitOnShutdown); + } + } catch (Exception e) { + log("Quartz Scheduler failed to shutdown cleanly: " + e.toString()); + e.printStackTrace(); + } + log("Quartz Scheduler successful shutdown."); + } + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + response.sendError(HttpServletResponse.SC_FORBIDDEN); + } + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + response.sendError(HttpServletResponse.SC_FORBIDDEN); + } + } Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/helpers/TriggerUtils.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/helpers/VersionPrinter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/helpers/VersionPrinter.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/helpers/VersionPrinter.java 17 Aug 2012 15:10:21 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/helpers/VersionPrinter.java 15 Dec 2014 10:09:55 -0000 1.1.2.1 @@ -1,6 +1,6 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,9 +16,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.helpers; import org.quartz.core.QuartzScheduler; @@ -32,6 +29,12 @@ */ public class VersionPrinter { + /** + * Private constructor because this is a pure utility class. + */ + private VersionPrinter() { + } + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Index: 3rdParty_sources/quartz/org/quartz/helpers/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/helpers/package.html,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/helpers/package.html 17 Aug 2012 15:10:21 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/helpers/package.html 15 Dec 2014 10:09:55 -0000 1.1.2.1 @@ -8,8 +8,8 @@


-See the Quartz project - at Open Symphony for more information. +See the Quartz project + for more information. \ No newline at end of file Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/DefaultThreadExecutor.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/impl/DirectSchedulerFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/DirectSchedulerFactory.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/DirectSchedulerFactory.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/DirectSchedulerFactory.java 15 Dec 2014 10:09:52 -0000 1.1.2.1 @@ -1,131 +1,144 @@ -/* - * Copyright 2004-2005 OpenSymphony - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations +/* + * Copyright 2001-2009 Terracotta, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations * under the License. - * + * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SchedulerFactory; import org.quartz.core.JobRunShellFactory; import org.quartz.core.QuartzScheduler; import org.quartz.core.QuartzSchedulerResources; -import org.quartz.core.SchedulingContext; import org.quartz.simpl.CascadingClassLoadHelper; import org.quartz.simpl.RAMJobStore; import org.quartz.simpl.SimpleThreadPool; import org.quartz.spi.ClassLoadHelper; import org.quartz.spi.JobStore; +import org.quartz.spi.SchedulerPlugin; +import org.quartz.spi.ThreadExecutor; import org.quartz.spi.ThreadPool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.util.Collection; - /** *

* A singleton implementation of {@link org.quartz.SchedulerFactory}. *

- * + * *

* Here are some examples of using this class: *

*

* To create a scheduler that does not write anything to the database (is not * persistent), you can call createVolatileScheduler: - * + * *

  *  DirectSchedulerFactory.getInstance().createVolatileScheduler(10); // 10 threads * // don't forget to start the scheduler: DirectSchedulerFactory.getInstance().getScheduler().start();
  * 
- * - * + * + * *

* Several create methods are provided for convenience. All create methods * eventually end up calling the create method with all the parameters: *

- * + * *
  *  public void createScheduler(String schedulerName, String schedulerInstanceId, ThreadPool threadPool, JobStore jobStore, String rmiRegistryHost, int rmiRegistryPort)
  * 
- * - * + * + * *

* Here is an example of using this method: *

* * - * *
// create the thread pool SimpleThreadPool threadPool = new SimpleThreadPool(maxThreads, Thread.NORM_PRIORITY); threadPool.initialize(); * // create the job store JobStore jobStore = new RAMJobStore(); jobStore.initialize();
- * 
+ *  * 
// create the thread pool SimpleThreadPool threadPool = new SimpleThreadPool(maxThreads, Thread.NORM_PRIORITY); threadPool.initialize(); * // create the job store JobStore jobStore = new RAMJobStore();
+ *
  *  DirectSchedulerFactory.getInstance().createScheduler("My Quartz Scheduler", "My Instance", threadPool, jobStore, "localhost", 1099); * // don't forget to start the scheduler: DirectSchedulerFactory.getInstance().getScheduler("My Quartz Scheduler", "My Instance").start();
  * 
- * - * + * + * *

* You can also use a JDBCJobStore instead of the RAMJobStore: *

- * + * *
  *  DBConnectionManager.getInstance().addConnectionProvider("someDatasource", new JNDIConnectionProvider("someDatasourceJNDIName"));
- * 
- *  JDBCJobStore jdbcJobStore = new JDBCJobStore(); jdbcJobStore.setDataSource("someDatasource"); jdbcJobStore.setPostgresStyleBlobs(true); jdbcJobStore.setTablePrefix("QRTZ_"); jdbcJobStore.setInstanceId("My Instance"); jdbcJobStore.initialize();
+ *
+ *  JobStoreTX jdbcJobStore = new JobStoreTX(); jdbcJobStore.setDataSource("someDatasource"); jdbcJobStore.setPostgresStyleBlobs(true); jdbcJobStore.setTablePrefix("QRTZ_"); jdbcJobStore.setInstanceId("My Instance");
  * 
- * + * * @author Mohammad Rezaei * @author James House - * + * * @see JobStore * @see ThreadPool */ public class DirectSchedulerFactory implements SchedulerFactory { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Constants. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ public static final String DEFAULT_INSTANCE_ID = "SIMPLE_NON_CLUSTERED"; public static final String DEFAULT_SCHEDULER_NAME = "SimpleQuartzScheduler"; + private static final boolean DEFAULT_JMX_EXPORT = false; + + private static final String DEFAULT_JMX_OBJECTNAME = null; + + private static final DefaultThreadExecutor DEFAULT_THREAD_EXECUTOR = new DefaultThreadExecutor(); + + private static final int DEFAULT_BATCH_MAX_SIZE = 1; + + private static final long DEFAULT_BATCH_TIME_WINDOW = 0L; + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Data members. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ private boolean initialized = false; private static DirectSchedulerFactory instance = new DirectSchedulerFactory(); + private final Logger log = LoggerFactory.getLogger(getClass()); + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Constructors. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - private Log getLog() { - return LogFactory.getLog(DirectSchedulerFactory.class); + protected Logger getLog() { + return log; } /** @@ -136,9 +149,9 @@ /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Interface. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -149,35 +162,26 @@ /** * Creates an in memory job store ({@link RAMJobStore}) * The thread priority is set to Thread.NORM_PRIORITY - * + * * @param maxThreads * The number of threads in the thread pool * @throws SchedulerException * if initialization failed. */ public void createVolatileScheduler(int maxThreads) - throws SchedulerException { + throws SchedulerException { SimpleThreadPool threadPool = new SimpleThreadPool(maxThreads, Thread.NORM_PRIORITY); threadPool.initialize(); JobStore jobStore = new RAMJobStore(); this.createScheduler(threadPool, jobStore); - } + /** - * @deprecated see correctly spelled method. - * @see #createVolatileScheduler(int) - */ - public void createVolatileSchduler(int maxThreads) - throws SchedulerException { - createVolatileScheduler(maxThreads); - } - - /** * Creates a proxy to a remote scheduler. This scheduler can be retrieved * via {@link DirectSchedulerFactory#getScheduler()} - * + * * @param rmiHost * The hostname for remote scheduler * @param rmiPort @@ -186,10 +190,9 @@ * if the remote scheduler could not be reached. */ public void createRemoteScheduler(String rmiHost, int rmiPort) - throws SchedulerException { + throws SchedulerException { createRemoteScheduler(DEFAULT_SCHEDULER_NAME, DEFAULT_INSTANCE_ID, rmiHost, rmiPort); - initialized = true; } /** @@ -198,7 +201,7 @@ * with the addition of specifying the scheduler name and instance ID. This * scheduler can only be retrieved via * {@link DirectSchedulerFactory#getScheduler(String)} - * + * * @param schedulerName * The name for the scheduler. * @param schedulerInstanceId @@ -210,27 +213,54 @@ * @throws SchedulerException * if the remote scheduler could not be reached. */ - protected void createRemoteScheduler(String schedulerName, + public void createRemoteScheduler(String schedulerName, String schedulerInstanceId, String rmiHost, int rmiPort) - throws SchedulerException { - SchedulingContext schedCtxt = new SchedulingContext(); - schedCtxt.setInstanceId(schedulerInstanceId); + throws SchedulerException { + createRemoteScheduler(schedulerName, + schedulerInstanceId, null, rmiHost, rmiPort); + } - String uid = QuartzSchedulerResources.getUniqueIdentifier( + /** + * Same as + * {@link DirectSchedulerFactory#createRemoteScheduler(String rmiHost, int rmiPort)}, + * with the addition of specifying the scheduler name, instance ID, and rmi + * bind name. This scheduler can only be retrieved via + * {@link DirectSchedulerFactory#getScheduler(String)} + * + * @param schedulerName + * The name for the scheduler. + * @param schedulerInstanceId + * The instance ID for the scheduler. + * @param rmiBindName + * The name of the remote scheduler in the RMI repository. If null + * defaults to the generated unique identifier. + * @param rmiHost + * The hostname for remote scheduler + * @param rmiPort + * Port for the remote scheduler. The default RMI port is 1099. + * @throws SchedulerException + * if the remote scheduler could not be reached. + */ + public void createRemoteScheduler(String schedulerName, + String schedulerInstanceId, String rmiBindName, String rmiHost, int rmiPort) + throws SchedulerException { + + String uid = (rmiBindName != null) ? rmiBindName : + QuartzSchedulerResources.getUniqueIdentifier( schedulerName, schedulerInstanceId); - RemoteScheduler remoteScheduler = new RemoteScheduler(schedCtxt, uid, - rmiHost, rmiPort); + RemoteScheduler remoteScheduler = new RemoteScheduler(uid, rmiHost, rmiPort); SchedulerRepository schedRep = SchedulerRepository.getInstance(); schedRep.bind(remoteScheduler); + initialized = true; } /** * Creates a scheduler using the specified thread pool and job store. This * scheduler can be retrieved via * {@link DirectSchedulerFactory#getScheduler()} - * + * * @param threadPool * The thread pool for executing jobs * @param jobStore @@ -239,10 +269,9 @@ * if initialization failed */ public void createScheduler(ThreadPool threadPool, JobStore jobStore) - throws SchedulerException { + throws SchedulerException { createScheduler(DEFAULT_SCHEDULER_NAME, DEFAULT_INSTANCE_ID, threadPool, jobStore); - initialized = true; } /** @@ -251,7 +280,7 @@ * with the addition of specifying the scheduler name and instance ID. This * scheduler can only be retrieved via * {@link DirectSchedulerFactory#getScheduler(String)} - * + * * @param schedulerName * The name for the scheduler. * @param schedulerInstanceId @@ -265,15 +294,15 @@ */ public void createScheduler(String schedulerName, String schedulerInstanceId, ThreadPool threadPool, JobStore jobStore) - throws SchedulerException { + throws SchedulerException { createScheduler(schedulerName, schedulerInstanceId, threadPool, jobStore, null, 0, -1, -1); } /** * Creates a scheduler using the specified thread pool and job store and * binds it to RMI. - * + * * @param schedulerName * The name for the scheduler. * @param schedulerInstanceId @@ -297,37 +326,197 @@ String schedulerInstanceId, ThreadPool threadPool, JobStore jobStore, String rmiRegistryHost, int rmiRegistryPort, long idleWaitTime, long dbFailureRetryInterval) - throws SchedulerException { + throws SchedulerException { + createScheduler(schedulerName, + schedulerInstanceId, threadPool, + jobStore, null, // plugins + rmiRegistryHost, rmiRegistryPort, + idleWaitTime, dbFailureRetryInterval, + DEFAULT_JMX_EXPORT, DEFAULT_JMX_OBJECTNAME); + } + + /** + * Creates a scheduler using the specified thread pool, job store, and + * plugins, and binds it to RMI. + * + * @param schedulerName + * The name for the scheduler. + * @param schedulerInstanceId + * The instance ID for the scheduler. + * @param threadPool + * The thread pool for executing jobs + * @param jobStore + * The type of job store + * @param schedulerPluginMap + * Map from a String plugin names to + * {@link org.quartz.spi.SchedulerPlugin}s. Can use + * "null" if no plugins are required. + * @param rmiRegistryHost + * The hostname to register this scheduler with for RMI. Can use + * "null" if no RMI is required. + * @param rmiRegistryPort + * The port for RMI. Typically 1099. + * @param idleWaitTime + * The idle wait time in milliseconds. You can specify "-1" for + * the default value, which is currently 30000 ms. + * @throws SchedulerException + * if initialization failed + */ + public void createScheduler(String schedulerName, + String schedulerInstanceId, ThreadPool threadPool, + JobStore jobStore, Map schedulerPluginMap, + String rmiRegistryHost, int rmiRegistryPort, + long idleWaitTime, long dbFailureRetryInterval, + boolean jmxExport, String jmxObjectName) + throws SchedulerException { + createScheduler(schedulerName, schedulerInstanceId, threadPool, + DEFAULT_THREAD_EXECUTOR, jobStore, schedulerPluginMap, + rmiRegistryHost, rmiRegistryPort, idleWaitTime, + dbFailureRetryInterval, jmxExport, jmxObjectName); + } + + /** + * Creates a scheduler using the specified thread pool, job store, and + * plugins, and binds it to RMI. + * + * @param schedulerName + * The name for the scheduler. + * @param schedulerInstanceId + * The instance ID for the scheduler. + * @param threadPool + * The thread pool for executing jobs + * @param threadExecutor + * The thread executor for executing jobs + * @param jobStore + * The type of job store + * @param schedulerPluginMap + * Map from a String plugin names to + * {@link org.quartz.spi.SchedulerPlugin}s. Can use + * "null" if no plugins are required. + * @param rmiRegistryHost + * The hostname to register this scheduler with for RMI. Can use + * "null" if no RMI is required. + * @param rmiRegistryPort + * The port for RMI. Typically 1099. + * @param idleWaitTime + * The idle wait time in milliseconds. You can specify "-1" for + * the default value, which is currently 30000 ms. + * @throws SchedulerException + * if initialization failed + */ + public void createScheduler(String schedulerName, + String schedulerInstanceId, ThreadPool threadPool, + ThreadExecutor threadExecutor, + JobStore jobStore, Map schedulerPluginMap, + String rmiRegistryHost, int rmiRegistryPort, + long idleWaitTime, long dbFailureRetryInterval, + boolean jmxExport, String jmxObjectName) + throws SchedulerException { + createScheduler(schedulerName, schedulerInstanceId, threadPool, + DEFAULT_THREAD_EXECUTOR, jobStore, schedulerPluginMap, + rmiRegistryHost, rmiRegistryPort, idleWaitTime, + dbFailureRetryInterval, jmxExport, jmxObjectName, DEFAULT_BATCH_MAX_SIZE, DEFAULT_BATCH_TIME_WINDOW); + } + + /** + * Creates a scheduler using the specified thread pool, job store, and + * plugins, and binds it to RMI. + * + * @param schedulerName + * The name for the scheduler. + * @param schedulerInstanceId + * The instance ID for the scheduler. + * @param threadPool + * The thread pool for executing jobs + * @param threadExecutor + * The thread executor for executing jobs + * @param jobStore + * The type of job store + * @param schedulerPluginMap + * Map from a String plugin names to + * {@link org.quartz.spi.SchedulerPlugin}s. Can use + * "null" if no plugins are required. + * @param rmiRegistryHost + * The hostname to register this scheduler with for RMI. Can use + * "null" if no RMI is required. + * @param rmiRegistryPort + * The port for RMI. Typically 1099. + * @param idleWaitTime + * The idle wait time in milliseconds. You can specify "-1" for + * the default value, which is currently 30000 ms. + * @param maxBatchSize + * The maximum batch size of triggers, when acquiring them + * @param batchTimeWindow + * The time window for which it is allowed to "pre-acquire" triggers to fire + * @throws SchedulerException + * if initialization failed + */ + public void createScheduler(String schedulerName, + String schedulerInstanceId, ThreadPool threadPool, + ThreadExecutor threadExecutor, + JobStore jobStore, Map schedulerPluginMap, + String rmiRegistryHost, int rmiRegistryPort, + long idleWaitTime, long dbFailureRetryInterval, + boolean jmxExport, String jmxObjectName, int maxBatchSize, long batchTimeWindow) + throws SchedulerException { // Currently only one run-shell factory is available... JobRunShellFactory jrsf = new StdJobRunShellFactory(); // Fire everything up // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - SchedulingContext schedCtxt = new SchedulingContext(); - schedCtxt.setInstanceId(schedulerInstanceId); + threadPool.initialize(); + QuartzSchedulerResources qrs = new QuartzSchedulerResources(); qrs.setName(schedulerName); qrs.setInstanceId(schedulerInstanceId); + SchedulerDetailsSetter.setDetails(threadPool, schedulerName, schedulerInstanceId); qrs.setJobRunShellFactory(jrsf); qrs.setThreadPool(threadPool); + qrs.setThreadExecutor(threadExecutor); qrs.setJobStore(jobStore); + qrs.setMaxBatchSize(maxBatchSize); + qrs.setBatchTimeWindow(batchTimeWindow); qrs.setRMIRegistryHost(rmiRegistryHost); qrs.setRMIRegistryPort(rmiRegistryPort); + qrs.setJMXExport(jmxExport); + if (jmxObjectName != null) { + qrs.setJMXObjectName(jmxObjectName); + } + + // add plugins + if (schedulerPluginMap != null) { + for (Iterator pluginIter = schedulerPluginMap.values().iterator(); pluginIter.hasNext();) { + qrs.addSchedulerPlugin(pluginIter.next()); + } + } - QuartzScheduler qs = new QuartzScheduler(qrs, schedCtxt, idleWaitTime, - dbFailureRetryInterval); + QuartzScheduler qs = new QuartzScheduler(qrs, idleWaitTime, dbFailureRetryInterval); ClassLoadHelper cch = new CascadingClassLoadHelper(); cch.initialize(); - + + SchedulerDetailsSetter.setDetails(jobStore, schedulerName, schedulerInstanceId); + jobStore.initialize(cch, qs.getSchedulerSignaler()); - Scheduler scheduler = new StdScheduler(qs, schedCtxt); + Scheduler scheduler = new StdScheduler(qs); - jrsf.initialize(scheduler, schedCtxt); + jrsf.initialize(scheduler); + qs.initialize(); + + + // Initialize plugins now that we have a Scheduler instance. + if (schedulerPluginMap != null) { + for (Iterator> pluginEntryIter = schedulerPluginMap.entrySet().iterator(); pluginEntryIter.hasNext();) { + Entry pluginEntry = pluginEntryIter.next(); + + pluginEntry.getValue().initialize(pluginEntry.getKey(), scheduler, cch); + } + } + getLog().info("Quartz scheduler '" + scheduler.getSchedulerName()); getLog().info("Quartz scheduler version: " + qs.getVersion()); @@ -338,6 +527,8 @@ // garbage collected schedRep.bind(scheduler); + + initialized = true; } /* @@ -352,18 +543,19 @@ *

* Returns a handle to the Scheduler produced by this factory. *

- * + * *

* you must call createRemoteScheduler or createScheduler methods before * calling getScheduler() *

*/ public Scheduler getScheduler() throws SchedulerException { - if (!initialized) { throw new SchedulerException( - "you must call createRemoteScheduler or createScheduler methods before calling getScheduler()"); } - SchedulerRepository schedRep = SchedulerRepository.getInstance(); + if (!initialized) { + throw new SchedulerException( + "you must call createRemoteScheduler or createScheduler methods before calling getScheduler()"); + } - return schedRep.lookup(DEFAULT_SCHEDULER_NAME); + return getScheduler(DEFAULT_SCHEDULER_NAME); } /** @@ -383,7 +575,7 @@ * StdSchedulerFactory instance.). *

*/ - public Collection getAllSchedulers() throws SchedulerException { + public Collection getAllSchedulers() throws SchedulerException { return SchedulerRepository.getInstance().lookupAll(); } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/JobDetailImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/JobExecutionContextImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/impl/QuartzServer.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/QuartzServer.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/QuartzServer.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/QuartzServer.java 15 Dec 2014 10:09:52 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl; import java.io.BufferedReader; @@ -26,52 +23,52 @@ import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SchedulerFactory; -import org.quartz.Trigger; +import org.quartz.listeners.SchedulerListenerSupport; /** *

* Instantiates an instance of Quartz Scheduler as a stand-alone program, if * the scheduler is configured for RMI it will be made available. *

- * + * *

* The main() method of this class currently accepts 0 or 1 arguemtns, if there * is an argument, and its value is "console", then the program * will print a short message on the console (std-out) and wait for the user to * type "exit" - at which time the scheduler will be shutdown. *

- * + * *

* Future versions of this server should allow additional configuration for * responding to scheduler events by allowing the user to specify {@link org.quartz.JobListener}, * {@link org.quartz.TriggerListener} and {@link org.quartz.SchedulerListener} * classes. *

- * + * *

* Please read the Quartz FAQ entries about RMI before asking questions in the * forums or mail-lists. *

- * + * * @author James House */ -public class QuartzServer implements org.quartz.SchedulerListener { +public class QuartzServer extends SchedulerListenerSupport { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Data members. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ private Scheduler sched = null; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Constructors. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -80,14 +77,14 @@ /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Interface. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ public void serve(SchedulerFactory schedFact, boolean console) - throws Exception { + throws Exception { sched = schedFact.getScheduler(); sched.start(); @@ -125,111 +122,27 @@ /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * SchedulerListener Interface. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** *

- * Called by the {@link Scheduler} when a {@link org.quartz.JobDetail} - * is scheduled. - *

- */ - public void jobScheduled(Trigger trigger) { - } - - /** - *

- * Called by the {@link Scheduler} when a {@link org.quartz.JobDetail} - * is unscheduled. - *

- */ - public void jobUnscheduled(String triggerName, String triggerGroup) { - } - - /** - *

- * Called by the {@link Scheduler} when a {@link Trigger} - * has reached the condition in which it will never fire again. - *

- */ - public void triggerFinalized(Trigger trigger) { - } - - /** - *

- * Called by the {@link Scheduler} when a {@link Trigger} - * or group of {@link Trigger}s has been paused. - *

- * - *

- * If a group was paused, then the triggerName parameter - * will be null. - *

- */ - public void triggersPaused(String triggerName, String triggerGroup) { - } - - /** - *

- * Called by the {@link Scheduler} when a {@link Trigger} - * or group of {@link Trigger}s has been un-paused. - *

- * - *

- * If a group was resumed, then the triggerName parameter - * will be null. - *

- */ - public void triggersResumed(String triggerName, String triggerGroup) { - } - - /** - *

- * Called by the {@link Scheduler} when a {@link org.quartz.JobDetail} - * or group of {@link org.quartz.JobDetail}s has been - * paused. - *

- * - *

- * If a group was paused, then the jobName parameter will be - * null. - *

- */ - public void jobsPaused(String jobName, String jobGroup) { - } - - /** - *

- * Called by the {@link Scheduler} when a {@link org.quartz.JobDetail} - * or group of {@link org.quartz.JobDetail}s has been - * un-paused. - *

- * - *

- * If a group was paused, then the jobName parameter will be - * null. - *

- */ - public void jobsResumed(String jobName, String jobGroup) { - } - - /** - *

* Called by the {@link Scheduler} when a serious error has * occured within the scheduler - such as repeated failures in the JobStore, * or the inability to instantiate a Job instance when its * Trigger has fired. *

- * + * *

* The getErrorCode() method of the given SchedulerException * can be used to determine more specific information about the type of * error that was encountered. *

*/ + @Override public void schedulerError(String msg, SchedulerException cause) { System.err.println("*** " + msg); cause.printStackTrace(); @@ -241,16 +154,17 @@ * that it has shutdown. *

*/ + @Override public void schedulerShutdown() { System.out.println("\n*** The scheduler is now shutdown."); sched = null; } /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Main Method. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -266,11 +180,12 @@ try { QuartzServer server = new QuartzServer(); - if (args.length == 0) server.serve( + if (args.length == 0) { + server.serve( new org.quartz.impl.StdSchedulerFactory(), false); - else if (args.length == 1 && args[0].equalsIgnoreCase("console")) server - .serve(new org.quartz.impl.StdSchedulerFactory(), true); - else { + } else if (args.length == 1 && args[0].equalsIgnoreCase("console")) { + server.serve(new org.quartz.impl.StdSchedulerFactory(), true); + } else { System.err.println("\nUsage: QuartzServer [console]"); } } catch (Exception e) { Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/RemoteMBeanScheduler.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/impl/RemoteScheduler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/RemoteScheduler.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/RemoteScheduler.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/RemoteScheduler.java 15 Dec 2014 10:09:52 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,32 +15,32 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.util.Date; import java.util.List; +import java.util.Map; import java.util.Set; import org.quartz.Calendar; import org.quartz.JobDataMap; import org.quartz.JobDetail; -import org.quartz.JobListener; +import org.quartz.JobExecutionContext; +import org.quartz.JobKey; +import org.quartz.ListenerManager; import org.quartz.Scheduler; import org.quartz.SchedulerContext; import org.quartz.SchedulerException; -import org.quartz.SchedulerListener; import org.quartz.SchedulerMetaData; import org.quartz.Trigger; -import org.quartz.TriggerListener; +import org.quartz.TriggerKey; import org.quartz.UnableToInterruptJobException; +import org.quartz.Trigger.TriggerState; import org.quartz.core.RemotableQuartzScheduler; -import org.quartz.core.SchedulingContext; +import org.quartz.impl.matchers.GroupMatcher; import org.quartz.spi.JobFactory; /** @@ -52,7 +52,6 @@ * * @see org.quartz.Scheduler * @see org.quartz.core.QuartzScheduler - * @see org.quartz.core.SchedulingContext * * @author James House */ @@ -68,8 +67,6 @@ private RemotableQuartzScheduler rsched; - private SchedulingContext schedCtxt; - private String schedId; private String rmiHost; @@ -91,10 +88,7 @@ * SchedulingContext. *

*/ - public RemoteScheduler(SchedulingContext schedCtxt, String schedId, - String host, int port) { - - this.schedCtxt = schedCtxt; + public RemoteScheduler(String schedId, String host, int port) { this.schedId = schedId; this.rmiHost = host; this.rmiPort = port; @@ -109,8 +103,10 @@ */ protected RemotableQuartzScheduler getRemoteScheduler() - throws SchedulerException { - if (rsched != null) return rsched; + throws SchedulerException { + if (rsched != null) { + return rsched; + } try { Registry registry = LocateRegistry.getRegistry(rmiHost, rmiPort); @@ -121,8 +117,6 @@ SchedulerException initException = new SchedulerException( "Could not get handle to remote scheduler: " + e.getMessage(), e); - initException - .setErrorCode(SchedulerException.ERR_COMMUNICATION_FAILURE); throw initException; } @@ -133,7 +127,6 @@ Exception cause) { rsched = null; SchedulerException ex = new SchedulerException(msg, cause); - ex.setErrorCode(SchedulerException.ERR_COMMUNICATION_FAILURE); return ex; } @@ -169,12 +162,11 @@ try { RemotableQuartzScheduler sched = getRemoteScheduler(); return new SchedulerMetaData(getSchedulerName(), - getSchedulerInstanceId(), getClass(), true, sched - .runningSince() != null, isPaused(), isShutdown(), - sched.runningSince(), sched.numJobsExecuted(), sched - .getJobStoreClass(), sched.supportsPersistence(), - sched.getThreadPoolClass(), sched.getThreadPoolSize(), - sched.getVersion()); + getSchedulerInstanceId(), getClass(), true, isStarted(), + isInStandbyMode(), isShutdown(), sched.runningSince(), + sched.numJobsExecuted(), sched.getJobStoreClass(), + sched.supportsPersistence(), sched.isClustered(), sched.getThreadPoolClass(), + sched.getThreadPoolSize(), sched.getVersion()); } catch (RemoteException re) { throw invalidateHandleCreateException( @@ -222,6 +214,20 @@ * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ + public void startDelayed(int seconds) throws SchedulerException { + try { + getRemoteScheduler().startDelayed(seconds); + } catch (RemoteException re) { + throw invalidateHandleCreateException( + "Error communicating with remote scheduler.", re); + } + } + + /** + *

+ * Calls the equivalent method on the 'proxied' QuartzScheduler. + *

+ */ public void standby() throws SchedulerException { try { getRemoteScheduler().standby(); @@ -232,12 +238,27 @@ } /** - * @see org.quartz.Scheduler#pause() - * @deprecated - */ - public void pause() throws SchedulerException { - this.standby(); - } + * Whether the scheduler has been started. + * + *

+ * Note: This only reflects whether {@link #start()} has ever + * been called on this Scheduler, so it will return true even + * if the Scheduler is currently in standby mode or has been + * since shutdown. + *

+ * + * @see #start() + * @see #isShutdown() + * @see #isInStandbyMode() + */ + public boolean isStarted() throws SchedulerException { + try { + return (getRemoteScheduler().runningSince() != null); + } catch (RemoteException re) { + throw invalidateHandleCreateException( + "Error communicating with remote scheduler.", re); + } + } /** *

@@ -253,17 +274,18 @@ } } - public boolean isPaused() throws SchedulerException { - return this.isInStandbyMode(); - } /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ public void shutdown() throws SchedulerException { try { + String schedulerName = getSchedulerName(); + getRemoteScheduler().shutdown(); + + SchedulerRepository.getInstance().remove(schedulerName); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -276,9 +298,13 @@ *

*/ public void shutdown(boolean waitForJobsToComplete) - throws SchedulerException { + throws SchedulerException { try { + String schedulerName = getSchedulerName(); + getRemoteScheduler().shutdown(waitForJobsToComplete); + + SchedulerRepository.getInstance().remove(schedulerName); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -304,7 +330,7 @@ * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public List getCurrentlyExecutingJobs() throws SchedulerException { + public List getCurrentlyExecutingJobs() throws SchedulerException { try { return getRemoteScheduler().getCurrentlyExecutingJobs(); } catch (RemoteException re) { @@ -321,15 +347,13 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ public Date scheduleJob(JobDetail jobDetail, Trigger trigger) - throws SchedulerException { + throws SchedulerException { try { - return getRemoteScheduler().scheduleJob(schedCtxt, jobDetail, + return getRemoteScheduler().scheduleJob(jobDetail, trigger); } catch (RemoteException re) { throw invalidateHandleCreateException( @@ -339,14 +363,12 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ public Date scheduleJob(Trigger trigger) throws SchedulerException { try { - return getRemoteScheduler().scheduleJob(schedCtxt, trigger); + return getRemoteScheduler().scheduleJob(trigger); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -355,51 +377,60 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ public void addJob(JobDetail jobDetail, boolean replace) - throws SchedulerException { + throws SchedulerException { try { - getRemoteScheduler().addJob(schedCtxt, jobDetail, replace); + getRemoteScheduler().addJob(jobDetail, replace); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); } } - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. - *

- */ - public boolean deleteJob(String jobName, String groupName) + public void addJob(JobDetail jobDetail, boolean replace, boolean storeNonDurableWhileAwaitingScheduling) throws SchedulerException { try { - return getRemoteScheduler() - .deleteJob(schedCtxt, jobName, groupName); + getRemoteScheduler().addJob(jobDetail, replace, storeNonDurableWhileAwaitingScheduling); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); } } - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. - *

- */ - public boolean unscheduleJob(String triggerName, String groupName) + public boolean deleteJobs(List jobKeys) throws SchedulerException { + try { + return getRemoteScheduler().deleteJobs(jobKeys); + } catch (RemoteException re) { + throw invalidateHandleCreateException( + "Error communicating with remote scheduler.", re); + } + } + + public void scheduleJobs(Map> triggersAndJobs, boolean replace) throws SchedulerException { + try { + getRemoteScheduler().scheduleJobs(triggersAndJobs, replace); + } catch (RemoteException re) { + throw invalidateHandleCreateException( + "Error communicating with remote scheduler.", re); + } + } + + public void scheduleJob(JobDetail jobDetail, Set triggersForJob, boolean replace) throws SchedulerException { + try { + getRemoteScheduler().scheduleJob(jobDetail, triggersForJob, replace); + } catch (RemoteException re) { + throw invalidateHandleCreateException( + "Error communicating with remote scheduler.", re); + } + } + + public boolean unscheduleJobs(List triggerKeys) throws SchedulerException { try { - return getRemoteScheduler().unscheduleJob(schedCtxt, triggerName, - groupName); + return getRemoteScheduler().unscheduleJobs(triggerKeys); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -408,76 +439,71 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public Date rescheduleJob(String triggerName, - String groupName, Trigger newTrigger) throws SchedulerException { + public boolean deleteJob(JobKey jobKey) + throws SchedulerException { try { - return getRemoteScheduler().rescheduleJob(schedCtxt, triggerName, - groupName, newTrigger); + return getRemoteScheduler() + .deleteJob(jobKey); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); } } - - + /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void triggerJob(String jobName, String groupName) - throws SchedulerException { - triggerJob(jobName, groupName, null); + public boolean unscheduleJob(TriggerKey triggerKey) + throws SchedulerException { + try { + return getRemoteScheduler().unscheduleJob(triggerKey); + } catch (RemoteException re) { + throw invalidateHandleCreateException( + "Error communicating with remote scheduler.", re); + } } - + /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void triggerJob(String jobName, String groupName, JobDataMap data) - throws SchedulerException { + public Date rescheduleJob(TriggerKey triggerKey, + Trigger newTrigger) throws SchedulerException { try { - getRemoteScheduler().triggerJob(schedCtxt, jobName, groupName, data); + return getRemoteScheduler().rescheduleJob(triggerKey, + newTrigger); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); } } - + + /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void triggerJobWithVolatileTrigger(String jobName, String groupName) + public void triggerJob(JobKey jobKey) throws SchedulerException { - triggerJobWithVolatileTrigger(jobName, groupName, null); + triggerJob(jobKey, null); } /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void triggerJobWithVolatileTrigger(String jobName, String groupName, JobDataMap data) - throws SchedulerException { + public void triggerJob(JobKey jobKey, JobDataMap data) + throws SchedulerException { try { - getRemoteScheduler().triggerJobWithVolatileTrigger(schedCtxt, - jobName, groupName, data); + getRemoteScheduler().triggerJob(jobKey, data); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -486,16 +512,14 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void pauseTrigger(String triggerName, String groupName) - throws SchedulerException { + public void pauseTrigger(TriggerKey triggerKey) + throws SchedulerException { try { getRemoteScheduler() - .pauseTrigger(schedCtxt, triggerName, groupName); + .pauseTrigger(triggerKey); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -504,14 +528,12 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void pauseTriggerGroup(String groupName) throws SchedulerException { + public void pauseTriggers(GroupMatcher matcher) throws SchedulerException { try { - getRemoteScheduler().pauseTriggerGroup(schedCtxt, groupName); + getRemoteScheduler().pauseTriggers(matcher); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -520,15 +542,13 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void pauseJob(String jobName, String groupName) - throws SchedulerException { + public void pauseJob(JobKey jobKey) + throws SchedulerException { try { - getRemoteScheduler().pauseJob(schedCtxt, jobName, groupName); + getRemoteScheduler().pauseJob(jobKey); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -537,14 +557,12 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void pauseJobGroup(String groupName) throws SchedulerException { + public void pauseJobs(GroupMatcher matcher) throws SchedulerException { try { - getRemoteScheduler().pauseJobGroup(schedCtxt, groupName); + getRemoteScheduler().pauseJobs(matcher); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -553,16 +571,13 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void resumeTrigger(String triggerName, String groupName) - throws SchedulerException { + public void resumeTrigger(TriggerKey triggerKey) + throws SchedulerException { try { - getRemoteScheduler().resumeTrigger(schedCtxt, triggerName, - groupName); + getRemoteScheduler().resumeTrigger(triggerKey); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -571,14 +586,12 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void resumeTriggerGroup(String groupName) throws SchedulerException { + public void resumeTriggers(GroupMatcher matcher) throws SchedulerException { try { - getRemoteScheduler().resumeTriggerGroup(schedCtxt, groupName); + getRemoteScheduler().resumeTriggers(matcher); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -587,15 +600,13 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void resumeJob(String jobName, String groupName) - throws SchedulerException { + public void resumeJob(JobKey jobKey) + throws SchedulerException { try { - getRemoteScheduler().resumeJob(schedCtxt, jobName, groupName); + getRemoteScheduler().resumeJob(jobKey); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -604,14 +615,12 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void resumeJobGroup(String groupName) throws SchedulerException { + public void resumeJobs(GroupMatcher matcher) throws SchedulerException { try { - getRemoteScheduler().resumeJobGroup(schedCtxt, groupName); + getRemoteScheduler().resumeJobs(matcher); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -620,14 +629,12 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ public void pauseAll() throws SchedulerException { try { - getRemoteScheduler().pauseAll(schedCtxt); + getRemoteScheduler().pauseAll(); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -636,14 +643,12 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ public void resumeAll() throws SchedulerException { try { - getRemoteScheduler().resumeAll(schedCtxt); + getRemoteScheduler().resumeAll(); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -652,14 +657,12 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public String[] getJobGroupNames() throws SchedulerException { + public List getJobGroupNames() throws SchedulerException { try { - return getRemoteScheduler().getJobGroupNames(schedCtxt); + return getRemoteScheduler().getJobGroupNames(); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -668,14 +671,12 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public String[] getJobNames(String groupName) throws SchedulerException { + public Set getJobKeys(GroupMatcher matcher) throws SchedulerException { try { - return getRemoteScheduler().getJobNames(schedCtxt, groupName); + return getRemoteScheduler().getJobKeys(matcher); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -684,16 +685,13 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public Trigger[] getTriggersOfJob(String jobName, String groupName) - throws SchedulerException { + public List getTriggersOfJob(JobKey jobKey) + throws SchedulerException { try { - return getRemoteScheduler().getTriggersOfJob(schedCtxt, jobName, - groupName); + return getRemoteScheduler().getTriggersOfJob(jobKey); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -702,14 +700,12 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public String[] getTriggerGroupNames() throws SchedulerException { + public List getTriggerGroupNames() throws SchedulerException { try { - return getRemoteScheduler().getTriggerGroupNames(schedCtxt); + return getRemoteScheduler().getTriggerGroupNames(); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -718,14 +714,12 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public String[] getTriggerNames(String groupName) throws SchedulerException { + public Set getTriggerKeys(GroupMatcher matcher) throws SchedulerException { try { - return getRemoteScheduler().getTriggerNames(schedCtxt, groupName); + return getRemoteScheduler().getTriggerKeys(matcher); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -734,16 +728,13 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public JobDetail getJobDetail(String jobName, String jobGroup) - throws SchedulerException { + public JobDetail getJobDetail(JobKey jobKey) + throws SchedulerException { try { - return getRemoteScheduler().getJobDetail(schedCtxt, jobName, - jobGroup); + return getRemoteScheduler().getJobDetail(jobKey); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -752,68 +743,55 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public Trigger getTrigger(String triggerName, String triggerGroup) - throws SchedulerException { + public boolean checkExists(JobKey jobKey) throws SchedulerException { try { - return getRemoteScheduler().getTrigger(schedCtxt, triggerName, - triggerGroup); + return getRemoteScheduler().checkExists(jobKey); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); } } - + /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public int getTriggerState(String triggerName, String triggerGroup) - throws SchedulerException { + public boolean checkExists(TriggerKey triggerKey) throws SchedulerException { try { - return getRemoteScheduler().getTriggerState(schedCtxt, triggerName, - triggerGroup); + return getRemoteScheduler().checkExists(triggerKey); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); } } - + /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers) - throws SchedulerException { + public void clear() throws SchedulerException { try { - getRemoteScheduler().addCalendar(schedCtxt, calName, calendar, - replace, updateTriggers); + getRemoteScheduler().clear(); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); } } - + /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public boolean deleteCalendar(String calName) throws SchedulerException { + public Trigger getTrigger(TriggerKey triggerKey) + throws SchedulerException { try { - return getRemoteScheduler().deleteCalendar(schedCtxt, calName); + return getRemoteScheduler().getTrigger(triggerKey); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -822,14 +800,13 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public Calendar getCalendar(String calName) throws SchedulerException { + public TriggerState getTriggerState(TriggerKey triggerKey) + throws SchedulerException { try { - return getRemoteScheduler().getCalendar(schedCtxt, calName); + return getRemoteScheduler().getTriggerState(triggerKey); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); @@ -838,240 +815,104 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public String[] getCalendarNames() throws SchedulerException { + public void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers) + throws SchedulerException { try { - return getRemoteScheduler().getCalendarNames(schedCtxt); + getRemoteScheduler().addCalendar(calName, calendar, + replace, updateTriggers); } catch (RemoteException re) { throw invalidateHandleCreateException( "Error communicating with remote scheduler.", re); } } - /////////////////////////////////////////////////////////////////////////// - /// - /// Listener-related Methods - /// - /////////////////////////////////////////////////////////////////////////// - /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void addGlobalJobListener(JobListener jobListener) - throws SchedulerException { - throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); + public boolean deleteCalendar(String calName) throws SchedulerException { + try { + return getRemoteScheduler().deleteCalendar(calName); + } catch (RemoteException re) { + throw invalidateHandleCreateException( + "Error communicating with remote scheduler.", re); + } } /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void addJobListener(JobListener jobListener) - throws SchedulerException { - throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); + public Calendar getCalendar(String calName) throws SchedulerException { + try { + return getRemoteScheduler().getCalendar(calName); + } catch (RemoteException re) { + throw invalidateHandleCreateException( + "Error communicating with remote scheduler.", re); + } } /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public boolean removeGlobalJobListener(JobListener jobListener) - throws SchedulerException { - throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); + public List getCalendarNames() throws SchedulerException { + try { + return getRemoteScheduler().getCalendarNames(); + } catch (RemoteException re) { + throw invalidateHandleCreateException( + "Error communicating with remote scheduler.", re); + } } - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler. - *

+ /** + * @see org.quartz.Scheduler#getPausedTriggerGroups() */ - public boolean removeJobListener(String name) throws SchedulerException { - throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); + public Set getPausedTriggerGroups() throws SchedulerException { + try { + return getRemoteScheduler().getPausedTriggerGroups(); + } catch (RemoteException re) { + throw invalidateHandleCreateException( + "Error communicating with remote scheduler.", re); + } } - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler. - *

- */ - public List getGlobalJobListeners() throws SchedulerException { - throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); - } - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler. - *

- */ - public Set getJobListenerNames() throws SchedulerException { - throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); - } + /////////////////////////////////////////////////////////////////////////// + /// + /// Other Methods + /// + /////////////////////////////////////////////////////////////////////////// - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler. - *

- */ - public JobListener getJobListener(String name) throws SchedulerException { - throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); - } - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler. - *

- */ - public void addGlobalTriggerListener(TriggerListener triggerListener) - throws SchedulerException { + public ListenerManager getListenerManager() throws SchedulerException { throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); + "Operation not supported for remote schedulers."); } /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler. - *

+ * @see org.quartz.Scheduler#interrupt(JobKey) */ - public void addTriggerListener(TriggerListener triggerListener) - throws SchedulerException { - throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); - } - - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler. - *

- */ - public boolean removeGlobalTriggerListener(TriggerListener triggerListener) - throws SchedulerException { - throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); - } - - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler. - *

- */ - public boolean removeTriggerListener(String name) throws SchedulerException { - throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); - } - - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler. - *

- */ - public List getGlobalTriggerListeners() throws SchedulerException { - throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); - } - - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler. - *

- */ - public Set getTriggerListenerNames() throws SchedulerException { - throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); - } - - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler. - *

- */ - public TriggerListener getTriggerListener(String name) - throws SchedulerException { - throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); - } - - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler. - *

- */ - public void addSchedulerListener(SchedulerListener schedulerListener) - throws SchedulerException { - throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); - } - - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler. - *

- */ - public boolean removeSchedulerListener(SchedulerListener schedulerListener) - throws SchedulerException { - throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); - } - - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler. - *

- */ - public List getSchedulerListeners() throws SchedulerException { - throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); - } - - /** - * @see org.quartz.Scheduler#getPausedTriggerGroups() - */ - public Set getPausedTriggerGroups() throws SchedulerException { + public boolean interrupt(JobKey jobKey) throws UnableToInterruptJobException { try { - return getRemoteScheduler().getPausedTriggerGroups(schedCtxt); + return getRemoteScheduler().interrupt(jobKey); } catch (RemoteException re) { - throw invalidateHandleCreateException( - "Error communicating with remote scheduler.", re); + throw new UnableToInterruptJobException(invalidateHandleCreateException( + "Error communicating with remote scheduler.", re)); + } catch (SchedulerException se) { + throw new UnableToInterruptJobException(se); } } - /** - * @see org.quartz.Scheduler#interrupt(java.lang.String, java.lang.String) - */ - public boolean interrupt(String jobName, String groupName) throws UnableToInterruptJobException { + public boolean interrupt(String fireInstanceId) throws UnableToInterruptJobException { try { - return getRemoteScheduler().interrupt(schedCtxt, jobName, groupName); + return getRemoteScheduler().interrupt(fireInstanceId); } catch (RemoteException re) { throw new UnableToInterruptJobException(invalidateHandleCreateException( "Error communicating with remote scheduler.", re)); @@ -1085,7 +926,7 @@ */ public void setJobFactory(JobFactory factory) throws SchedulerException { throw new SchedulerException( - "Operation not supported for remote schedulers.", - SchedulerException.ERR_UNSUPPORTED_FUNCTION_IN_THIS_CONFIGURATION); + "Operation not supported for remote schedulers."); } + } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/SchedulerDetailsSetter.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/impl/SchedulerRepository.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/SchedulerRepository.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/SchedulerRepository.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/SchedulerRepository.java 15 Dec 2014 10:09:52 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl; import java.util.Collection; @@ -45,7 +42,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - private HashMap schedulers; + private HashMap schedulers; private static SchedulerRepository inst; @@ -58,7 +55,7 @@ */ private SchedulerRepository() { - schedulers = new HashMap(); + schedulers = new HashMap(); } /* @@ -70,17 +67,19 @@ */ public static synchronized SchedulerRepository getInstance() { - if (inst == null) inst = new SchedulerRepository(); + if (inst == null) { + inst = new SchedulerRepository(); + } return inst; } public synchronized void bind(Scheduler sched) throws SchedulerException { - if ((Scheduler) schedulers.get(sched.getSchedulerName()) != null) - throw new SchedulerException("Scheduler with name '" - + sched.getSchedulerName() + "' already exists.", - SchedulerException.ERR_BAD_CONFIGURATION); + if ((Scheduler) schedulers.get(sched.getSchedulerName()) != null) { + throw new SchedulerException("Scheduler with name '" + + sched.getSchedulerName() + "' already exists."); + } schedulers.put(sched.getSchedulerName(), sched); } @@ -90,10 +89,10 @@ } public synchronized Scheduler lookup(String schedName) { - return (Scheduler) schedulers.get(schedName); + return schedulers.get(schedName); } - public synchronized Collection lookupAll() { + public synchronized Collection lookupAll() { return java.util.Collections .unmodifiableCollection(schedulers.values()); } Index: 3rdParty_sources/quartz/org/quartz/impl/StdJobRunShellFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/StdJobRunShellFactory.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/StdJobRunShellFactory.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/StdJobRunShellFactory.java 15 Dec 2014 10:09:53 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,16 +15,13 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.core.JobRunShell; import org.quartz.core.JobRunShellFactory; -import org.quartz.core.SchedulingContext; +import org.quartz.spi.TriggerFiredBundle; /** *

@@ -33,11 +30,6 @@ * instance. *

* - *

- * This implementation does not re-use any objects, it simply makes a new - * JobRunShell each time borrowJobRunShell() is called. - *

- * * @author James House */ public class StdJobRunShellFactory implements JobRunShellFactory { @@ -51,8 +43,6 @@ private Scheduler scheduler; - private SchedulingContext schedCtxt; - /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -65,14 +55,11 @@ *

* Initialize the factory, providing a handle to the Scheduler * that should be made available within the JobRunShell and - * the JobExecutionCOntext s within it, and a handle to the - * SchedulingContext that the shell will use in its own - * operations with the JobStore. + * the JobExecutionContext s within it. *

*/ - public void initialize(Scheduler scheduler, SchedulingContext schedCtxt) { - this.scheduler = scheduler; - this.schedCtxt = schedCtxt; + public void initialize(Scheduler sched) { + this.scheduler = sched; } /** @@ -82,19 +69,7 @@ * {@link org.quartz.core.JobRunShell}. *

*/ - public JobRunShell borrowJobRunShell() throws SchedulerException { - return new JobRunShell(this, scheduler, schedCtxt); + public JobRunShell createJobRunShell(TriggerFiredBundle bndle) throws SchedulerException { + return new JobRunShell(scheduler, bndle); } - - /** - *

- * Called by the {@link org.quartz.core.QuartzSchedulerThread} - * to return instances of - * {@link org.quartz.core.JobRunShell}. - *

- */ - public void returnJobRunShell(JobRunShell jobRunShell) { - jobRunShell.passivate(); - } - } Index: 3rdParty_sources/quartz/org/quartz/impl/StdScheduler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/StdScheduler.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/StdScheduler.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/StdScheduler.java 15 Dec 2014 10:09:52 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,29 +15,29 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl; import java.util.Date; import java.util.List; +import java.util.Map; import java.util.Set; import org.quartz.Calendar; import org.quartz.JobDataMap; import org.quartz.JobDetail; -import org.quartz.JobListener; +import org.quartz.JobExecutionContext; +import org.quartz.JobKey; +import org.quartz.ListenerManager; import org.quartz.Scheduler; import org.quartz.SchedulerContext; import org.quartz.SchedulerException; -import org.quartz.SchedulerListener; import org.quartz.SchedulerMetaData; import org.quartz.Trigger; -import org.quartz.TriggerListener; +import org.quartz.TriggerKey; import org.quartz.UnableToInterruptJobException; +import org.quartz.Trigger.TriggerState; import org.quartz.core.QuartzScheduler; -import org.quartz.core.SchedulingContext; +import org.quartz.impl.matchers.GroupMatcher; import org.quartz.spi.JobFactory; /** @@ -49,8 +49,7 @@ * * @see org.quartz.Scheduler * @see org.quartz.core.QuartzScheduler - * @see org.quartz.core.SchedulingContext - * + * * @author James House */ public class StdScheduler implements Scheduler { @@ -65,8 +64,6 @@ private QuartzScheduler sched; - private SchedulingContext schedCtxt; - /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -81,9 +78,8 @@ * QuartzScheduler instance, and with the given SchedulingContext. *

*/ - public StdScheduler(QuartzScheduler sched, SchedulingContext schedCtxt) { + public StdScheduler(QuartzScheduler sched) { this.sched = sched; - this.schedCtxt = schedCtxt; } /* @@ -114,12 +110,11 @@ public SchedulerMetaData getMetaData() { return new SchedulerMetaData(getSchedulerName(), - getSchedulerInstanceId(), getClass(), false, sched - .runningSince() != null, isPaused(), isShutdown(), - sched.runningSince(), sched.numJobsExecuted(), sched - .getJobStoreClass(), sched.supportsPersistence(), sched - .getThreadPoolClass(), sched.getThreadPoolSize(), sched - .getVersion()); + getSchedulerInstanceId(), getClass(), false, isStarted(), + isInStandbyMode(), isShutdown(), sched.runningSince(), + sched.numJobsExecuted(), sched.getJobStoreClass(), + sched.supportsPersistence(), sched.isClustered(), sched.getThreadPoolClass(), + sched.getThreadPoolSize(), sched.getVersion()); } @@ -151,14 +146,12 @@ *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

- * - * @deprecated - * @see standby() */ - public void pause() { - this.standby(); + public void startDelayed(int seconds) throws SchedulerException { + sched.startDelayed(seconds); } - + + /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. @@ -169,7 +162,25 @@ } /** + * Whether the scheduler has been started. + * *

+ * Note: This only reflects whether {@link #start()} has ever + * been called on this Scheduler, so it will return true even + * if the Scheduler is currently in standby mode or has been + * since shutdown. + *

+ * + * @see #start() + * @see #isShutdown() + * @see #isInStandbyMode() + */ + public boolean isStarted() { + return (sched.runningSince() != null); + } + + /** + *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ @@ -178,13 +189,6 @@ } /** - * @deprecated - */ - public boolean isPaused() { - return isInStandbyMode(); - } - - /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

@@ -216,7 +220,7 @@ * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public List getCurrentlyExecutingJobs() { + public List getCurrentlyExecutingJobs() { return sched.getCurrentlyExecutingJobs(); } @@ -228,549 +232,377 @@ /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public Date scheduleJob(JobDetail jobDetail, Trigger trigger) - throws SchedulerException { - return sched.scheduleJob(schedCtxt, jobDetail, trigger); + public void clear() throws SchedulerException { + sched.clear(); } - - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. - *

- */ - public Date scheduleJob(Trigger trigger) throws SchedulerException { - return sched.scheduleJob(schedCtxt, trigger); - } - - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. - *

- */ - public void addJob(JobDetail jobDetail, boolean replace) - throws SchedulerException { - sched.addJob(schedCtxt, jobDetail, replace); - } - - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. - *

- */ - public boolean deleteJob(String jobName, String groupName) - throws SchedulerException { - return sched.deleteJob(schedCtxt, jobName, groupName); - } - - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. - *

- */ - public boolean unscheduleJob(String triggerName, String groupName) - throws SchedulerException { - return sched.unscheduleJob(schedCtxt, triggerName, groupName); - } /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public Date rescheduleJob(String triggerName, - String groupName, Trigger newTrigger) throws SchedulerException { - return sched.rescheduleJob(schedCtxt, triggerName, groupName, newTrigger); + public Date scheduleJob(JobDetail jobDetail, Trigger trigger) + throws SchedulerException { + return sched.scheduleJob(jobDetail, trigger); } /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void triggerJob(String jobName, String groupName) - throws SchedulerException { - triggerJob(jobName, groupName, null); + public Date scheduleJob(Trigger trigger) throws SchedulerException { + return sched.scheduleJob(trigger); } - - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. - *

- */ - public void triggerJob(String jobName, String groupName, JobDataMap data) - throws SchedulerException { - sched.triggerJob(schedCtxt, jobName, groupName, data); - } /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void triggerJobWithVolatileTrigger(String jobName, String groupName) - throws SchedulerException { - triggerJobWithVolatileTrigger(jobName, groupName, null); + public void addJob(JobDetail jobDetail, boolean replace) + throws SchedulerException { + sched.addJob(jobDetail, replace); } - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. - *

- */ - public void triggerJobWithVolatileTrigger(String jobName, String groupName, JobDataMap data) + public void addJob(JobDetail jobDetail, boolean replace, boolean storeNonDurableWhileAwaitingScheduling) throws SchedulerException { - sched.triggerJobWithVolatileTrigger(schedCtxt, jobName, groupName, data); + sched.addJob(jobDetail, replace, storeNonDurableWhileAwaitingScheduling); } - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. - *

- */ - public void pauseTrigger(String triggerName, String groupName) - throws SchedulerException { - sched.pauseTrigger(schedCtxt, triggerName, groupName); - } - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. - *

- */ - public void pauseTriggerGroup(String groupName) throws SchedulerException { - sched.pauseTriggerGroup(schedCtxt, groupName); + public boolean deleteJobs(List jobKeys) throws SchedulerException { + return sched.deleteJobs(jobKeys); } - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. - *

- */ - public void pauseJob(String jobName, String groupName) - throws SchedulerException { - sched.pauseJob(schedCtxt, jobName, groupName); + public void scheduleJobs(Map> triggersAndJobs, boolean replace) throws SchedulerException { + sched.scheduleJobs(triggersAndJobs, replace); } - /** - * @see org.quartz.Scheduler#getPausedTriggerGroups() - */ - public Set getPausedTriggerGroups() throws SchedulerException { - return sched.getPausedTriggerGroups(schedCtxt); + public void scheduleJob(JobDetail jobDetail, Set triggersForJob, boolean replace) throws SchedulerException { + sched.scheduleJob(jobDetail, triggersForJob, replace); } - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. - *

- */ - public void pauseJobGroup(String groupName) throws SchedulerException { - sched.pauseJobGroup(schedCtxt, groupName); - } - - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. - *

- */ - public void resumeTrigger(String triggerName, String groupName) + public boolean unscheduleJobs(List triggerKeys) throws SchedulerException { - sched.resumeTrigger(schedCtxt, triggerName, groupName); - } - + return sched.unscheduleJobs(triggerKeys); + } + /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void resumeTriggerGroup(String groupName) throws SchedulerException { - sched.resumeTriggerGroup(schedCtxt, groupName); + public boolean deleteJob(JobKey jobKey) + throws SchedulerException { + return sched.deleteJob(jobKey); } /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void resumeJob(String jobName, String groupName) - throws SchedulerException { - sched.resumeJob(schedCtxt, jobName, groupName); + public boolean unscheduleJob(TriggerKey triggerKey) + throws SchedulerException { + return sched.unscheduleJob(triggerKey); } - + /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void resumeJobGroup(String groupName) throws SchedulerException { - sched.resumeJobGroup(schedCtxt, groupName); + public Date rescheduleJob(TriggerKey triggerKey, + Trigger newTrigger) throws SchedulerException { + return sched.rescheduleJob(triggerKey, newTrigger); } /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void pauseAll() throws SchedulerException { - sched.pauseAll(schedCtxt); + public void triggerJob(JobKey jobKey) + throws SchedulerException { + triggerJob(jobKey, null); } - + /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void resumeAll() throws SchedulerException { - sched.resumeAll(schedCtxt); + public void triggerJob(JobKey jobKey, JobDataMap data) + throws SchedulerException { + sched.triggerJob(jobKey, data); } /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public String[] getJobGroupNames() throws SchedulerException { - return sched.getJobGroupNames(schedCtxt); + public void pauseTrigger(TriggerKey triggerKey) + throws SchedulerException { + sched.pauseTrigger(triggerKey); } /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public Trigger[] getTriggersOfJob(String jobName, String groupName) - throws SchedulerException { - return sched.getTriggersOfJob(schedCtxt, jobName, groupName); + public void pauseTriggers(GroupMatcher matcher) throws SchedulerException { + sched.pauseTriggers(matcher); } /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public String[] getJobNames(String groupName) throws SchedulerException { - return sched.getJobNames(schedCtxt, groupName); + public void pauseJob(JobKey jobKey) + throws SchedulerException { + sched.pauseJob(jobKey); } - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. - *

+ /** + * @see org.quartz.Scheduler#getPausedTriggerGroups() */ - public String[] getTriggerGroupNames() throws SchedulerException { - return sched.getTriggerGroupNames(schedCtxt); + public Set getPausedTriggerGroups() throws SchedulerException { + return sched.getPausedTriggerGroups(); } - + /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public String[] getTriggerNames(String groupName) throws SchedulerException { - return sched.getTriggerNames(schedCtxt, groupName); + public void pauseJobs(GroupMatcher matcher) throws SchedulerException { + sched.pauseJobs(matcher); } /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public JobDetail getJobDetail(String jobName, String jobGroup) - throws SchedulerException { - return sched.getJobDetail(schedCtxt, jobName, jobGroup); + public void resumeTrigger(TriggerKey triggerKey) + throws SchedulerException { + sched.resumeTrigger(triggerKey); } /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public Trigger getTrigger(String triggerName, String triggerGroup) - throws SchedulerException { - return sched.getTrigger(schedCtxt, triggerName, triggerGroup); + public void resumeTriggers(GroupMatcher matcher) throws SchedulerException { + sched.resumeTriggers(matcher); } /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public int getTriggerState(String triggerName, String triggerGroup) - throws SchedulerException { - return sched.getTriggerState(schedCtxt, triggerName, triggerGroup); + public void resumeJob(JobKey jobKey) + throws SchedulerException { + sched.resumeJob(jobKey); } /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers) - throws SchedulerException { - sched.addCalendar(schedCtxt, calName, calendar, replace, updateTriggers); + public void resumeJobs(GroupMatcher matcher) throws SchedulerException { + sched.resumeJobs(matcher); } /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. + * Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public boolean deleteCalendar(String calName) throws SchedulerException { - return sched.deleteCalendar(schedCtxt, calName); + public void pauseAll() throws SchedulerException { + sched.pauseAll(); } /** *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. - *

- */ - public Calendar getCalendar(String calName) throws SchedulerException { - return sched.getCalendar(schedCtxt, calName); - } - - /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler, - * passing the SchedulingContext associated with this - * instance. - *

- */ - public String[] getCalendarNames() throws SchedulerException { - return sched.getCalendarNames(schedCtxt); - } - - /////////////////////////////////////////////////////////////////////////// - /// - /// Listener-related Methods - /// - /////////////////////////////////////////////////////////////////////////// - - /** - *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void addGlobalJobListener(JobListener jobListener) { - sched.addGlobalJobListener(jobListener); + public void resumeAll() throws SchedulerException { + sched.resumeAll(); } /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void addJobListener(JobListener jobListener) { - sched.addJobListener(jobListener); + public List getJobGroupNames() throws SchedulerException { + return sched.getJobGroupNames(); } /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public boolean removeGlobalJobListener(JobListener jobListener) { - return sched.removeGlobalJobListener(jobListener); + public List getTriggersOfJob(JobKey jobKey) + throws SchedulerException { + return sched.getTriggersOfJob(jobKey); } /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public boolean removeJobListener(String name) { - return sched.removeJobListener(name); + public Set getJobKeys(GroupMatcher matcher) throws SchedulerException { + return sched.getJobKeys(matcher); } /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public List getGlobalJobListeners() { - return sched.getGlobalJobListeners(); + public List getTriggerGroupNames() throws SchedulerException { + return sched.getTriggerGroupNames(); } /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public Set getJobListenerNames() { - return sched.getJobListenerNames(); + public Set getTriggerKeys(GroupMatcher matcher) throws SchedulerException { + return sched.getTriggerKeys(matcher); } /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public JobListener getJobListener(String name) { - return sched.getJobListener(name); + public JobDetail getJobDetail(JobKey jobKey) + throws SchedulerException { + return sched.getJobDetail(jobKey); } /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void addGlobalTriggerListener(TriggerListener triggerListener) { - sched.addGlobalTriggerListener(triggerListener); + public Trigger getTrigger(TriggerKey triggerKey) + throws SchedulerException { + return sched.getTrigger(triggerKey); } /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void addTriggerListener(TriggerListener triggerListener) { - sched.addTriggerListener(triggerListener); + public TriggerState getTriggerState(TriggerKey triggerKey) + throws SchedulerException { + return sched.getTriggerState(triggerKey); } /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public boolean removeGlobalTriggerListener(TriggerListener triggerListener) { - return sched.removeGlobalTriggerListener(triggerListener); + public void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers) + throws SchedulerException { + sched.addCalendar(calName, calendar, replace, updateTriggers); } /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public boolean removeTriggerListener(String name) { - return sched.removeTriggerListener(name); + public boolean deleteCalendar(String calName) throws SchedulerException { + return sched.deleteCalendar(calName); } /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public List getGlobalTriggerListeners() { - return sched.getGlobalTriggerListeners(); + public Calendar getCalendar(String calName) throws SchedulerException { + return sched.getCalendar(calName); } /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public Set getTriggerListenerNames() { - return sched.getTriggerListenerNames(); + public List getCalendarNames() throws SchedulerException { + return sched.getCalendarNames(); } /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public TriggerListener getTriggerListener(String name) { - return sched.getTriggerListener(name); + public boolean checkExists(JobKey jobKey) throws SchedulerException { + return sched.checkExists(jobKey); } - + + /** *

* Calls the equivalent method on the 'proxied' QuartzScheduler. *

*/ - public void addSchedulerListener(SchedulerListener schedulerListener) { - sched.addSchedulerListener(schedulerListener); + public boolean checkExists(TriggerKey triggerKey) throws SchedulerException { + return sched.checkExists(triggerKey); } + /////////////////////////////////////////////////////////////////////////// + /// + /// Other Methods + /// + /////////////////////////////////////////////////////////////////////////// + + + /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler. - *

+ * @see org.quartz.Scheduler#setJobFactory(org.quartz.spi.JobFactory) */ - public boolean removeSchedulerListener(SchedulerListener schedulerListener) { - return sched.removeSchedulerListener(schedulerListener); + public void setJobFactory(JobFactory factory) throws SchedulerException { + sched.setJobFactory(factory); } /** - *

- * Calls the equivalent method on the 'proxied' QuartzScheduler. - *

+ * @see org.quartz.Scheduler#getListenerManager() */ - public List getSchedulerListeners() { - return sched.getSchedulerListeners(); + public ListenerManager getListenerManager() throws SchedulerException { + return sched.getListenerManager(); } - public boolean interrupt(String jobName, String groupName) throws UnableToInterruptJobException { - return sched.interrupt(schedCtxt, jobName, groupName); + public boolean interrupt(JobKey jobKey) throws UnableToInterruptJobException { + return sched.interrupt(jobKey); } - /** - * @see org.quartz.Scheduler#setJobFactory(org.quartz.spi.JobFactory) - */ - public void setJobFactory(JobFactory factory) throws SchedulerException { - sched.setJobFactory(factory); + public boolean interrupt(String fireInstanceId) throws UnableToInterruptJobException { + return sched.interrupt(fireInstanceId); } - + + } Index: 3rdParty_sources/quartz/org/quartz/impl/StdSchedulerFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/StdSchedulerFactory.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/StdSchedulerFactory.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/StdSchedulerFactory.java 15 Dec 2014 10:09:53 -0000 1.1.2.1 @@ -1,23 +1,20 @@ -/* - * Copyright 2004-2005 OpenSymphony - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations +/* + * Copyright 2001-2009 Terracotta, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations * under the License. - * + * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl; import java.beans.BeanInfo; @@ -30,14 +27,12 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; +import java.security.AccessControlException; import java.sql.SQLException; import java.util.Collection; -import java.util.Iterator; import java.util.Locale; import java.util.Properties; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.quartz.JobListener; import org.quartz.Scheduler; import org.quartz.SchedulerConfigException; @@ -47,61 +42,77 @@ import org.quartz.core.JobRunShellFactory; import org.quartz.core.QuartzScheduler; import org.quartz.core.QuartzSchedulerResources; -import org.quartz.core.SchedulingContext; +import org.quartz.ee.jta.JTAAnnotationAwareJobRunShellFactory; import org.quartz.ee.jta.JTAJobRunShellFactory; import org.quartz.ee.jta.UserTransactionHelper; import org.quartz.impl.jdbcjobstore.JobStoreSupport; +import org.quartz.impl.jdbcjobstore.Semaphore; +import org.quartz.impl.jdbcjobstore.TablePrefixAware; +import org.quartz.impl.matchers.EverythingMatcher; +import org.quartz.management.ManagementRESTServiceConfiguration; import org.quartz.simpl.RAMJobStore; import org.quartz.simpl.SimpleThreadPool; import org.quartz.spi.ClassLoadHelper; import org.quartz.spi.InstanceIdGenerator; import org.quartz.spi.JobFactory; import org.quartz.spi.JobStore; import org.quartz.spi.SchedulerPlugin; +import org.quartz.spi.ThreadExecutor; import org.quartz.spi.ThreadPool; import org.quartz.utils.ConnectionProvider; import org.quartz.utils.DBConnectionManager; import org.quartz.utils.JNDIConnectionProvider; import org.quartz.utils.PoolingConnectionProvider; import org.quartz.utils.PropertiesParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** *

* An implementation of {@link org.quartz.SchedulerFactory} that - * does all of it's work of creating a QuartzScheduler instance - * based on the contenents of a Properties file. + * does all of its work of creating a QuartzScheduler instance + * based on the contents of a Properties file. *

- * + * *

* By default a properties file named "quartz.properties" is loaded from the * 'current working directory'. If that fails, then the "quartz.properties" * file located (as a resource) in the org/quartz package is loaded. If you * wish to use a file other than these defaults, you must define the system - * property 'org.quartz.properties' to* point to the file you want. + * property 'org.quartz.properties' to point to the file you want. *

- * + * *

+ * Alternatively, you can explicitly initialize the factory by calling one of + * the initialize(xx) methods before calling getScheduler(). + *

+ * + *

* See the sample properties files that are distributed with Quartz for * information about the various settings available within the file. + * Full configuration documentation can be found at + * http://www.quartz-scheduler.org/docs/index.html *

- * + * *

- * Alternativly, you can explicitly initialize the factory by calling one of - * the initialize(xx) methods before calling getScheduler(). - *

- * - *

* Instances of the specified {@link org.quartz.spi.JobStore}, - * {@link org.quartz.spi.ThreadPool}, classes will be created + * {@link org.quartz.spi.ThreadPool}, and other SPI classes will be created * by name, and then any additional properties specified for them in the config * file will be set on the instance by calling an equivalent 'set' method. For - * example if the properties file contains the property 'org.quartz.jobStore. - * myProp = 10' then after the JobStore class has been instantiated, the method - * 'setMyProp()' will be called on it. Type conversion to primitive Java types - * (int, long, float, double, boolean, and String) are performed before calling - * the propertie's setter method. + * example if the properties file contains the property + * 'org.quartz.jobStore.myProp = 10' then after the JobStore class has been + * instantiated, the method 'setMyProp()' will be called on it. Type conversion + * to primitive Java types (int, long, float, double, boolean, and String) are + * performed before calling the property's setter method. *

* + *

+ * One property can reference another property's value by specifying a value + * following the convention of "$@other.property.name", for example, to reference + * the scheduler's instance name as the value for some other property, you + * would use "$@org.quartz.scheduler.instanceName". + *

+ * * @author James House * @author Anthony Eden * @author Mohammad Rezaei @@ -110,9 +121,9 @@ /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Constants. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -122,9 +133,26 @@ public static final String PROP_SCHED_INSTANCE_ID = "org.quartz.scheduler.instanceId"; - public static final String PROP_SCHED_INSTANCE_ID_GENERATOR_CLASS = "org.quartz.scheduler.instanceIdGenerator.class"; - + public static final String PROP_SCHED_INSTANCE_ID_GENERATOR_PREFIX = "org.quartz.scheduler.instanceIdGenerator"; + + public static final String PROP_SCHED_INSTANCE_ID_GENERATOR_CLASS = + PROP_SCHED_INSTANCE_ID_GENERATOR_PREFIX + ".class"; + public static final String PROP_SCHED_THREAD_NAME = "org.quartz.scheduler.threadName"; + + public static final String PROP_SCHED_SKIP_UPDATE_CHECK = "org.quartz.scheduler.skipUpdateCheck"; + + public static final String PROP_SCHED_BATCH_TIME_WINDOW = "org.quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow"; + + public static final String PROP_SCHED_MAX_BATCH_SIZE = "org.quartz.scheduler.batchTriggerAcquisitionMaxCount"; + + public static final String PROP_SCHED_JMX_EXPORT = "org.quartz.scheduler.jmx.export"; + + public static final String PROP_SCHED_JMX_OBJECT_NAME = "org.quartz.scheduler.jmx.objectName"; + + public static final String PROP_SCHED_JMX_PROXY = "org.quartz.scheduler.jmx.proxy"; + + public static final String PROP_SCHED_JMX_PROXY_CLASS = "org.quartz.scheduler.jmx.proxy.class"; public static final String PROP_SCHED_RMI_EXPORT = "org.quartz.scheduler.rmi.export"; @@ -138,6 +166,8 @@ public static final String PROP_SCHED_RMI_CREATE_REGISTRY = "org.quartz.scheduler.rmi.createRegistry"; + public static final String PROP_SCHED_RMI_BIND_NAME = "org.quartz.scheduler.rmi.bindName"; + public static final String PROP_SCHED_WRAP_JOB_IN_USER_TX = "org.quartz.scheduler.wrapJobExecutionInUserTransaction"; public static final String PROP_SCHED_USER_TX_URL = "org.quartz.scheduler.userTransactionURL"; @@ -146,12 +176,20 @@ public static final String PROP_SCHED_DB_FAILURE_RETRY_INTERVAL = "org.quartz.scheduler.dbFailureRetryInterval"; + public static final String PROP_SCHED_MAKE_SCHEDULER_THREAD_DAEMON = "org.quartz.scheduler.makeSchedulerThreadDaemon"; + + public static final String PROP_SCHED_SCHEDULER_THREADS_INHERIT_CONTEXT_CLASS_LOADER_OF_INITIALIZING_THREAD = "org.quartz.scheduler.threadsInheritContextClassLoaderOfInitializer"; + public static final String PROP_SCHED_CLASS_LOAD_HELPER_CLASS = "org.quartz.scheduler.classLoadHelper.class"; public static final String PROP_SCHED_JOB_FACTORY_CLASS = "org.quartz.scheduler.jobFactory.class"; public static final String PROP_SCHED_JOB_FACTORY_PREFIX = "org.quartz.scheduler.jobFactory"; + public static final String PROP_SCHED_INTERRUPT_JOBS_ON_SHUTDOWN = "org.quartz.scheduler.interruptJobsOnShutdown"; + + public static final String PROP_SCHED_INTERRUPT_JOBS_ON_SHUTDOWN_WITH_WAIT = "org.quartz.scheduler.interruptJobsOnShutdownWithWait"; + public static final String PROP_SCHED_CONTEXT_PREFIX = "org.quartz.context.key"; public static final String PROP_THREAD_POOL_PREFIX = "org.quartz.threadPool"; @@ -160,6 +198,14 @@ public static final String PROP_JOB_STORE_PREFIX = "org.quartz.jobStore"; + public static final String PROP_JOB_STORE_LOCK_HANDLER_PREFIX = PROP_JOB_STORE_PREFIX + ".lockHandler"; + + public static final String PROP_JOB_STORE_LOCK_HANDLER_CLASS = PROP_JOB_STORE_LOCK_HANDLER_PREFIX + ".class"; + + public static final String PROP_TABLE_PREFIX = "tablePrefix"; + + public static final String PROP_SCHED_NAME = "schedName"; + public static final String PROP_JOB_STORE_CLASS = "org.quartz.jobStore.class"; public static final String PROP_JOB_STORE_USE_PROP = "org.quartz.jobStore.useProperties"; @@ -168,16 +214,40 @@ public static final String PROP_CONNECTION_PROVIDER_CLASS = "connectionProvider.class"; + /** + * @deprecated Replaced with {@link PoolingConnectionProvider#DB_DRIVER} + */ + @Deprecated public static final String PROP_DATASOURCE_DRIVER = "driver"; + /** + * @deprecated Replaced with {@link PoolingConnectionProvider#DB_URL} + */ + @Deprecated public static final String PROP_DATASOURCE_URL = "URL"; + /** + * @deprecated Replaced with {@link PoolingConnectionProvider#DB_USER} + */ + @Deprecated public static final String PROP_DATASOURCE_USER = "user"; + /** + * @deprecated Replaced with {@link PoolingConnectionProvider#DB_PASSWORD} + */ + @Deprecated public static final String PROP_DATASOURCE_PASSWORD = "password"; + /** + * @deprecated Replaced with {@link PoolingConnectionProvider#DB_MAX_CONNECTIONS} + */ + @Deprecated public static final String PROP_DATASOURCE_MAX_CONNECTIONS = "maxConnections"; + /** + * @deprecated Replaced with {@link PoolingConnectionProvider#DB_VALIDATION_QUERY} + */ + @Deprecated public static final String PROP_DATASOURCE_VALIDATION_QUERY = "validationQuery"; public static final String PROP_DATASOURCE_JNDI_URL = "jndiURL"; @@ -206,11 +276,21 @@ public static final String AUTO_GENERATE_INSTANCE_ID = "AUTO"; + public static final String PROP_THREAD_EXECUTOR = "org.quartz.threadExecutor"; + + public static final String PROP_THREAD_EXECUTOR_CLASS = "org.quartz.threadExecutor.class"; + + public static final String SYSTEM_PROPERTY_AS_INSTANCE_ID = "SYS_PROP"; + + public static final String MANAGEMENT_REST_SERVICE_ENABLED = "org.quartz.managementRESTService.enabled"; + + public static final String MANAGEMENT_REST_SERVICE_HOST_PORT = "org.quartz.managementRESTService.bind"; + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Data members. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -220,45 +300,63 @@ private PropertiesParser cfg; + private final Logger log = LoggerFactory.getLogger(getClass()); + // private Scheduler scheduler; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Constructors. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + /** + * Create an uninitialized StdSchedulerFactory. + */ public StdSchedulerFactory() { } + /** + * Create a StdSchedulerFactory that has been initialized via + * {@link #initialize(Properties)}. + * + * @see #initialize(Properties) + */ public StdSchedulerFactory(Properties props) throws SchedulerException { initialize(props); } + /** + * Create a StdSchedulerFactory that has been initialized via + * {@link #initialize(String)}. + * + * @see #initialize(String) + */ public StdSchedulerFactory(String fileName) throws SchedulerException { initialize(fileName); } /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Interface. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - public static Log getLog() { - return LogFactory.getLog(StdSchedulerFactory.class); + public Logger getLog() { + return log; } /** *

* Initialize the {@link org.quartz.SchedulerFactory} with - * the contenents of a Properties file. + * the contents of a Properties file and overriding System + * properties. *

- * + * *

* By default a properties file named "quartz.properties" is loaded from * the 'current working directory'. If that fails, then the @@ -267,17 +365,23 @@ * you must define the system property 'org.quartz.properties' to point to * the file you want. *

- * + * *

- * System properties (envrionment variables, and -D definitions on the - * command-line when running the JVM) over-ride any properties in the - * loaded file. + * System properties (environment variables, and -D definitions on the + * command-line when running the JVM) override any properties in the + * loaded file. For this reason, you may want to use a different initialize() + * method if your application security policy prohibits access to + * {@link java.lang.System#getProperties()}. *

*/ public void initialize() throws SchedulerException { // short-circuit if already initialized - if (cfg != null) return; - if (initException != null) throw initException; + if (cfg != null) { + return; + } + if (initException != null) { + throw initException; + } String requestedFile = System.getProperty(PROPERTIES_FILE); String propFileName = requestedFile != null ? requestedFile @@ -286,130 +390,177 @@ Properties props = new Properties(); - if (propFile.exists()) { - try { - if (requestedFile != null) propSrc = "specified file: '" - + requestedFile + "'"; - else - propSrc = "default file in current working dir: 'quartz.properties'"; + InputStream in = null; - props.load(new BufferedInputStream(new FileInputStream( - propFileName))); + try { + if (propFile.exists()) { + try { + if (requestedFile != null) { + propSrc = "specified file: '" + requestedFile + "'"; + } else { + propSrc = "default file in current working dir: 'quartz.properties'"; + } - initialize(overRideWithSysProps(props)); - } catch (IOException ioe) { - initException = new SchedulerException("Properties file: '" - + propFileName + "' could not be read.", ioe); - throw initException; - } - } else if (requestedFile != null) { - InputStream in = - Thread.currentThread().getContextClassLoader().getResourceAsStream(requestedFile); + in = new BufferedInputStream(new FileInputStream(propFileName)); + props.load(in); - if(in == null) { - initException = new SchedulerException("Properties file: '" - + requestedFile + "' could not be found."); - throw initException; - } - - propSrc = "specified file: '" + requestedFile + "' in the class resource path."; - - try { - props.load(new BufferedInputStream(in)); - initialize(overRideWithSysProps(props)); - } catch (IOException ioe) { - initException = new SchedulerException("Properties file: '" - + requestedFile + "' could not be read.", ioe); - throw initException; - } - - } else { - propSrc = "default resource file in Quartz package: 'quartz.properties'"; + } catch (IOException ioe) { + initException = new SchedulerException("Properties file: '" + + propFileName + "' could not be read.", ioe); + throw initException; + } + } else if (requestedFile != null) { + in = + Thread.currentThread().getContextClassLoader().getResourceAsStream(requestedFile); - InputStream in = getClass().getClassLoader().getResourceAsStream( - "quartz.properties"); + if(in == null) { + initException = new SchedulerException("Properties file: '" + + requestedFile + "' could not be found."); + throw initException; + } - if (in == null) - in = getClass().getClassLoader().getResourceAsStream( + propSrc = "specified file: '" + requestedFile + "' in the class resource path."; + + in = new BufferedInputStream(in); + try { + props.load(in); + } catch (IOException ioe) { + initException = new SchedulerException("Properties file: '" + + requestedFile + "' could not be read.", ioe); + throw initException; + } + + } else { + propSrc = "default resource file in Quartz package: 'quartz.properties'"; + + ClassLoader cl = getClass().getClassLoader(); + if(cl == null) + cl = findClassloader(); + if(cl == null) + throw new SchedulerConfigException("Unable to find a class loader on the current thread or class."); + + in = cl.getResourceAsStream( + "quartz.properties"); + + if (in == null) { + in = cl.getResourceAsStream( "/quartz.properties"); - if (in == null) - in = getClass().getClassLoader().getResourceAsStream( + } + if (in == null) { + in = cl.getResourceAsStream( "org/quartz/quartz.properties"); - if (in == null) { - initException = new SchedulerException( - "Default quartz.properties not found in class path"); - throw initException; + } + if (in == null) { + initException = new SchedulerException( + "Default quartz.properties not found in class path"); + throw initException; + } + try { + props.load(in); + } catch (IOException ioe) { + initException = new SchedulerException( + "Resource properties file: 'org/quartz/quartz.properties' " + + "could not be read from the classpath.", ioe); + throw initException; + } } - try { - props.load(in); - } catch (IOException ioe) { - initException = new SchedulerException( - "Resource properties file: 'org/quartz/quartz.properties' " - + "could not be read from the classpath.", ioe); - throw initException; + } finally { + if(in != null) { + try { in.close(); } catch(IOException ignore) { /* ignore */ } } - - initialize(overRideWithSysProps(props)); } + + initialize(overrideWithSysProps(props)); } - private Properties overRideWithSysProps(Properties props) { + /** + * Add all System properties to the given props. Will override + * any properties that already exist in the given props. + */ + private Properties overrideWithSysProps(Properties props) { + Properties sysProps = null; + try { + sysProps = System.getProperties(); + } catch (AccessControlException e) { + getLog().warn( + "Skipping overriding quartz properties with System properties " + + "during initialization because of an AccessControlException. " + + "This is likely due to not having read/write access for " + + "java.util.PropertyPermission as required by java.lang.System.getProperties(). " + + "To resolve this warning, either add this permission to your policy file or " + + "use a non-default version of initialize().", + e); + } - Properties sysProps = System.getProperties(); - props.putAll(sysProps); + if (sysProps != null) { + props.putAll(sysProps); + } return props; } /** *

* Initialize the {@link org.quartz.SchedulerFactory} with - * the contenents of the Properties file with the given + * the contents of the Properties file with the given * name. *

*/ public void initialize(String filename) throws SchedulerException { // short-circuit if already initialized - if (cfg != null) return; - if (initException != null) throw initException; + if (cfg != null) { + return; + } + if (initException != null) { + throw initException; + } + InputStream is = null; Properties props = new Properties(); is = Thread.currentThread().getContextClassLoader().getResourceAsStream(filename); - + try { if(is != null) { is = new BufferedInputStream(is); propSrc = "the specified file : '" + filename + "' from the class resource path."; + } else { + is = new BufferedInputStream(new FileInputStream(filename)); + propSrc = "the specified file : '" + filename + "'"; } - else { - is = new BufferedInputStream(new FileInputStream(filename)); - propSrc = "the specified file : '" + filename + "'"; - } props.load(is); } catch (IOException ioe) { initException = new SchedulerException("Properties file: '" + filename + "' could not be read.", ioe); throw initException; } + finally { + if(is != null) + try { is.close(); } catch(IOException ignore) {} + } initialize(props); } /** *

* Initialize the {@link org.quartz.SchedulerFactory} with - * the contenents of the Properties file opened with the + * the contents of the Properties file opened with the * given InputStream. *

*/ public void initialize(InputStream propertiesStream) - throws SchedulerException { + throws SchedulerException { // short-circuit if already initialized - if (cfg != null) return; - if (initException != null) throw initException; + if (cfg != null) { + return; + } + if (initException != null) { + throw initException; + } + Properties props = new Properties(); if (propertiesStream != null) { @@ -433,39 +584,42 @@ /** *

* Initialize the {@link org.quartz.SchedulerFactory} with - * the contenents of the given Properties object. + * the contents of the given Properties object. *

*/ public void initialize(Properties props) throws SchedulerException { - if (propSrc == null) - propSrc = "an externally provided properties instance."; + if (propSrc == null) { + propSrc = "an externally provided properties instance."; + } this.cfg = new PropertiesParser(props); } - /** - * - */ private Scheduler instantiate() throws SchedulerException { - if (cfg == null) initialize(); + if (cfg == null) { + initialize(); + } - if (initException != null) throw initException; + if (initException != null) { + throw initException; + } JobStore js = null; ThreadPool tp = null; QuartzScheduler qs = null; - SchedulingContext schedCtxt = null; DBConnectionManager dbMgr = null; String instanceIdGeneratorClass = null; Properties tProps = null; String userTXLocation = null; boolean wrapJobInTx = false; boolean autoId = false; long idleWaitTime = -1; - long dbFailureRetry = -1; + long dbFailureRetry = 15000L; // 15 secs String classLoadHelperClass; String jobFactoryClass; + ThreadExecutor threadExecutor; + SchedulerRepository schedRep = SchedulerRepository.getInstance(); // Get Scheduler Properties @@ -476,7 +630,7 @@ String threadName = cfg.getStringProperty(PROP_SCHED_THREAD_NAME, schedName + "_QuartzSchedulerThread"); - + String schedInstId = cfg.getStringProperty(PROP_SCHED_INSTANCE_ID, DEFAULT_INSTANCE_ID); @@ -486,11 +640,17 @@ PROP_SCHED_INSTANCE_ID_GENERATOR_CLASS, "org.quartz.simpl.SimpleInstanceIdGenerator"); } - + else if (schedInstId.equals(SYSTEM_PROPERTY_AS_INSTANCE_ID)) { + autoId = true; + instanceIdGeneratorClass = + "org.quartz.simpl.SystemPropertyInstanceIdGenerator"; + } + userTXLocation = cfg.getStringProperty(PROP_SCHED_USER_TX_URL, userTXLocation); - if (userTXLocation != null && userTXLocation.trim().length() == 0) - userTXLocation = null; + if (userTXLocation != null && userTXLocation.trim().length() == 0) { + userTXLocation = null; + } classLoadHelperClass = cfg.getStringProperty( PROP_SCHED_CLASS_LOAD_HELPER_CLASS, @@ -503,43 +663,72 @@ idleWaitTime = cfg.getLongProperty(PROP_SCHED_IDLE_WAIT_TIME, idleWaitTime); - dbFailureRetry = cfg.getLongProperty( - PROP_SCHED_DB_FAILURE_RETRY_INTERVAL, dbFailureRetry); + if(idleWaitTime > -1 && idleWaitTime < 1000) { + throw new SchedulerException("org.quartz.scheduler.idleWaitTime of less than 1000ms is not legal."); + } + + dbFailureRetry = cfg.getLongProperty(PROP_SCHED_DB_FAILURE_RETRY_INTERVAL, dbFailureRetry); + if (dbFailureRetry < 0) { + throw new SchedulerException(PROP_SCHED_DB_FAILURE_RETRY_INTERVAL + " of less than 0 ms is not legal."); + } - boolean rmiExport = cfg - .getBooleanProperty(PROP_SCHED_RMI_EXPORT, false); + boolean makeSchedulerThreadDaemon = + cfg.getBooleanProperty(PROP_SCHED_MAKE_SCHEDULER_THREAD_DAEMON); + + boolean threadsInheritInitalizersClassLoader = + cfg.getBooleanProperty(PROP_SCHED_SCHEDULER_THREADS_INHERIT_CONTEXT_CLASS_LOADER_OF_INITIALIZING_THREAD); + + boolean skipUpdateCheck = cfg.getBooleanProperty(PROP_SCHED_SKIP_UPDATE_CHECK, false); + long batchTimeWindow = cfg.getLongProperty(PROP_SCHED_BATCH_TIME_WINDOW, 0L); + int maxBatchSize = cfg.getIntProperty(PROP_SCHED_MAX_BATCH_SIZE, 1); + + boolean interruptJobsOnShutdown = cfg.getBooleanProperty(PROP_SCHED_INTERRUPT_JOBS_ON_SHUTDOWN, false); + boolean interruptJobsOnShutdownWithWait = cfg.getBooleanProperty(PROP_SCHED_INTERRUPT_JOBS_ON_SHUTDOWN_WITH_WAIT, false); + + boolean jmxExport = cfg.getBooleanProperty(PROP_SCHED_JMX_EXPORT); + String jmxObjectName = cfg.getStringProperty(PROP_SCHED_JMX_OBJECT_NAME); + + boolean jmxProxy = cfg.getBooleanProperty(PROP_SCHED_JMX_PROXY); + String jmxProxyClass = cfg.getStringProperty(PROP_SCHED_JMX_PROXY_CLASS); + + boolean rmiExport = cfg.getBooleanProperty(PROP_SCHED_RMI_EXPORT, false); boolean rmiProxy = cfg.getBooleanProperty(PROP_SCHED_RMI_PROXY, false); - String rmiHost = cfg - .getStringProperty(PROP_SCHED_RMI_HOST, "localhost"); + String rmiHost = cfg.getStringProperty(PROP_SCHED_RMI_HOST, "localhost"); int rmiPort = cfg.getIntProperty(PROP_SCHED_RMI_PORT, 1099); int rmiServerPort = cfg.getIntProperty(PROP_SCHED_RMI_SERVER_PORT, -1); String rmiCreateRegistry = cfg.getStringProperty( PROP_SCHED_RMI_CREATE_REGISTRY, QuartzSchedulerResources.CREATE_REGISTRY_NEVER); + String rmiBindName = cfg.getStringProperty(PROP_SCHED_RMI_BIND_NAME); + if (jmxProxy && rmiProxy) { + throw new SchedulerConfigException("Cannot proxy both RMI and JMX."); + } + + boolean managementRESTServiceEnabled = cfg.getBooleanProperty(MANAGEMENT_REST_SERVICE_ENABLED, false); + String managementRESTServiceHostAndPort = cfg.getStringProperty(MANAGEMENT_REST_SERVICE_HOST_PORT, "0.0.0.0:9889"); + Properties schedCtxtProps = cfg.getPropertyGroup(PROP_SCHED_CONTEXT_PREFIX, true); // If Proxying to remote scheduler, short-circuit here... // ~~~~~~~~~~~~~~~~~~ if (rmiProxy) { - if (autoId) + if (autoId) { schedInstId = DEFAULT_INSTANCE_ID; - - schedCtxt = new SchedulingContext(); - schedCtxt.setInstanceId(schedInstId); + } - String uid = QuartzSchedulerResources.getUniqueIdentifier( - schedName, schedInstId); + String uid = (rmiBindName == null) ? QuartzSchedulerResources.getUniqueIdentifier( + schedName, schedInstId) : rmiBindName; - RemoteScheduler remoteScheduler = new RemoteScheduler(schedCtxt, - uid, rmiHost, rmiPort); + RemoteScheduler remoteScheduler = new RemoteScheduler(uid, rmiHost, rmiPort); schedRep.bind(remoteScheduler); return remoteScheduler; } + // Create class load helper ClassLoadHelper loadHelper = null; try { @@ -551,6 +740,49 @@ + e.getMessage(), e); } loadHelper.initialize(); + + // If Proxying to remote JMX scheduler, short-circuit here... + // ~~~~~~~~~~~~~~~~~~ + if (jmxProxy) { + if (autoId) { + schedInstId = DEFAULT_INSTANCE_ID; + } + + if (jmxProxyClass == null) { + throw new SchedulerConfigException("No JMX Proxy Scheduler class provided"); + } + + RemoteMBeanScheduler jmxScheduler = null; + try { + jmxScheduler = (RemoteMBeanScheduler)loadHelper.loadClass(jmxProxyClass) + .newInstance(); + } catch (Exception e) { + throw new SchedulerConfigException( + "Unable to instantiate RemoteMBeanScheduler class.", e); + } + + if (jmxObjectName == null) { + jmxObjectName = QuartzSchedulerResources.generateJMXObjectName(schedName, schedInstId); + } + + jmxScheduler.setSchedulerObjectName(jmxObjectName); + + tProps = cfg.getPropertyGroup(PROP_SCHED_JMX_PROXY, true); + try { + setBeanProps(jmxScheduler, tProps); + } catch (Exception e) { + initException = new SchedulerException("RemoteMBeanScheduler class '" + + jmxProxyClass + "' props could not be configured.", e); + throw initException; + } + + jmxScheduler.initialize(); + + schedRep.bind(jmxScheduler); + + return jmxScheduler; + } + JobFactory jobFactory = null; if(jobFactoryClass != null) { @@ -569,12 +801,10 @@ } catch (Exception e) { initException = new SchedulerException("JobFactory class '" + jobFactoryClass + "' props could not be configured.", e); - initException - .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); throw initException; } - } - + } + InstanceIdGenerator instanceIdGenerator = null; if(instanceIdGeneratorClass != null) { try { @@ -585,17 +815,25 @@ "Unable to instantiate InstanceIdGenerator class: " + e.getMessage(), e); } - } - + + tProps = cfg.getPropertyGroup(PROP_SCHED_INSTANCE_ID_GENERATOR_PREFIX, true); + try { + setBeanProps(instanceIdGenerator, tProps); + } catch (Exception e) { + initException = new SchedulerException("InstanceIdGenerator class '" + + instanceIdGeneratorClass + "' props could not be configured.", e); + throw initException; + } + } + // Get ThreadPool Properties // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - String tpClass = cfg.getStringProperty(PROP_THREAD_POOL_CLASS, null); + String tpClass = cfg.getStringProperty(PROP_THREAD_POOL_CLASS, SimpleThreadPool.class.getName()); if (tpClass == null) { initException = new SchedulerException( - "ThreadPool class not specified. ", - SchedulerException.ERR_BAD_CONFIGURATION); + "ThreadPool class not specified. "); throw initException; } @@ -604,8 +842,6 @@ } catch (Exception e) { initException = new SchedulerException("ThreadPool class '" + tpClass + "' could not be instantiated.", e); - initException - .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); throw initException; } tProps = cfg.getPropertyGroup(PROP_THREAD_POOL_PREFIX, true); @@ -614,8 +850,6 @@ } catch (Exception e) { initException = new SchedulerException("ThreadPool class '" + tpClass + "' props could not be configured.", e); - initException - .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); throw initException; } @@ -627,8 +861,7 @@ if (jsClass == null) { initException = new SchedulerException( - "JobStore class not specified. ", - SchedulerException.ERR_BAD_CONFIGURATION); + "JobStore class not specified. "); throw initException; } @@ -637,28 +870,55 @@ } catch (Exception e) { initException = new SchedulerException("JobStore class '" + jsClass + "' could not be instantiated.", e); - initException - .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); throw initException; } - tProps = cfg.getPropertyGroup(PROP_JOB_STORE_PREFIX, true); + + SchedulerDetailsSetter.setDetails(js, schedName, schedInstId); + + tProps = cfg.getPropertyGroup(PROP_JOB_STORE_PREFIX, true, new String[] {PROP_JOB_STORE_LOCK_HANDLER_PREFIX}); try { setBeanProps(js, tProps); } catch (Exception e) { initException = new SchedulerException("JobStore class '" + jsClass + "' props could not be configured.", e); - initException - .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); throw initException; } - if (js instanceof org.quartz.impl.jdbcjobstore.JobStoreSupport) { - ((org.quartz.impl.jdbcjobstore.JobStoreSupport) js) - .setInstanceId(schedInstId); - ((org.quartz.impl.jdbcjobstore.JobStoreSupport) js) - .setInstanceName(schedName); + if (js instanceof JobStoreSupport) { + // Install custom lock handler (Semaphore) + String lockHandlerClass = cfg.getStringProperty(PROP_JOB_STORE_LOCK_HANDLER_CLASS); + if (lockHandlerClass != null) { + try { + Semaphore lockHandler = (Semaphore)loadHelper.loadClass(lockHandlerClass).newInstance(); + + tProps = cfg.getPropertyGroup(PROP_JOB_STORE_LOCK_HANDLER_PREFIX, true); + + // If this lock handler requires the table prefix, add it to its properties. + if (lockHandler instanceof TablePrefixAware) { + tProps.setProperty( + PROP_TABLE_PREFIX, ((JobStoreSupport)js).getTablePrefix()); + tProps.setProperty( + PROP_SCHED_NAME, schedName); + } + + try { + setBeanProps(lockHandler, tProps); + } catch (Exception e) { + initException = new SchedulerException("JobStore LockHandler class '" + lockHandlerClass + + "' props could not be configured.", e); + throw initException; + } + + ((JobStoreSupport)js).setLockHandler(lockHandler); + getLog().info("Using custom data access locking (synchronization): " + lockHandlerClass); + } catch (Exception e) { + initException = new SchedulerException("JobStore LockHandler class '" + lockHandlerClass + + "' could not be instantiated.", e); + throw initException; + } + } } - + // Set up any DataSources // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -677,73 +937,67 @@ } catch (Exception e) { initException = new SchedulerException("ConnectionProvider class '" + cpClass + "' could not be instantiated.", e); - initException - .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); throw initException; } try { // remove the class name, so it isn't attempted to be set pp.getUnderlyingProperties().remove( PROP_CONNECTION_PROVIDER_CLASS); - + setBeanProps(cp, pp.getUnderlyingProperties()); + cp.initialize(); } catch (Exception e) { initException = new SchedulerException("ConnectionProvider class '" + cpClass + "' props could not be configured.", e); - initException - .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); throw initException; } dbMgr = DBConnectionManager.getInstance(); dbMgr.addConnectionProvider(dsNames[i], cp); - } - else { - String dsDriver = pp - .getStringProperty(PROP_DATASOURCE_DRIVER, null); - String dsURL = pp.getStringProperty(PROP_DATASOURCE_URL, null); - boolean dsAlwaysLookup = pp.getBooleanProperty( - PROP_DATASOURCE_JNDI_ALWAYS_LOOKUP, false); - String dsUser = pp.getStringProperty(PROP_DATASOURCE_USER, ""); - String dsPass = pp.getStringProperty(PROP_DATASOURCE_PASSWORD, ""); - int dsCnt = pp.getIntProperty(PROP_DATASOURCE_MAX_CONNECTIONS, 10); - String dsJndi = pp - .getStringProperty(PROP_DATASOURCE_JNDI_URL, null); - String dsJndiInitial = pp.getStringProperty( - PROP_DATASOURCE_JNDI_INITIAL, null); - String dsJndiProvider = pp.getStringProperty( - PROP_DATASOURCE_JNDI_PROVDER, null); - String dsJndiPrincipal = pp.getStringProperty( - PROP_DATASOURCE_JNDI_PRINCIPAL, null); - String dsJndiCredentials = pp.getStringProperty( - PROP_DATASOURCE_JNDI_CREDENTIALS, null); - String dsValidation = pp.getStringProperty( - PROP_DATASOURCE_VALIDATION_QUERY, null); - + } else { + String dsJndi = pp.getStringProperty(PROP_DATASOURCE_JNDI_URL, null); + if (dsJndi != null) { + boolean dsAlwaysLookup = pp.getBooleanProperty( + PROP_DATASOURCE_JNDI_ALWAYS_LOOKUP); + String dsJndiInitial = pp.getStringProperty( + PROP_DATASOURCE_JNDI_INITIAL); + String dsJndiProvider = pp.getStringProperty( + PROP_DATASOURCE_JNDI_PROVDER); + String dsJndiPrincipal = pp.getStringProperty( + PROP_DATASOURCE_JNDI_PRINCIPAL); + String dsJndiCredentials = pp.getStringProperty( + PROP_DATASOURCE_JNDI_CREDENTIALS); Properties props = null; if (null != dsJndiInitial || null != dsJndiProvider || null != dsJndiPrincipal || null != dsJndiCredentials) { props = new Properties(); - if (dsJndiInitial != null) - props.put(PROP_DATASOURCE_JNDI_INITIAL, - dsJndiInitial); - if (dsJndiProvider != null) - props.put(PROP_DATASOURCE_JNDI_PROVDER, - dsJndiProvider); - if (dsJndiPrincipal != null) - props.put(PROP_DATASOURCE_JNDI_PRINCIPAL, - dsJndiPrincipal); - if (dsJndiCredentials != null) - props.put(PROP_DATASOURCE_JNDI_CREDENTIALS, - dsJndiCredentials); + if (dsJndiInitial != null) { + props.put(PROP_DATASOURCE_JNDI_INITIAL, + dsJndiInitial); + } + if (dsJndiProvider != null) { + props.put(PROP_DATASOURCE_JNDI_PROVDER, + dsJndiProvider); + } + if (dsJndiPrincipal != null) { + props.put(PROP_DATASOURCE_JNDI_PRINCIPAL, + dsJndiPrincipal); + } + if (dsJndiCredentials != null) { + props.put(PROP_DATASOURCE_JNDI_CREDENTIALS, + dsJndiCredentials); + } } JNDIConnectionProvider cp = new JNDIConnectionProvider(dsJndi, props, dsAlwaysLookup); dbMgr = DBConnectionManager.getInstance(); dbMgr.addConnectionProvider(dsNames[i], cp); } else { + String dsDriver = pp.getStringProperty(PoolingConnectionProvider.DB_DRIVER); + String dsURL = pp.getStringProperty(PoolingConnectionProvider.DB_URL); + if (dsDriver == null) { initException = new SchedulerException( "Driver not specified for DataSource: " @@ -757,9 +1011,7 @@ throw initException; } try { - PoolingConnectionProvider cp = new PoolingConnectionProvider( - dsDriver, dsURL, dsUser, dsPass, dsCnt, - dsValidation); + PoolingConnectionProvider cp = new PoolingConnectionProvider(pp.getUnderlyingProperties()); dbMgr = DBConnectionManager.getInstance(); dbMgr.addConnectionProvider(dsNames[i], cp); } catch (SQLException sqle) { @@ -769,9 +1021,9 @@ throw initException; } } - + } - + } // Set up any SchedulerPlugins @@ -788,8 +1040,7 @@ if (plugInClass == null) { initException = new SchedulerException( "SchedulerPlugin class not specified for plugin '" - + pluginNames[i] + "'", - SchedulerException.ERR_BAD_CONFIGURATION); + + pluginNames[i] + "'"); throw initException; } SchedulerPlugin plugin = null; @@ -800,8 +1051,6 @@ initException = new SchedulerException( "SchedulerPlugin class '" + plugInClass + "' could not be instantiated.", e); - initException - .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); throw initException; } try { @@ -810,60 +1059,61 @@ initException = new SchedulerException( "JobStore SchedulerPlugin '" + plugInClass + "' props could not be configured.", e); - initException - .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); throw initException; } + plugins[i] = plugin; } // Set up any JobListeners // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Class[] strArg = new Class[] { String.class }; + Class[] strArg = new Class[] { String.class }; String[] jobListenerNames = cfg.getPropertyGroups(PROP_JOB_LISTENER_PREFIX); JobListener[] jobListeners = new JobListener[jobListenerNames.length]; for (int i = 0; i < jobListenerNames.length; i++) { Properties lp = cfg.getPropertyGroup(PROP_JOB_LISTENER_PREFIX + "." + jobListenerNames[i], true); - + String listenerClass = lp.getProperty(PROP_LISTENER_CLASS, null); if (listenerClass == null) { initException = new SchedulerException( "JobListener class not specified for listener '" - + jobListenerNames[i] + "'", - SchedulerException.ERR_BAD_CONFIGURATION); + + jobListenerNames[i] + "'"); throw initException; } JobListener listener = null; try { - listener = (JobListener) + listener = (JobListener) loadHelper.loadClass(listenerClass).newInstance(); } catch (Exception e) { initException = new SchedulerException( "JobListener class '" + listenerClass + "' could not be instantiated.", e); - initException - .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); throw initException; } try { - Method nameSetter = listener.getClass().getMethod("setName", strArg); - if(nameSetter != null) + Method nameSetter = null; + try { + nameSetter = listener.getClass().getMethod("setName", strArg); + } + catch(NoSuchMethodException ignore) { + /* do nothing */ + } + if(nameSetter != null) { nameSetter.invoke(listener, new Object[] {jobListenerNames[i] } ); + } setBeanProps(listener, lp); } catch (Exception e) { initException = new SchedulerException( "JobListener '" + listenerClass + "' props could not be configured.", e); - initException - .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); throw initException; } jobListeners[i] = listener; } - + // Set up any TriggerListeners // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -872,172 +1122,270 @@ for (int i = 0; i < triggerListenerNames.length; i++) { Properties lp = cfg.getPropertyGroup(PROP_TRIGGER_LISTENER_PREFIX + "." + triggerListenerNames[i], true); - + String listenerClass = lp.getProperty(PROP_LISTENER_CLASS, null); if (listenerClass == null) { initException = new SchedulerException( "TriggerListener class not specified for listener '" - + triggerListenerNames[i] + "'", - SchedulerException.ERR_BAD_CONFIGURATION); + + triggerListenerNames[i] + "'"); throw initException; } TriggerListener listener = null; try { - listener = (TriggerListener) + listener = (TriggerListener) loadHelper.loadClass(listenerClass).newInstance(); } catch (Exception e) { initException = new SchedulerException( "TriggerListener class '" + listenerClass + "' could not be instantiated.", e); - initException - .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); throw initException; } try { - Method nameSetter = listener.getClass().getMethod("setName", strArg); - if(nameSetter != null) + Method nameSetter = null; + try { + nameSetter = listener.getClass().getMethod("setName", strArg); + } + catch(NoSuchMethodException ignore) { /* do nothing */ } + if(nameSetter != null) { nameSetter.invoke(listener, new Object[] {triggerListenerNames[i] } ); + } setBeanProps(listener, lp); } catch (Exception e) { initException = new SchedulerException( "TriggerListener '" + listenerClass + "' props could not be configured.", e); - initException - .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); throw initException; } triggerListeners[i] = listener; } - - - // Fire everything up - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - JobRunShellFactory jrsf = null; // Create correct run-shell factory... - UserTransactionHelper userTxHelper = null; + boolean tpInited = false; + boolean qsInited = false; - if (wrapJobInTx) - userTxHelper = new UserTransactionHelper(userTXLocation); - if (wrapJobInTx) jrsf = new JTAJobRunShellFactory(userTxHelper); - else - jrsf = new StdJobRunShellFactory(); + // Get ThreadExecutor Properties + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - if (autoId) { + String threadExecutorClass = cfg.getStringProperty(PROP_THREAD_EXECUTOR_CLASS); + if (threadExecutorClass != null) { + tProps = cfg.getPropertyGroup(PROP_THREAD_EXECUTOR, true); try { - schedInstId = DEFAULT_INSTANCE_ID; - if (js instanceof org.quartz.impl.jdbcjobstore.JobStoreSupport) { - if(((org.quartz.impl.jdbcjobstore.JobStoreSupport) js) - .isClustered()) { - schedInstId = instanceIdGenerator.generateInstanceId(); - } - } + threadExecutor = (ThreadExecutor) loadHelper.loadClass(threadExecutorClass).newInstance(); + log.info("Using custom implementation for ThreadExecutor: " + threadExecutorClass); + + setBeanProps(threadExecutor, tProps); } catch (Exception e) { - getLog().error("Couldn't generate instance Id!", e); - throw new IllegalStateException( - "Cannot run without an instance id."); + initException = new SchedulerException( + "ThreadExecutor class '" + threadExecutorClass + "' could not be instantiated.", e); + throw initException; } + } else { + log.info("Using default implementation for ThreadExecutor"); + threadExecutor = new DefaultThreadExecutor(); } - if (js instanceof JobStoreSupport) { - JobStoreSupport jjs = (JobStoreSupport) js; - jjs.setInstanceId(schedInstId); - jjs.setDbRetryInterval(dbFailureRetry); - } - - QuartzSchedulerResources rsrcs = new QuartzSchedulerResources(); - rsrcs.setName(schedName); - rsrcs.setThreadName(threadName); - rsrcs.setInstanceId(schedInstId); - rsrcs.setJobRunShellFactory(jrsf); - if (rmiExport) { - rsrcs.setRMIRegistryHost(rmiHost); - rsrcs.setRMIRegistryPort(rmiPort); - rsrcs.setRMIServerPort(rmiServerPort); - rsrcs.setRMICreateRegistryStrategy(rmiCreateRegistry); - } - rsrcs.setThreadPool(tp); - if(tp instanceof SimpleThreadPool) - ((SimpleThreadPool)tp).setThreadNamePrefix(schedName + "_Worker"); - tp.initialize(); - - rsrcs.setJobStore(js); + // Fire everything up + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + try { + + + JobRunShellFactory jrsf = null; // Create correct run-shell factory... + + if (userTXLocation != null) { + UserTransactionHelper.setUserTxLocation(userTXLocation); + } + + if (wrapJobInTx) { + jrsf = new JTAJobRunShellFactory(); + } else { + jrsf = new JTAAnnotationAwareJobRunShellFactory(); + } + + if (autoId) { + try { + schedInstId = DEFAULT_INSTANCE_ID; + if (js.isClustered()) { + schedInstId = instanceIdGenerator.generateInstanceId(); + } + } catch (Exception e) { + getLog().error("Couldn't generate instance Id!", e); + throw new IllegalStateException("Cannot run without an instance id."); + } + } - schedCtxt = new SchedulingContext(); - schedCtxt.setInstanceId(rsrcs.getInstanceId()); + if (js.getClass().getName().startsWith("org.terracotta.quartz")) { + try { + String uuid = (String) js.getClass().getMethod("getUUID").invoke(js); + if(schedInstId.equals(DEFAULT_INSTANCE_ID)) { + schedInstId = "TERRACOTTA_CLUSTERED,node=" + uuid; + if (jmxObjectName == null) { + jmxObjectName = QuartzSchedulerResources.generateJMXObjectName(schedName, schedInstId); + } + } else if(jmxObjectName == null) { + jmxObjectName = QuartzSchedulerResources.generateJMXObjectName(schedName, schedInstId + ",node=" + uuid); + } + } catch(Exception e) { + throw new RuntimeException("Problem obtaining node id from TerracottaJobStore.", e); + } - qs = new QuartzScheduler(rsrcs, schedCtxt, idleWaitTime, dbFailureRetry); + if(null == cfg.getStringProperty(PROP_SCHED_JMX_EXPORT)) { + jmxExport = true; + } + } + + if (js instanceof JobStoreSupport) { + JobStoreSupport jjs = (JobStoreSupport)js; + jjs.setDbRetryInterval(dbFailureRetry); + if(threadsInheritInitalizersClassLoader) + jjs.setThreadsInheritInitializersClassLoadContext(threadsInheritInitalizersClassLoader); + + jjs.setThreadExecutor(threadExecutor); + } + + QuartzSchedulerResources rsrcs = new QuartzSchedulerResources(); + rsrcs.setName(schedName); + rsrcs.setThreadName(threadName); + rsrcs.setInstanceId(schedInstId); + rsrcs.setJobRunShellFactory(jrsf); + rsrcs.setMakeSchedulerThreadDaemon(makeSchedulerThreadDaemon); + rsrcs.setThreadsInheritInitializersClassLoadContext(threadsInheritInitalizersClassLoader); + rsrcs.setRunUpdateCheck(!skipUpdateCheck); + rsrcs.setBatchTimeWindow(batchTimeWindow); + rsrcs.setMaxBatchSize(maxBatchSize); + rsrcs.setInterruptJobsOnShutdown(interruptJobsOnShutdown); + rsrcs.setInterruptJobsOnShutdownWithWait(interruptJobsOnShutdownWithWait); + rsrcs.setJMXExport(jmxExport); + rsrcs.setJMXObjectName(jmxObjectName); - // if(usingJSCMT) - // qs.setSignalOnSchedulingChange(false); // TODO: fixed? (don't need - // this any more?) + if (managementRESTServiceEnabled) { + ManagementRESTServiceConfiguration managementRESTServiceConfiguration = new ManagementRESTServiceConfiguration(); + managementRESTServiceConfiguration.setBind(managementRESTServiceHostAndPort); + managementRESTServiceConfiguration.setEnabled(managementRESTServiceEnabled); + rsrcs.setManagementRESTServiceConfiguration(managementRESTServiceConfiguration); + } + + if (rmiExport) { + rsrcs.setRMIRegistryHost(rmiHost); + rsrcs.setRMIRegistryPort(rmiPort); + rsrcs.setRMIServerPort(rmiServerPort); + rsrcs.setRMICreateRegistryStrategy(rmiCreateRegistry); + rsrcs.setRMIBindName(rmiBindName); + } + + SchedulerDetailsSetter.setDetails(tp, schedName, schedInstId); - // Create Scheduler ref... - Scheduler scheduler = instantiate(rsrcs, qs); - - // set job factory if specified - if(jobFactory != null) - qs.setJobFactory(jobFactory); + rsrcs.setThreadExecutor(threadExecutor); + threadExecutor.initialize(); - // add plugins - for (int i = 0; i < plugins.length; i++) { - plugins[i].initialize(pluginNames[i], scheduler); - qs.addSchedulerPlugin(plugins[i]); + rsrcs.setThreadPool(tp); + if(tp instanceof SimpleThreadPool) { + if(threadsInheritInitalizersClassLoader) + ((SimpleThreadPool)tp).setThreadsInheritContextClassLoaderOfInitializingThread(threadsInheritInitalizersClassLoader); + } + tp.initialize(); + tpInited = true; + + rsrcs.setJobStore(js); + + // add plugins + for (int i = 0; i < plugins.length; i++) { + rsrcs.addSchedulerPlugin(plugins[i]); + } + + qs = new QuartzScheduler(rsrcs, idleWaitTime, dbFailureRetry); + qsInited = true; + + // Create Scheduler ref... + Scheduler scheduler = instantiate(rsrcs, qs); + + // set job factory if specified + if(jobFactory != null) { + qs.setJobFactory(jobFactory); + } + + // Initialize plugins now that we have a Scheduler instance. + for (int i = 0; i < plugins.length; i++) { + plugins[i].initialize(pluginNames[i], scheduler, loadHelper); + } + + // add listeners + for (int i = 0; i < jobListeners.length; i++) { + qs.getListenerManager().addJobListener(jobListeners[i], EverythingMatcher.allJobs()); + } + for (int i = 0; i < triggerListeners.length; i++) { + qs.getListenerManager().addTriggerListener(triggerListeners[i], EverythingMatcher.allTriggers()); + } + + // set scheduler context data... + for(Object key: schedCtxtProps.keySet()) { + String val = schedCtxtProps.getProperty((String) key); + scheduler.getContext().put((String)key, val); + } + + // fire up job store, and runshell factory + + js.setInstanceId(schedInstId); + js.setInstanceName(schedName); + js.setThreadPoolSize(tp.getPoolSize()); + js.initialize(loadHelper, qs.getSchedulerSignaler()); + + jrsf.initialize(scheduler); + + qs.initialize(); + + getLog().info( + "Quartz scheduler '" + scheduler.getSchedulerName() + + "' initialized from " + propSrc); + + getLog().info("Quartz scheduler version: " + qs.getVersion()); + + // prevents the repository from being garbage collected + qs.addNoGCObject(schedRep); + // prevents the db manager from being garbage collected + if (dbMgr != null) { + qs.addNoGCObject(dbMgr); + } + + schedRep.bind(scheduler); + return scheduler; } - - // add listeners - for (int i = 0; i < jobListeners.length; i++) { - qs.addGlobalJobListener(jobListeners[i]); + catch(SchedulerException e) { + shutdownFromInstantiateException(tp, qs, tpInited, qsInited); + throw e; } - for (int i = 0; i < triggerListeners.length; i++) { - qs.addGlobalTriggerListener(triggerListeners[i]); + catch(RuntimeException re) { + shutdownFromInstantiateException(tp, qs, tpInited, qsInited); + throw re; } - - // set scheduler context data... - Iterator itr = schedCtxtProps.keySet().iterator(); - while(itr.hasNext()) { - String key = (String) itr.next(); - String val = schedCtxtProps.getProperty(key); - - scheduler.getContext().put(key, val); + catch(Error re) { + shutdownFromInstantiateException(tp, qs, tpInited, qsInited); + throw re; } - - // fire up job store, and runshell factory + } - js.initialize(loadHelper, qs.getSchedulerSignaler()); - - jrsf.initialize(scheduler, schedCtxt); - - getLog().info( - "Quartz scheduler '" + scheduler.getSchedulerName() - + "' initialized from " + propSrc); - - getLog().info("Quartz scheduler version: " + qs.getVersion()); - - // prevents the repository from being garbage collected - qs.addNoGCObject(schedRep); - // prevents the db manager from being garbage collected - if (dbMgr != null) qs.addNoGCObject(dbMgr); - - schedRep.bind(scheduler); - - return scheduler; + private void shutdownFromInstantiateException(ThreadPool tp, QuartzScheduler qs, boolean tpInited, boolean qsInited) { + try { + if(qsInited) + qs.shutdown(false); + else if(tpInited) + tp.shutdown(false); + } catch (Exception e) { + getLog().error("Got another exception while shutting down after instantiation exception", e); + } } protected Scheduler instantiate(QuartzSchedulerResources rsrcs, QuartzScheduler qs) { - SchedulingContext schedCtxt = new SchedulingContext(); - schedCtxt.setInstanceId(rsrcs.getInstanceId()); - - Scheduler scheduler = new StdScheduler(qs, schedCtxt); + + Scheduler scheduler = new StdScheduler(qs); return scheduler; } - + private void setBeanProps(Object obj, Properties props) - throws NoSuchMethodException, IllegalAccessException, + throws NoSuchMethodException, IllegalAccessException, java.lang.reflect.InvocationTargetException, IntrospectionException, SchedulerConfigException { props.remove("class"); @@ -1046,7 +1394,7 @@ PropertyDescriptor[] propDescs = bi.getPropertyDescriptors(); PropertiesParser pp = new PropertiesParser(props); - java.util.Enumeration keys = props.keys(); + java.util.Enumeration keys = props.keys(); while (keys.hasMoreElements()) { String name = (String) keys.nextElement(); String c = name.substring(0, 1).toUpperCase(Locale.US); @@ -1055,38 +1403,44 @@ java.lang.reflect.Method setMeth = getSetMethod(methName, propDescs); try { - if (setMeth == null) - throw new NoSuchMethodException( - "No setter for property '" + name + "'"); + if (setMeth == null) { + throw new NoSuchMethodException( + "No setter for property '" + name + "'"); + } - Class[] params = setMeth.getParameterTypes(); - if (params.length != 1) - throw new NoSuchMethodException( - "No 1-argument setter for property '" + name - + "'"); - + Class[] params = setMeth.getParameterTypes(); + if (params.length != 1) { + throw new NoSuchMethodException( + "No 1-argument setter for property '" + name + "'"); + } + + // does the property value reference another property's value? If so, swap to look at its value + PropertiesParser refProps = pp; + String refName = pp.getStringProperty(name); + if(refName != null && refName.startsWith("$@")) { + refName = refName.substring(2); + refProps = cfg; + } + else + refName = name; + if (params[0].equals(int.class)) { - setMeth.invoke(obj, new Object[]{new Integer(pp - .getIntProperty(name))}); + setMeth.invoke(obj, new Object[]{Integer.valueOf(refProps.getIntProperty(refName))}); } else if (params[0].equals(long.class)) { - setMeth.invoke(obj, new Object[]{new Long(pp - .getLongProperty(name))}); + setMeth.invoke(obj, new Object[]{Long.valueOf(refProps.getLongProperty(refName))}); } else if (params[0].equals(float.class)) { - setMeth.invoke(obj, new Object[]{new Float(pp - .getFloatProperty(name))}); + setMeth.invoke(obj, new Object[]{Float.valueOf(refProps.getFloatProperty(refName))}); } else if (params[0].equals(double.class)) { - setMeth.invoke(obj, new Object[]{new Double(pp - .getDoubleProperty(name))}); + setMeth.invoke(obj, new Object[]{Double.valueOf(refProps.getDoubleProperty(refName))}); } else if (params[0].equals(boolean.class)) { - setMeth.invoke(obj, new Object[]{new Boolean(pp - .getBooleanProperty(name))}); + setMeth.invoke(obj, new Object[]{Boolean.valueOf(refProps.getBooleanProperty(refName))}); } else if (params[0].equals(String.class)) { - setMeth.invoke(obj, - new Object[]{pp.getStringProperty(name)}); - } else + setMeth.invoke(obj, new Object[]{refProps.getStringProperty(refName)}); + } else { throw new NoSuchMethodException( "No primitive-type setter for property '" + name + "'"); + } } catch (NumberFormatException nfe) { throw new SchedulerConfigException("Could not parse property '" + name + "' into correct data type: " + nfe.toString()); @@ -1099,54 +1453,67 @@ for (int i = 0; i < props.length; i++) { java.lang.reflect.Method wMeth = props[i].getWriteMethod(); - if (wMeth != null && wMeth.getName().equals(name)) return wMeth; + if (wMeth != null && wMeth.getName().equals(name)) { + return wMeth; + } } return null; } - private Class loadClass(String className) throws ClassNotFoundException { + private Class loadClass(String className) throws ClassNotFoundException, SchedulerConfigException { try { - return Thread.currentThread().getContextClassLoader().loadClass( - className); + ClassLoader cl = findClassloader(); + if(cl != null) + return cl.loadClass(className); + throw new SchedulerConfigException("Unable to find a class loader on the current thread or class."); } catch (ClassNotFoundException e) { - return getClass().getClassLoader().loadClass(className); + if(getClass().getClassLoader() != null) + return getClass().getClassLoader().loadClass(className); + throw e; } } - + + private ClassLoader findClassloader() { + // work-around set context loader for windows-service started jvms (QUARTZ-748) + if(Thread.currentThread().getContextClassLoader() == null && getClass().getClassLoader() != null) { + Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); + } + return Thread.currentThread().getContextClassLoader(); + } + private String getSchedulerName() { return cfg.getStringProperty(PROP_SCHED_INSTANCE_NAME, "QuartzScheduler"); } - private String getSchedulerInstId() { - return cfg.getStringProperty(PROP_SCHED_INSTANCE_ID, - DEFAULT_INSTANCE_ID); - } - /** *

* Returns a handle to the Scheduler produced by this factory. *

- * + * *

* If one of the initialize methods has not be previously * called, then the default (no-arg) initialize() method * will be called by this method. *

*/ public Scheduler getScheduler() throws SchedulerException { - if (cfg == null) initialize(); + if (cfg == null) { + initialize(); + } SchedulerRepository schedRep = SchedulerRepository.getInstance(); Scheduler sched = schedRep.lookup(getSchedulerName()); if (sched != null) { - if (sched.isShutdown()) schedRep.remove(getSchedulerName()); - else + if (sched.isShutdown()) { + schedRep.remove(getSchedulerName()); + } else { return sched; + } } sched = instantiate(); @@ -1159,7 +1526,7 @@ * Returns a handle to the default Scheduler, creating it if it does not * yet exist. *

- * + * * @see #initialize() */ public static Scheduler getDefaultScheduler() throws SchedulerException { @@ -1184,8 +1551,7 @@ * StdSchedulerFactory instance.). *

*/ - public Collection getAllSchedulers() throws SchedulerException { + public Collection getAllSchedulers() throws SchedulerException { return SchedulerRepository.getInstance().lookupAll(); } - } Index: 3rdParty_sources/quartz/org/quartz/impl/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/package.html,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/package.html 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/package.html 15 Dec 2014 10:09:53 -0000 1.1.2.1 @@ -11,8 +11,8 @@


-See the Quartz project - at Open Symphony for more information. +See the Quartz project + for more information. Index: 3rdParty_sources/quartz/org/quartz/impl/calendar/AnnualCalendar.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/calendar/AnnualCalendar.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/calendar/AnnualCalendar.java 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/calendar/AnnualCalendar.java 15 Dec 2014 10:09:54 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,18 +15,14 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - * and Juergen Donnerstag (c) 2002, EDS 2002 - */ - package org.quartz.impl.calendar; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; +import java.util.TimeZone; import org.quartz.Calendar; @@ -44,35 +40,41 @@ public class AnnualCalendar extends BaseCalendar implements Calendar, Serializable { - private ArrayList excludeDays = new ArrayList(); + static final long serialVersionUID = 7346867105876610961L; + private ArrayList excludeDays = new ArrayList(); + // true, if excludeDays is sorted private boolean dataSorted = false; - /** - *

- * Constructor - *

- */ public AnnualCalendar() { - super(); } - /** - *

- * Constructor - *

- */ public AnnualCalendar(Calendar baseCalendar) { super(baseCalendar); } + public AnnualCalendar(TimeZone timeZone) { + super(timeZone); + } + + public AnnualCalendar(Calendar baseCalendar, TimeZone timeZone) { + super(baseCalendar, timeZone); + } + + @Override + public Object clone() { + AnnualCalendar clone = (AnnualCalendar) super.clone(); + clone.excludeDays = new ArrayList(excludeDays); + return clone; + } + /** *

* Get the array which defines the exclude-value of each day of month *

*/ - public ArrayList getDaysExcluded() { + public ArrayList getDaysExcluded() { return excludeDays; } @@ -82,10 +84,17 @@ *

*/ public boolean isDayExcluded(java.util.Calendar day) { - if (day == null) - throw new IllegalArgumentException( - "Parameter day must not be null"); + if (day == null) { + throw new IllegalArgumentException( + "Parameter day must not be null"); + } + + // Check baseCalendar first + if (! super.isTimeIncluded(day.getTime().getTime())) { + return true; + } + int dmonth = day.get(java.util.Calendar.MONTH); int dday = day.get(java.util.Calendar.DAY_OF_MONTH); @@ -94,16 +103,22 @@ dataSorted = true; } - Iterator iter = excludeDays.iterator(); + Iterator iter = excludeDays.iterator(); while (iter.hasNext()) { java.util.Calendar cl = (java.util.Calendar) iter.next(); // remember, the list is sorted - if (dmonth < cl.get(java.util.Calendar.MONTH)) return false; + if (dmonth < cl.get(java.util.Calendar.MONTH)) { + return false; + } - if (dday != cl.get(java.util.Calendar.DAY_OF_MONTH)) continue; + if (dday != cl.get(java.util.Calendar.DAY_OF_MONTH)) { + continue; + } - if (dmonth != cl.get(java.util.Calendar.MONTH)) continue; + if (dmonth != cl.get(java.util.Calendar.MONTH)) { + continue; + } return true; } @@ -113,14 +128,17 @@ /** *

- * Redefine the array of days excluded. The array must of size greater or - * equal 31. + * Redefine the list of days excluded. The ArrayList + * should contain java.util.Calendar objects. *

*/ - public void setDaysExcluded(ArrayList days) { - if (days == null) excludeDays = new ArrayList(); + public void setDaysExcluded(ArrayList days) { + if (days == null) { + excludeDays = new ArrayList(); + } else { + excludeDays = days; + } - excludeDays = days; dataSorted = false; } @@ -130,13 +148,68 @@ *

*/ public void setDayExcluded(java.util.Calendar day, boolean exclude) { - if (isDayExcluded(day)) return; + if (exclude) { + if (isDayExcluded(day)) { + return; + } - excludeDays.add(day); - dataSorted = false; + excludeDays.add(day); + dataSorted = false; + } else { + if (!isDayExcluded(day)) { + return; + } + + removeExcludedDay(day, true); + } } /** + * Remove the given day from the list of excluded days + * + * @param day the day to exclude + */ + public void removeExcludedDay(java.util.Calendar day) { + removeExcludedDay(day, false); + } + + private void removeExcludedDay(java.util.Calendar day, boolean isChecked) { + if (! isChecked && + ! isDayExcluded(day)) { + return; + } + + // Fast way, see if exact day object was already in list + if (this.excludeDays.remove(day)) { + return; + } + + int dmonth = day.get(java.util.Calendar.MONTH); + int dday = day.get(java.util.Calendar.DAY_OF_MONTH); + + // Since there is no guarantee that the given day is in the arraylist with the exact same year + // search for the object based on month and day of month in the list and remove it + Iterator iter = excludeDays.iterator(); + while (iter.hasNext()) { + java.util.Calendar cl = (java.util.Calendar) iter.next(); + + if (dmonth != cl.get(java.util.Calendar.MONTH)) { + continue; + } + + if (dday != cl.get(java.util.Calendar.DAY_OF_MONTH)) { + continue; + } + + day = cl; + break; + } + + this.excludeDays.remove(day); + } + + + /** *

* Determine whether the given time (in milliseconds) is 'included' by the * Calendar. @@ -146,12 +219,13 @@ * Note that this Calendar is only has full-day precision. *

*/ + @Override public boolean isTimeIncluded(long timeStamp) { // Test the base calendar first. Only if the base calendar not already // excludes the time/date, continue evaluating this calendar instance. if (super.isTimeIncluded(timeStamp) == false) { return false; } - java.util.Calendar day = getJavaCalendar(timeStamp); + java.util.Calendar day = createJavaCalendar(timeStamp); return !(isDayExcluded(day)); } @@ -167,18 +241,20 @@ * Note that this Calendar is only has full-day precision. *

*/ + @Override public long getNextIncludedTime(long timeStamp) { // Call base calendar implementation first long baseTime = super.getNextIncludedTime(timeStamp); - if ((baseTime > 0) && (baseTime > timeStamp)) timeStamp = baseTime; + if ((baseTime > 0) && (baseTime > timeStamp)) { + timeStamp = baseTime; + } // Get timestamp for 00:00:00 - long newTimeStamp = buildHoliday(timeStamp); + java.util.Calendar day = getStartOfDayJavaCalendar(timeStamp); + if (isDayExcluded(day) == false) { + return timeStamp; // return the original value + } - java.util.Calendar day = getJavaCalendar(newTimeStamp); - if (isDayExcluded(day) == false) return timeStamp; // return the - // original value - while (isDayExcluded(day) == true) { day.add(java.util.Calendar.DATE, 1); } @@ -187,25 +263,34 @@ } } -class CalendarComparator implements Comparator -{ +class CalendarComparator implements Comparator, Serializable { + + private static final long serialVersionUID = 7346867105876610961L; public CalendarComparator() { - } - /** - * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) - */ - public int compare(Object arg0, Object arg1) { - java.util.Calendar c1 = (java.util.Calendar) arg0; - java.util.Calendar c2 = (java.util.Calendar) arg1; + + public int compare(java.util.Calendar c1, java.util.Calendar c2) { - if(c1.before(c2)) + int month1 = c1.get(java.util.Calendar.MONTH); + int month2 = c2.get(java.util.Calendar.MONTH); + + int day1 = c1.get(java.util.Calendar.DAY_OF_MONTH); + int day2 = c2.get(java.util.Calendar.DAY_OF_MONTH); + + if (month1 < month2) { return -1; - else if(c1.after(c2)) + } + if (month1 > month2) { + return 1; + } + if (day1 < day2) { + return -1; + } + if (day1 > day2) { return 1; - else - return 0; - } + } + return 0; + } } Index: 3rdParty_sources/quartz/org/quartz/impl/calendar/BaseCalendar.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/calendar/BaseCalendar.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/calendar/BaseCalendar.java 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/calendar/BaseCalendar.java 15 Dec 2014 10:09:54 -0000 1.1.2.1 @@ -1,29 +1,25 @@ -/* - * Copyright 2004-2005 OpenSymphony - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations +/* + * Copyright 2001-2009 Terracotta, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations * under the License. - * + * */ -/* - * Previously Copyright (c) 2001-2004 James House - * and Juergen Donnerstag (c) 2002, EDS 2002 - */ - package org.quartz.impl.calendar; import java.io.Serializable; import java.util.Date; +import java.util.TimeZone; import org.quartz.Calendar; @@ -33,44 +29,70 @@ * base class for more sophisticated one's. It merely implements the base * functionality required by each Calendar. *

- * + * *

* Regarded as base functionality is the treatment of base calendars. Base * calendar allow you to chain (stack) as much calendars as you may need. For * example to exclude weekends you may use WeeklyCalendar. In order to exclude * holidays as well you may define a WeeklyCalendar instance to be the base * calendar for HolidayCalendar instance. *

- * + * * @see org.quartz.Calendar - * + * * @author Juergen Donnerstag * @author James House */ -public class BaseCalendar implements Calendar, Serializable { +public class BaseCalendar implements Calendar, Serializable, Cloneable { + static final long serialVersionUID = 3106623404629760239L; + //

A optional base calendar.

private Calendar baseCalendar; private String description; + private TimeZone timeZone; + + public BaseCalendar() { + } + + public BaseCalendar(Calendar baseCalendar) { + setBaseCalendar(baseCalendar); + } + /** - *

- * Default Constructor - *

+ * @param timeZone The time zone to use for this Calendar, null + * if {@link TimeZone#getDefault()} should be used */ - public BaseCalendar() { + public BaseCalendar(TimeZone timeZone) { + setTimeZone(timeZone); } /** - *

- * Constructor - *

+ * @param timeZone The time zone to use for this Calendar, null + * if {@link TimeZone#getDefault()} should be used */ - public BaseCalendar(Calendar baseCalendar) { + public BaseCalendar(Calendar baseCalendar, TimeZone timeZone) { setBaseCalendar(baseCalendar); + setTimeZone(timeZone); } + @Override + public Object clone() { + try { + BaseCalendar clone = (BaseCalendar) super.clone(); + if (getBaseCalendar() != null) { + clone.baseCalendar = (Calendar) getBaseCalendar().clone(); + } + if(getTimeZone() != null) + clone.timeZone = (TimeZone) getTimeZone().clone(); + return clone; + } catch (CloneNotSupportedException ex) { + throw new IncompatibleClassChangeError("Not Cloneable."); + } + } + /** *

* Set a new base calendar or remove the existing one @@ -94,7 +116,7 @@ * Return the description given to the Calendar instance by * its creator (if any). *

- * + * * @return null if no description was set. */ public String getDescription() { @@ -113,19 +135,41 @@ } /** + * Returns the time zone for which this Calendar will be + * resolved. + * + * @return This Calendar's timezone, null if Calendar should + * use the {@link TimeZone#getDefault()} + */ + public TimeZone getTimeZone() { + return timeZone; + } + + /** + * Sets the time zone for which this Calendar will be resolved. + * + * @param timeZone The time zone to use for this Calendar, null + * if {@link TimeZone#getDefault()} should be used + */ + public void setTimeZone(TimeZone timeZone) { + this.timeZone = timeZone; + } + + /** *

* Check if date/time represented by timeStamp is included. If included * return true. The implementation of BaseCalendar simply calls the base * calendars isTimeIncluded() method if base calendar is set. *

- * + * * @see org.quartz.Calendar#isTimeIncluded(long) */ public boolean isTimeIncluded(long timeStamp) { - if (timeStamp <= 0) - throw new IllegalArgumentException( - "timeStamp must be greater 0"); + if (timeStamp <= 0) { + throw new IllegalArgumentException( + "timeStamp must be greater 0"); + } if (baseCalendar != null) { if (baseCalendar.isTimeIncluded(timeStamp) == false) { return false; } @@ -140,62 +184,81 @@ * Calendar after the given time. Return the original value if timeStamp is * included. Return 0 if all days are excluded. *

- * + * * @see org.quartz.Calendar#getNextIncludedTime(long) */ public long getNextIncludedTime(long timeStamp) { - if (timeStamp <= 0) - throw new IllegalArgumentException( - "timeStamp must be greater 0"); + if (timeStamp <= 0) { + throw new IllegalArgumentException( + "timeStamp must be greater 0"); + } - if (baseCalendar != null) { return baseCalendar - .getNextIncludedTime(timeStamp); } + if (baseCalendar != null) { + return baseCalendar.getNextIncludedTime(timeStamp); + } return timeStamp; } /** - *

- * Utility method. Return the date of excludeDate. The time fraction will - * be reset to 00.00:00. - *

+ * Build a {@link java.util.Calendar} for the given timeStamp. + * The new Calendar will use the BaseCalendar time zone if it + * is not null. */ - static public Date buildHoliday(Date excludedDate) { - java.util.Calendar cl = java.util.Calendar.getInstance(); - java.util.Calendar clEx = java.util.Calendar.getInstance(); - clEx.setTime(excludedDate); + protected java.util.Calendar createJavaCalendar(long timeStamp) { + java.util.Calendar calendar = createJavaCalendar(); + calendar.setTime(new Date(timeStamp)); + return calendar; + } - cl.setLenient(false); - cl.clear(); - cl.set(clEx.get(java.util.Calendar.YEAR), clEx - .get(java.util.Calendar.MONTH), clEx - .get(java.util.Calendar.DATE)); - - return cl.getTime(); + /** + * Build a {@link java.util.Calendar} with the current time. + * The new Calendar will use the BaseCalendar time zone if + * it is not null. + */ + protected java.util.Calendar createJavaCalendar() { + return + (getTimeZone() == null) ? + java.util.Calendar.getInstance() : + java.util.Calendar.getInstance(getTimeZone()); } /** - *

- * Utility method. Return just the date of excludeDate. The time fraction - * will be reset to 00.00:00. - *

+ * Returns the start of the given day as a {@link java.util.Calendar}. + * This calculation will take the BaseCalendar + * time zone into account if it is not null. + * + * @param timeInMillis A time containing the desired date for the + * start-of-day time + * @return A {@link java.util.Calendar} set to the start of + * the given day. */ - static public long buildHoliday(long timeStamp) { - return buildHoliday(new Date(timeStamp)).getTime(); + protected java.util.Calendar getStartOfDayJavaCalendar(long timeInMillis) { + java.util.Calendar startOfDay = createJavaCalendar(timeInMillis); + startOfDay.set(java.util.Calendar.HOUR_OF_DAY, 0); + startOfDay.set(java.util.Calendar.MINUTE, 0); + startOfDay.set(java.util.Calendar.SECOND, 0); + startOfDay.set(java.util.Calendar.MILLISECOND, 0); + return startOfDay; } /** - *

- * Utility method. Return a java.util.Calendar for timeStamp. - *

- * - * @param timeStamp - * @return Calendar + * Returns the end of the given day {@link java.util.Calendar}. + * This calculation will take the BaseCalendar + * time zone into account if it is not null. + * + * @param timeInMillis a time containing the desired date for the + * end-of-day time. + * @return A {@link java.util.Calendar} set to the end of + * the given day. */ - static public java.util.Calendar getJavaCalendar(long timeStamp) { - java.util.Calendar cl = java.util.Calendar.getInstance(); - cl.setTime(new Date(timeStamp)); - return cl; + protected java.util.Calendar getEndOfDayJavaCalendar(long timeInMillis) { + java.util.Calendar endOfDay = createJavaCalendar(timeInMillis); + endOfDay.set(java.util.Calendar.HOUR_OF_DAY, 23); + endOfDay.set(java.util.Calendar.MINUTE, 59); + endOfDay.set(java.util.Calendar.SECOND, 59); + endOfDay.set(java.util.Calendar.MILLISECOND, 999); + return endOfDay; } } Index: 3rdParty_sources/quartz/org/quartz/impl/calendar/CronCalendar.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/calendar/CronCalendar.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/calendar/CronCalendar.java 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/calendar/CronCalendar.java 15 Dec 2014 10:09:54 -0000 1.1.2.1 @@ -2,14 +2,16 @@ import java.text.ParseException; import java.util.Date; +import java.util.TimeZone; +import org.quartz.Calendar; import org.quartz.CronExpression; /** * This implementation of the Calendar excludes the set of times expressed by a * given {@link org.quartz.CronExpression CronExpression}. For example, you * could use this calendar to exclude all but business hours (8AM - 5PM) every - * day using the expression "* * 0-7,18-24 ? * *". + * day using the expression "* * 0-7,18-23 ? * *". *

* It is important to remember that the cron expression here describes a set of * times to be excluded from firing. Whereas the cron expression in @@ -20,66 +22,107 @@ * trigger includes, and they will cancel each other out. * * @author Aaron Craven - * @version $Revision$ $Date$ */ public class CronCalendar extends BaseCalendar { static final long serialVersionUID = -8172103999750856831L; - - private String name; + CronExpression cronExpression; /** * Create a CronCalendar with the given cron expression and no * baseCalendar. * - * @param name the name for the DailyCalendar * @param expression a String representation of the desired cron expression */ - public CronCalendar(String name, String expression) - throws ParseException { - super(); - this.name = name; - this.cronExpression = new CronExpression(expression); + public CronCalendar(String expression) + throws ParseException { + this(null, expression, null); } /** - * Create a CronCalendar with the given cron exprssion and + * Create a CronCalendar with the given cron expression and * baseCalendar. * - * @param name the name for the DailyCalendar * @param baseCalendar the base calendar for this calendar instance – * see {@link BaseCalendar} for more information on base * calendar functionality * @param expression a String representation of the desired cron expression */ - public CronCalendar(String name, org.quartz.Calendar baseCalendar, - String expression) throws ParseException { + public CronCalendar(Calendar baseCalendar, + String expression) throws ParseException { + this(baseCalendar, expression, null); + } + + /** + * Create a CronCalendar with the given cron exprssion, + * baseCalendar, and TimeZone. + * + * @param baseCalendar the base calendar for this calendar instance – + * see {@link BaseCalendar} for more information on base + * calendar functionality + * @param expression a String representation of the desired cron expression + * @param timeZone + * Specifies for which time zone the expression + * should be interpreted, i.e. the expression 0 0 10 * * ?, is + * resolved to 10:00 am in this time zone. If + * timeZone is null then + * TimeZone.getDefault() will be used. + */ + public CronCalendar(Calendar baseCalendar, + String expression, TimeZone timeZone) throws ParseException { super(baseCalendar); - this.name = name; this.cronExpression = new CronExpression(expression); + this.cronExpression.setTimeZone(timeZone); } + + @Override + public Object clone() { + CronCalendar clone = (CronCalendar) super.clone(); + clone.cronExpression = new CronExpression(cronExpression); + return clone; + } /** - * Returns the name of the CronCalendar - * - * @return the name of the CronCalendar + * Returns the time zone for which the CronExpression of + * this CronCalendar will be resolved. + *

+ * Overrides {@link BaseCalendar#getTimeZone()} to + * defer to its CronExpression. + *

*/ - public String getName() { - return name; + @Override + public TimeZone getTimeZone() { + return cronExpression.getTimeZone(); } /** + * Sets the time zone for which the CronExpression of this + * CronCalendar will be resolved. If timeZone + * is null then TimeZone.getDefault() will be + * used. + *

+ * Overrides {@link BaseCalendar#setTimeZone(TimeZone)} to + * defer to its CronExpression. + *

+ */ + @Override + public void setTimeZone(TimeZone timeZone) { + cronExpression.setTimeZone(timeZone); + } + + /** * Determines whether the given time (in milliseconds) is 'included' by the * BaseCalendar * * @param timeInMillis the date/time to test * @return a boolean indicating whether the specified time is 'included' by * the CronCalendar */ + @Override public boolean isTimeIncluded(long timeInMillis) { if ((getBaseCalendar() != null) && - (getBaseCalendar().isTimeIncluded(timeInMillis) == false)) { - return false; + (getBaseCalendar().isTimeIncluded(timeInMillis) == false)) { + return false; } return (!(cronExpression.isSatisfiedBy(new Date(timeInMillis)))); @@ -94,27 +137,28 @@ * @return the time in milliseconds representing the next time included * after the specified time. */ + @Override public long getNextIncludedTime(long timeInMillis) { long nextIncludedTime = timeInMillis + 1; //plus on millisecond while (!isTimeIncluded(nextIncludedTime)) { - //If the time is in a range excluded by this calendar, we can - // move to the end of the excluded time range and continue testing - // from there. Otherwise, if nextIncludedTime is excluded by the - // baseCalendar, ask it the next time it includes and begin testing - // from there. Failing this, add one millisecond and continue - // testing. - if (cronExpression.isSatisfiedBy(new Date(nextIncludedTime))) { - nextIncludedTime = - cronExpression.getNextValidTimeAfter( - new Date(nextIncludedTime)).getTime(); - } else if ((getBaseCalendar() != null) && - (!getBaseCalendar().isTimeIncluded(nextIncludedTime))){ - nextIncludedTime = - getBaseCalendar().getNextIncludedTime(nextIncludedTime); - } else { - nextIncludedTime++; - } + + //If the time is in a range excluded by this calendar, we can + // move to the end of the excluded time range and continue testing + // from there. Otherwise, if nextIncludedTime is excluded by the + // baseCalendar, ask it the next time it includes and begin testing + // from there. Failing this, add one millisecond and continue + // testing. + if (cronExpression.isSatisfiedBy(new Date(nextIncludedTime))) { + nextIncludedTime = cronExpression.getNextInvalidTimeAfter( + new Date(nextIncludedTime)).getTime(); + } else if ((getBaseCalendar() != null) && + (!getBaseCalendar().isTimeIncluded(nextIncludedTime))){ + nextIncludedTime = + getBaseCalendar().getNextIncludedTime(nextIncludedTime); + } else { + nextIncludedTime++; + } } return nextIncludedTime; @@ -126,14 +170,14 @@ * * @return the properteis of the CronCalendar in a String format */ + @Override public String toString() { StringBuffer buffer = new StringBuffer(); - buffer.append(getName()); - buffer.append(": base calendar: ["); + buffer.append("base calendar: ["); if (getBaseCalendar() != null) { - buffer.append(getBaseCalendar().toString()); + buffer.append(getBaseCalendar().toString()); } else { - buffer.append("null"); + buffer.append("null"); } buffer.append("], excluded cron expression: '"); buffer.append(cronExpression); @@ -149,7 +193,7 @@ * @see org.quartz.CronExpression */ public CronExpression getCronExpression() { - return cronExpression; + return cronExpression; } /** @@ -160,9 +204,9 @@ * if the string expression cannot be parsed */ public void setCronExpression(String expression) throws ParseException { - CronExpression newExp = new CronExpression(expression); - - this.cronExpression = newExp; + CronExpression newExp = new CronExpression(expression); + + this.cronExpression = newExp; } /** @@ -171,10 +215,10 @@ * @param expression the new cron expression */ public void setCronExpression(CronExpression expression) { - if (expression == null) { - throw new IllegalArgumentException("expression cannot be null"); - } - - this.cronExpression = expression; + if (expression == null) { + throw new IllegalArgumentException("expression cannot be null"); + } + + this.cronExpression = expression; } } \ No newline at end of file Index: 3rdParty_sources/quartz/org/quartz/impl/calendar/DailyCalendar.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/calendar/DailyCalendar.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/calendar/DailyCalendar.java 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/calendar/DailyCalendar.java 15 Dec 2014 10:09:54 -0000 1.1.2.1 @@ -1,7 +1,10 @@ package org.quartz.impl.calendar; import java.text.NumberFormat; +import java.util.ArrayList; import java.util.Calendar; +import java.util.StringTokenizer; +import java.util.TimeZone; /** * This implementation of the Calendar excludes (or includes - see below) a @@ -22,9 +25,10 @@ * set of times that are excluded every day. * * @author Mike Funk, Aaron Craven - * @version $Revision$ $Date$ */ public class DailyCalendar extends BaseCalendar { + static final long serialVersionUID = -7561220099904944039L; + private static final String invalidHourOfDay = "Invalid hour of day: "; private static final String invalidMinute = "Invalid minute: "; private static final String invalidSecond = "Invalid second: "; @@ -34,7 +38,6 @@ private static final long oneMillis = 1; private static final String colon = ":"; - private String name; private int rangeStartingHourOfDay; private int rangeStartingMinute; private int rangeStartingSecond; @@ -65,18 +68,21 @@ * time. Note this means that a time range may not cross daily * boundaries (10PM - 2AM) * + * + *

+ * Note: This DailyCalendar will use the + * {@link TimeZone#getDefault()} time zone unless an explicit + * time zone is set via {@link BaseCalendar#setTimeZone(TimeZone)} + *

* - * @param name the name for the DailyCalendar * @param rangeStartingTime a String representing the starting time for the * time range * @param rangeEndingTime a String representing the ending time for the * the time range */ - public DailyCalendar(String name, - String rangeStartingTime, + public DailyCalendar(String rangeStartingTime, String rangeEndingTime) { super(); - this.name = name; setTimeRange(rangeStartingTime, rangeEndingTime); } @@ -100,7 +106,12 @@ * boundaries (10PM - 2AM) * * - * @param name the name for the DailyCalendar + *

+ * Note: This DailyCalendar will use the + * {@link TimeZone#getDefault()} time zone unless an explicit + * time zone is set via {@link BaseCalendar#setTimeZone(TimeZone)} + *

+ * * @param baseCalendar the base calendar for this calendar instance * – see {@link BaseCalendar} for more * information on base calendar functionality @@ -109,12 +120,10 @@ * @param rangeEndingTime a String representing the ending time for the * time range */ - public DailyCalendar(String name, - org.quartz.Calendar baseCalendar, + public DailyCalendar(org.quartz.Calendar baseCalendar, String rangeStartingTime, String rangeEndingTime) { super(baseCalendar); - this.name = name; setTimeRange(rangeStartingTime, rangeEndingTime); } @@ -132,7 +141,12 @@ * boundaries (10PM - 2AM) * * - * @param name the name for the DailyCalendar + *

+ * Note: This DailyCalendar will use the + * {@link TimeZone#getDefault()} time zone unless an explicit + * time zone is set via {@link BaseCalendar#setTimeZone(TimeZone)} + *

+ * * @param rangeStartingHourOfDay the hour of the start of the time range * @param rangeStartingMinute the minute of the start of the time range * @param rangeStartingSecond the second of the start of the time range @@ -144,8 +158,7 @@ * @param rangeEndingMillis the millisecond of the start of the time * range */ - public DailyCalendar(String name, - int rangeStartingHourOfDay, + public DailyCalendar(int rangeStartingHourOfDay, int rangeStartingMinute, int rangeStartingSecond, int rangeStartingMillis, @@ -154,7 +167,6 @@ int rangeEndingSecond, int rangeEndingMillis) { super(); - this.name = name; setTimeRange(rangeStartingHourOfDay, rangeStartingMinute, rangeStartingSecond, @@ -179,8 +191,12 @@ * boundaries (10PM - 2AM) * * - * @param name the name for the - * DailyCalendar + *

+ * Note: This DailyCalendar will use the + * {@link TimeZone#getDefault()} time zone unless an explicit + * time zone is set via {@link BaseCalendar#setTimeZone(TimeZone)} + *

+ * * @param baseCalendar the base calendar for this calendar * instance – see * {@link BaseCalendar} for more @@ -197,8 +213,7 @@ * @param rangeEndingMillis the millisecond of the start of the time * range */ - public DailyCalendar(String name, - org.quartz.Calendar baseCalendar, + public DailyCalendar(org.quartz.Calendar baseCalendar, int rangeStartingHourOfDay, int rangeStartingMinute, int rangeStartingSecond, @@ -208,7 +223,6 @@ int rangeEndingSecond, int rangeEndingMillis) { super(baseCalendar); - this.name = name; setTimeRange(rangeStartingHourOfDay, rangeStartingMinute, rangeStartingSecond, @@ -235,17 +249,21 @@ * true) * * - * @param name the name for the DailyCalendar + *

+ * Note: This DailyCalendar will use the + * {@link TimeZone#getDefault()} time zone unless an explicit + * time zone is set via {@link BaseCalendar#setTimeZone(TimeZone)} + *

+ * * @param rangeStartingCalendar a java.util.Calendar representing the * starting time for the time range * @param rangeEndingCalendar a java.util.Calendar representing the ending * time for the time range */ - public DailyCalendar(String name, + public DailyCalendar( Calendar rangeStartingCalendar, Calendar rangeEndingCalendar) { super(); - this.name = name; setTimeRange(rangeStartingCalendar, rangeEndingCalendar); } @@ -265,7 +283,12 @@ * true) * * - * @param name the name for the DailyCalendar + *

+ * Note: This DailyCalendar will use the + * {@link TimeZone#getDefault()} time zone unless an explicit + * time zone is set via {@link BaseCalendar#setTimeZone(TimeZone)} + *

+ * * @param baseCalendar the base calendar for this calendar instance * – see {@link BaseCalendar} for more * information on base calendar functionality @@ -274,12 +297,10 @@ * @param rangeEndingCalendar a java.util.Calendar representing the ending * time for the time range */ - public DailyCalendar(String name, - org.quartz.Calendar baseCalendar, + public DailyCalendar(org.quartz.Calendar baseCalendar, Calendar rangeStartingCalendar, Calendar rangeEndingCalendar) { super(baseCalendar); - this.name = name; setTimeRange(rangeStartingCalendar, rangeEndingCalendar); } @@ -297,20 +318,26 @@ * rangeEndingTime) * * - * @param name the name for the - * DailyCalendar + *

+ * Note: This DailyCalendar will use the + * {@link TimeZone#getDefault()} time zone unless an explicit + * time zone is set via {@link BaseCalendar#setTimeZone(TimeZone)}. + * You should use {@link #DailyCalendar(org.quartz.Calendar, java.util.TimeZone, long, long)} + * if you don't want the given rangeStartingTimeInMillis and + * rangeEndingTimeInMillis to be evaluated in the default + * time zone. + *

+ * * @param rangeStartingTimeInMillis a long representing the starting time * for the time range * @param rangeEndingTimeInMillis a long representing the ending time for * the time range */ - public DailyCalendar(String name, - long rangeStartingTimeInMillis, + public DailyCalendar(long rangeStartingTimeInMillis, long rangeEndingTimeInMillis) { super(); - this.name = name; setTimeRange(rangeStartingTimeInMillis, - rangeEndingTimeInMillis); + rangeEndingTimeInMillis); } /** @@ -327,8 +354,16 @@ * rangeEndingTime) * * - * @param name the name for the - * DailyCalendar + *

+ * Note: This DailyCalendar will use the + * {@link TimeZone#getDefault()} time zone unless an explicit + * time zone is set via {@link BaseCalendar#setTimeZone(TimeZone)}. + * You should use {@link #DailyCalendar(org.quartz.Calendar, java.util.TimeZone, long, long)} + * if you don't want the given rangeStartingTimeInMillis and + * rangeEndingTimeInMillis to be evaluated in the default + * time zone. + *

+ * * @param baseCalendar the base calendar for this calendar * instance – see {@link * BaseCalendar} for more information on @@ -338,25 +373,87 @@ * @param rangeEndingTimeInMillis a long representing the ending time for * the time range */ - public DailyCalendar(String name, - org.quartz.Calendar baseCalendar, + public DailyCalendar(org.quartz.Calendar baseCalendar, long rangeStartingTimeInMillis, long rangeEndingTimeInMillis) { super(baseCalendar); - this.name = name; setTimeRange(rangeStartingTimeInMillis, - rangeEndingTimeInMillis); + rangeEndingTimeInMillis); } + + /** + * Create a DailyCalendar with a time range defined by the + * specified values and no baseCalendar. The values are + * subject to the following considerations: + *
  • Only the time-of-day portion of the specified values will be + * used
  • + *
  • The starting time must be before the ending time of the defined + * time range. Note this means that a time range may not cross + * daily boundaries (10PM - 2AM). (because only time value are + * are used, it is possible for the two values to represent a valid + * time range and rangeStartingTime > + * rangeEndingTime)
  • + *
+ * + * @param timeZone the time zone for of the + * DailyCalendar which will + * also be used to resolve the given + * start/end times. + * @param rangeStartingTimeInMillis a long representing the starting time + * for the time range + * @param rangeEndingTimeInMillis a long representing the ending time for + * the time range + */ + public DailyCalendar(TimeZone timeZone, + long rangeStartingTimeInMillis, + long rangeEndingTimeInMillis) { + super(timeZone); + setTimeRange(rangeStartingTimeInMillis, + rangeEndingTimeInMillis); + } /** - * Returns the name of the DailyCalendar + * Create a DailyCalendar with a time range defined by the + * specified values and the specified baseCalendar. The values + * are subject to the following considerations: + *
  • Only the time-of-day portion of the specified values will be + * used
  • + *
  • The starting time must be before the ending time of the defined + * time range. Note this means that a time range may not cross + * daily boundaries (10PM - 2AM). (because only time value are + * are used, it is possible for the two values to represent a valid + * time range and rangeStartingTime > + * rangeEndingTime)
  • + *
* - * @return the name of the DailyCalendar + * @param baseCalendar the base calendar for this calendar + * instance – see {@link + * BaseCalendar} for more information on + * base calendar functionality + * @param timeZone the time zone for of the + * DailyCalendar which will + * also be used to resolve the given + * start/end times. + * @param rangeStartingTimeInMillis a long representing the starting time + * for the time range + * @param rangeEndingTimeInMillis a long representing the ending time for + * the time range */ - public String getName() { - return name; + public DailyCalendar(org.quartz.Calendar baseCalendar, + TimeZone timeZone, + long rangeStartingTimeInMillis, + long rangeEndingTimeInMillis) { + super(baseCalendar, timeZone); + setTimeRange(rangeStartingTimeInMillis, + rangeEndingTimeInMillis); } + @Override + public Object clone() { + DailyCalendar clone = (DailyCalendar) super.clone(); + return clone; + } + /** * Determines whether the given time (in milliseconds) is 'included' by the * BaseCalendar @@ -365,35 +462,28 @@ * @return a boolean indicating whether the specified time is 'included' by * the BaseCalendar */ + @Override public boolean isTimeIncluded(long timeInMillis) { if ((getBaseCalendar() != null) && - (getBaseCalendar().isTimeIncluded(timeInMillis) == false)) { - return false; + (getBaseCalendar().isTimeIncluded(timeInMillis) == false)) { + return false; } - long startOfDayInMillis = getStartOfDayInMillis(timeInMillis); - long endOfDayInMillis = getEndOfDayInMillis(timeInMillis); + long startOfDayInMillis = getStartOfDayJavaCalendar(timeInMillis).getTime().getTime(); + long endOfDayInMillis = getEndOfDayJavaCalendar(timeInMillis).getTime().getTime(); long timeRangeStartingTimeInMillis = - getTimeRangeStartingTimeInMillis(timeInMillis); + getTimeRangeStartingTimeInMillis(timeInMillis); long timeRangeEndingTimeInMillis = - getTimeRangeEndingTimeInMillis(timeInMillis); + getTimeRangeEndingTimeInMillis(timeInMillis); if (!invertTimeRange) { - if ((timeInMillis > startOfDayInMillis && - timeInMillis < timeRangeStartingTimeInMillis) || - (timeInMillis > timeRangeEndingTimeInMillis && - timeInMillis < endOfDayInMillis)) { - - return true; - } else { - return false; - } + return + ((timeInMillis > startOfDayInMillis && + timeInMillis < timeRangeStartingTimeInMillis) || + (timeInMillis > timeRangeEndingTimeInMillis && + timeInMillis < endOfDayInMillis)); } else { - if ((timeInMillis >= timeRangeStartingTimeInMillis) && - (timeInMillis <= timeRangeEndingTimeInMillis)) { - return true; - } else { - return false; - } + return ((timeInMillis >= timeRangeStartingTimeInMillis) && + (timeInMillis <= timeRangeEndingTimeInMillis)); } } @@ -406,56 +496,57 @@ * @return the time in milliseconds representing the next time included * after the specified time. */ + @Override public long getNextIncludedTime(long timeInMillis) { long nextIncludedTime = timeInMillis + oneMillis; while (!isTimeIncluded(nextIncludedTime)) { - if (!invertTimeRange) { - //If the time is in a range excluded by this calendar, we can - // move to the end of the excluded time range and continue - // testing from there. Otherwise, if nextIncludedTime is - // excluded by the baseCalendar, ask it the next time it - // includes and begin testing from there. Failing this, add one - // millisecond and continue testing. - if ((nextIncludedTime >= - getTimeRangeStartingTimeInMillis(nextIncludedTime)) && - (nextIncludedTime <= - getTimeRangeEndingTimeInMillis(nextIncludedTime))) { - - nextIncludedTime = - getTimeRangeEndingTimeInMillis(nextIncludedTime) + - oneMillis; - } else if ((getBaseCalendar() != null) && - (!getBaseCalendar().isTimeIncluded(nextIncludedTime))){ - nextIncludedTime = - getBaseCalendar().getNextIncludedTime(nextIncludedTime); - } else { - nextIncludedTime++; - } - } else { - //If the time is in a range excluded by this calendar, we can - // move to the end of the excluded time range and continue - // testing from there. Otherwise, if nextIncludedTime is - // excluded by the baseCalendar, ask it the next time it - // includes and begin testing from there. Failing this, add one - // millisecond and continue testing. - if (nextIncludedTime < - getTimeRangeStartingTimeInMillis(nextIncludedTime)) { - nextIncludedTime = - getTimeRangeStartingTimeInMillis(nextIncludedTime); - } else if (nextIncludedTime > - getTimeRangeEndingTimeInMillis(nextIncludedTime)) { - //(move to start of next day) - nextIncludedTime = getEndOfDayInMillis(nextIncludedTime); - nextIncludedTime += 1l; - } else if ((getBaseCalendar() != null) && - (!getBaseCalendar().isTimeIncluded(nextIncludedTime))){ - nextIncludedTime = - getBaseCalendar().getNextIncludedTime(nextIncludedTime); - } else { - nextIncludedTime++; - } - } + if (!invertTimeRange) { + //If the time is in a range excluded by this calendar, we can + // move to the end of the excluded time range and continue + // testing from there. Otherwise, if nextIncludedTime is + // excluded by the baseCalendar, ask it the next time it + // includes and begin testing from there. Failing this, add one + // millisecond and continue testing. + if ((nextIncludedTime >= + getTimeRangeStartingTimeInMillis(nextIncludedTime)) && + (nextIncludedTime <= + getTimeRangeEndingTimeInMillis(nextIncludedTime))) { + + nextIncludedTime = + getTimeRangeEndingTimeInMillis(nextIncludedTime) + + oneMillis; + } else if ((getBaseCalendar() != null) && + (!getBaseCalendar().isTimeIncluded(nextIncludedTime))){ + nextIncludedTime = + getBaseCalendar().getNextIncludedTime(nextIncludedTime); + } else { + nextIncludedTime++; + } + } else { + //If the time is in a range excluded by this calendar, we can + // move to the end of the excluded time range and continue + // testing from there. Otherwise, if nextIncludedTime is + // excluded by the baseCalendar, ask it the next time it + // includes and begin testing from there. Failing this, add one + // millisecond and continue testing. + if (nextIncludedTime < + getTimeRangeStartingTimeInMillis(nextIncludedTime)) { + nextIncludedTime = + getTimeRangeStartingTimeInMillis(nextIncludedTime); + } else if (nextIncludedTime > + getTimeRangeEndingTimeInMillis(nextIncludedTime)) { + //(move to start of next day) + nextIncludedTime = getEndOfDayJavaCalendar(nextIncludedTime).getTime().getTime(); + nextIncludedTime += 1l; + } else if ((getBaseCalendar() != null) && + (!getBaseCalendar().isTimeIncluded(nextIncludedTime))){ + nextIncludedTime = + getBaseCalendar().getNextIncludedTime(nextIncludedTime); + } else { + nextIncludedTime++; + } + } } return nextIncludedTime; @@ -471,13 +562,12 @@ * time range for the specified date. */ public long getTimeRangeStartingTimeInMillis(long timeInMillis) { - Calendar rangeStartingTime = Calendar.getInstance(); - rangeStartingTime.setTimeInMillis(timeInMillis); + Calendar rangeStartingTime = createJavaCalendar(timeInMillis); rangeStartingTime.set(Calendar.HOUR_OF_DAY, rangeStartingHourOfDay); rangeStartingTime.set(Calendar.MINUTE, rangeStartingMinute); rangeStartingTime.set(Calendar.SECOND, rangeStartingSecond); rangeStartingTime.set(Calendar.MILLISECOND, rangeStartingMillis); - return rangeStartingTime.getTimeInMillis(); + return rangeStartingTime.getTime().getTime(); } /** @@ -490,13 +580,12 @@ * time range for the specified date. */ public long getTimeRangeEndingTimeInMillis(long timeInMillis) { - Calendar rangeEndingTime = Calendar.getInstance(); - rangeEndingTime.setTimeInMillis(timeInMillis); + Calendar rangeEndingTime = createJavaCalendar(timeInMillis); rangeEndingTime.set(Calendar.HOUR_OF_DAY, rangeEndingHourOfDay); rangeEndingTime.set(Calendar.MINUTE, rangeEndingMinute); rangeEndingTime.set(Calendar.SECOND, rangeEndingSecond); rangeEndingTime.set(Calendar.MILLISECOND, rangeEndingMillis); - return rangeEndingTime.getTimeInMillis(); + return rangeEndingTime.getTime().getTime(); } /** @@ -506,7 +595,7 @@ * @return a boolean indicating whether the time range is inverted */ public boolean getInvertTimeRange() { - return invertTimeRange; + return invertTimeRange; } /** @@ -516,7 +605,7 @@ * @param flag the new value for the invertTimeRange flag. */ public void setInvertTimeRange(boolean flag) { - this.invertTimeRange = flag; + this.invertTimeRange = flag; } /** @@ -525,18 +614,17 @@ * * @return the properteis of the DailyCalendar in a String format */ + @Override public String toString() { - long todayInMillis = Calendar.getInstance().getTimeInMillis(); NumberFormat numberFormatter = NumberFormat.getNumberInstance(); numberFormatter.setMaximumFractionDigits(0); numberFormatter.setMinimumIntegerDigits(2); StringBuffer buffer = new StringBuffer(); - buffer.append(getName()); - buffer.append(": base calendar: ["); + buffer.append("base calendar: ["); if (getBaseCalendar() != null) { - buffer.append(getBaseCalendar().toString()); + buffer.append(getBaseCalendar().toString()); } else { - buffer.append("null"); + buffer.append("null"); } buffer.append("], time range: '"); buffer.append(numberFormatter.format(rangeStartingHourOfDay)); @@ -557,12 +645,25 @@ buffer.append(":"); numberFormatter.setMinimumIntegerDigits(3); buffer.append(numberFormatter.format(rangeEndingMillis)); - buffer.append("', inverted: " + - Boolean.toString(invertTimeRange) + "]"); + buffer.append("', inverted: " + invertTimeRange + "]"); return buffer.toString(); } /** + * Helper method to split the given string by the given delimiter. + */ + private String[] split(String string, String delim) { + ArrayList result = new ArrayList(); + + StringTokenizer stringTokenizer = new StringTokenizer(string, delim); + while (stringTokenizer.hasMoreTokens()) { + result.add(stringTokenizer.nextToken()); + } + + return (String[])result.toArray(new String[result.size()]); + } + + /** * Sets the time range for the DailyCalendar to the times * represented in the specified Strings. * @@ -571,68 +672,68 @@ * @param rangeEndingTimeString a String representing the end time of the * excluded time range */ - private void setTimeRange(String rangeStartingTimeString, + public void setTimeRange(String rangeStartingTimeString, String rangeEndingTimeString) { - String[] rangeStartingTime; - int rangeStartingHourOfDay; - int rangeStartingMinute; - int rangeStartingSecond; - int rangeStartingMillis; - - String[] rangeEndingTime; - int rangeEndingHourOfDay; - int rangeEndingMinute; - int rangeEndingSecond; - int rangeEndingMillis; - - rangeStartingTime = rangeStartingTimeString.split(colon); + String[] rangeStartingTime; + int rStartingHourOfDay; + int rStartingMinute; + int rStartingSecond; + int rStartingMillis; + String[] rEndingTime; + int rEndingHourOfDay; + int rEndingMinute; + int rEndingSecond; + int rEndingMillis; + + rangeStartingTime = split(rangeStartingTimeString, colon); + if ((rangeStartingTime.length < 2) || (rangeStartingTime.length > 4)) { - throw new IllegalArgumentException("Invalid time string '" + - rangeStartingTimeString + "'"); + throw new IllegalArgumentException("Invalid time string '" + + rangeStartingTimeString + "'"); } - rangeStartingHourOfDay = Integer.parseInt(rangeStartingTime[0]); - rangeStartingMinute = Integer.parseInt(rangeStartingTime[1]); + rStartingHourOfDay = Integer.parseInt(rangeStartingTime[0]); + rStartingMinute = Integer.parseInt(rangeStartingTime[1]); if (rangeStartingTime.length > 2) { - rangeStartingSecond = Integer.parseInt(rangeStartingTime[2]); + rStartingSecond = Integer.parseInt(rangeStartingTime[2]); } else { - rangeStartingSecond = 0; + rStartingSecond = 0; } if (rangeStartingTime.length == 4) { - rangeStartingMillis = Integer.parseInt(rangeStartingTime[3]); + rStartingMillis = Integer.parseInt(rangeStartingTime[3]); } else { - rangeStartingMillis = 0; + rStartingMillis = 0; } - rangeEndingTime = rangeEndingTimeString.split(colon); + rEndingTime = split(rangeEndingTimeString, colon); - if ((rangeEndingTime.length < 2) || (rangeEndingTime.length > 4)) { - throw new IllegalArgumentException("Invalid time string '" + - rangeEndingTimeString + "'"); + if ((rEndingTime.length < 2) || (rEndingTime.length > 4)) { + throw new IllegalArgumentException("Invalid time string '" + + rangeEndingTimeString + "'"); } - rangeEndingHourOfDay = Integer.parseInt(rangeEndingTime[0]); - rangeEndingMinute = Integer.parseInt(rangeEndingTime[1]); - if (rangeEndingTime.length > 2) { - rangeEndingSecond = Integer.parseInt(rangeEndingTime[2]); + rEndingHourOfDay = Integer.parseInt(rEndingTime[0]); + rEndingMinute = Integer.parseInt(rEndingTime[1]); + if (rEndingTime.length > 2) { + rEndingSecond = Integer.parseInt(rEndingTime[2]); } else { - rangeEndingSecond = 0; + rEndingSecond = 0; } - if (rangeEndingTime.length == 4) { - rangeEndingMillis = Integer.parseInt(rangeEndingTime[3]); + if (rEndingTime.length == 4) { + rEndingMillis = Integer.parseInt(rEndingTime[3]); } else { - rangeEndingMillis = 0; + rEndingMillis = 0; } - setTimeRange(rangeStartingHourOfDay, - rangeStartingMinute, - rangeStartingSecond, - rangeStartingMillis, - rangeEndingHourOfDay, - rangeEndingMinute, - rangeEndingSecond, - rangeEndingMillis); + setTimeRange(rStartingHourOfDay, + rStartingMinute, + rStartingSecond, + rStartingMillis, + rEndingHourOfDay, + rEndingMinute, + rEndingSecond, + rEndingMillis); } /** @@ -650,7 +751,7 @@ * @param rangeEndingMillis the millisecond of the start of the time * range */ - private void setTimeRange(int rangeStartingHourOfDay, + public void setTimeRange(int rangeStartingHourOfDay, int rangeStartingMinute, int rangeStartingSecond, int rangeStartingMillis, @@ -668,28 +769,28 @@ rangeEndingSecond, rangeEndingMillis); - Calendar startCal = Calendar.getInstance(); + Calendar startCal = createJavaCalendar(); startCal.set(Calendar.HOUR_OF_DAY, rangeStartingHourOfDay); startCal.set(Calendar.MINUTE, rangeStartingMinute); startCal.set(Calendar.SECOND, rangeStartingSecond); startCal.set(Calendar.MILLISECOND, rangeStartingMillis); - Calendar endCal = Calendar.getInstance(); + Calendar endCal = createJavaCalendar(); endCal.set(Calendar.HOUR_OF_DAY, rangeEndingHourOfDay); endCal.set(Calendar.MINUTE, rangeEndingMinute); endCal.set(Calendar.SECOND, rangeEndingSecond); endCal.set(Calendar.MILLISECOND, rangeEndingMillis); if (!startCal.before(endCal)) { throw new IllegalArgumentException(invalidTimeRange + - rangeStartingHourOfDay + ":" + - rangeStartingMinute + ":" + - rangeStartingSecond + ":" + - rangeStartingMillis + separator + - rangeEndingHourOfDay + ":" + - rangeEndingMinute + ":" + - rangeEndingSecond + ":" + - rangeEndingMillis); + rangeStartingHourOfDay + ":" + + rangeStartingMinute + ":" + + rangeStartingSecond + ":" + + rangeStartingMillis + separator + + rangeEndingHourOfDay + ":" + + rangeEndingMinute + ":" + + rangeEndingSecond + ":" + + rangeEndingMillis); } this.rangeStartingHourOfDay = rangeStartingHourOfDay; @@ -711,8 +812,8 @@ * @param rangeEndingCalendar a Calendar containing the end time for * the DailyCalendar */ - private void setTimeRange(Calendar rangeStartingCalendar, - Calendar rangeEndingCalendar) { + public void setTimeRange(Calendar rangeStartingCalendar, + Calendar rangeEndingCalendar) { setTimeRange( rangeStartingCalendar.get(Calendar.HOUR_OF_DAY), rangeStartingCalendar.get(Calendar.MINUTE), @@ -733,51 +834,14 @@ * @param rangeEndingTime the ending time (in milliseconds) for the time * range */ - private void setTimeRange(long rangeStartingTime, - long rangeEndingTime) { - Calendar startCal = Calendar.getInstance(); - Calendar endCal = Calendar.getInstance(); - startCal.setTimeInMillis(rangeStartingTime); - endCal.setTimeInMillis(rangeEndingTime); - - setTimeRange(startCal, endCal); + public void setTimeRange(long rangeStartingTime, + long rangeEndingTime) { + setTimeRange( + createJavaCalendar(rangeStartingTime), + createJavaCalendar(rangeEndingTime)); } /** - * Returns the start of the given day in milliseconds - * - * @param timeInMillis a time containing the desired date for the - * start-of-day time. - * @return the start of the given day in milliseconds - */ - private long getStartOfDayInMillis(long timeInMillis) { - Calendar startOfDay = Calendar.getInstance(); - startOfDay.setTimeInMillis(timeInMillis); - startOfDay.set(Calendar.HOUR_OF_DAY, 0); - startOfDay.set(Calendar.MINUTE, 0); - startOfDay.set(Calendar.SECOND, 0); - startOfDay.set(Calendar.MILLISECOND, 0); - return startOfDay.getTimeInMillis(); - } - - /** - * Returns the end of the given day in milliseconds - * - * @param timeInMillis a time containing the desired date for the - * end-of-day time. - * @return the end of the given day in milliseconds - */ - private long getEndOfDayInMillis(long timeInMillis) { - Calendar endOfDay = Calendar.getInstance(); - endOfDay.setTimeInMillis(timeInMillis); - endOfDay.set(Calendar.HOUR_OF_DAY, 23); - endOfDay.set(Calendar.MINUTE, 59); - endOfDay.set(Calendar.SECOND, 59); - endOfDay.set(Calendar.MILLISECOND, 999); - return endOfDay.getTimeInMillis(); - } - - /** * Checks the specified values for validity as a set of time values. * * @param hourOfDay the hour of the time to check (in military (24-hour) Index: 3rdParty_sources/quartz/org/quartz/impl/calendar/HolidayCalendar.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/calendar/HolidayCalendar.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/calendar/HolidayCalendar.java 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/calendar/HolidayCalendar.java 15 Dec 2014 10:09:54 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,15 +15,13 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.calendar; import java.io.Serializable; import java.util.Collections; import java.util.Date; import java.util.SortedSet; +import java.util.TimeZone; import java.util.TreeSet; import org.quartz.Calendar; @@ -45,23 +43,33 @@ */ public class HolidayCalendar extends BaseCalendar implements Calendar, Serializable { - + static final long serialVersionUID = -7590908752291814693L; + // A sorted set to store the holidays - private TreeSet dates = new TreeSet(); + private TreeSet dates = new TreeSet(); - /** - * Constructor - */ public HolidayCalendar() { } - /** - * Constructor - */ public HolidayCalendar(Calendar baseCalendar) { - setBaseCalendar(baseCalendar); + super(baseCalendar); } + public HolidayCalendar(TimeZone timeZone) { + super(timeZone); + } + + public HolidayCalendar(Calendar baseCalendar, TimeZone timeZone) { + super(baseCalendar, timeZone); + } + + @Override + public Object clone() { + HolidayCalendar clone = (HolidayCalendar) super.clone(); + clone.dates = new TreeSet(dates); + return clone; + } + /** *

* Determine whether the given time (in milliseconds) is 'included' by the @@ -72,10 +80,13 @@ * Note that this Calendar is only has full-day precision. *

*/ + @Override public boolean isTimeIncluded(long timeStamp) { - if (super.isTimeIncluded(timeStamp) == false) return false; + if (super.isTimeIncluded(timeStamp) == false) { + return false; + } - Date lookFor = buildHoliday(new Date(timeStamp)); + Date lookFor = getStartOfDayJavaCalendar(timeStamp).getTime(); return !(dates.contains(lookFor)); } @@ -90,16 +101,17 @@ * Note that this Calendar is only has full-day precision. *

*/ + @Override public long getNextIncludedTime(long timeStamp) { // Call base calendar implementation first long baseTime = super.getNextIncludedTime(timeStamp); - if ((baseTime > 0) && (baseTime > timeStamp)) timeStamp = baseTime; + if ((baseTime > 0) && (baseTime > timeStamp)) { + timeStamp = baseTime; + } // Get timestamp for 00:00:00 - long newTimeStamp = buildHoliday(timeStamp); - - java.util.Calendar day = getJavaCalendar(newTimeStamp); + java.util.Calendar day = getStartOfDayJavaCalendar(timeStamp); while (isTimeIncluded(day.getTime().getTime()) == false) { day.add(java.util.Calendar.DATE, 1); } @@ -114,7 +126,7 @@ *

*/ public void addExcludedDate(Date excludedDate) { - Date date = buildHoliday(excludedDate); + Date date = getStartOfDayJavaCalendar(excludedDate.getTime()).getTime(); /* * System.err.println( "HolidayCalendar.add(): date=" + * excludedDate.toLocaleString()); @@ -123,7 +135,7 @@ } public void removeExcludedDate(Date dateToRemove) { - Date date = buildHoliday(dateToRemove); + Date date = getStartOfDayJavaCalendar(dateToRemove.getTime()).getTime(); dates.remove(date); } @@ -134,7 +146,7 @@ * significant. *

*/ - public SortedSet getExcludedDates() { + public SortedSet getExcludedDates() { return Collections.unmodifiableSortedSet(dates); } } Index: 3rdParty_sources/quartz/org/quartz/impl/calendar/MonthlyCalendar.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/calendar/MonthlyCalendar.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/calendar/MonthlyCalendar.java 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/calendar/MonthlyCalendar.java 15 Dec 2014 10:09:54 -0000 1.1.2.1 @@ -1,87 +1,84 @@ -/* - * Copyright 2004-2005 OpenSymphony - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations +/* + * Copyright 2001-2009 Terracotta, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations * under the License. - * + * */ -/* - * Previously Copyright (c) 2001-2004 James House - * and Juergen Donnerstag (c) 2002, EDS 2002 - */ - package org.quartz.impl.calendar; import java.io.Serializable; -import java.util.Date; +import java.util.TimeZone; import org.quartz.Calendar; /** *

* This implementation of the Calendar excludes a set of days of the month. You - * may use it to exclude every 1. of each month for example. But you may define + * may use it to exclude every first day of each month for example. But you may define * any day of a month. *

- * + * * @see org.quartz.Calendar * @see org.quartz.impl.calendar.BaseCalendar - * + * * @author Juergen Donnerstag */ public class MonthlyCalendar extends BaseCalendar implements Calendar, Serializable { + static final long serialVersionUID = 419164961091807944L; + + private static final int MAX_DAYS_IN_MONTH = 31; + // An array to store a months days which are to be excluded. // java.util.Calendar.get( ) as index. - private boolean[] excludeDays = new boolean[31]; + private boolean[] excludeDays = new boolean[MAX_DAYS_IN_MONTH]; // Will be set to true, if all week days are excluded private boolean excludeAll = false; - /** - *

- * Constructor - *

- */ public MonthlyCalendar() { - super(); - init(); + this(null, null); } - /** - *

- * Constructor - *

- */ public MonthlyCalendar(Calendar baseCalendar) { - super(baseCalendar); - init(); + this(baseCalendar, null); } - /** - *

- * Initialize internal variables - *

- */ - private void init() { + public MonthlyCalendar(TimeZone timeZone) { + this(null, timeZone); + } + + public MonthlyCalendar(Calendar baseCalendar, TimeZone timeZone) { + super(baseCalendar, timeZone); + // all days are included by default excludeAll = areAllDaysExcluded(); } + @Override + public Object clone() { + MonthlyCalendar clone = (MonthlyCalendar) super.clone(); + clone.excludeDays = excludeDays.clone(); + return clone; + } + /** *

- * Get the array which defines the exclude-value of each day of month + * Get the array which defines the exclude-value of each day of month. + * Only the first 31 elements of the array are relevant, with the 0 index + * element representing the first day of the month. *

*/ public boolean[] getDaysExcluded() { @@ -90,22 +87,37 @@ /** *

- * Return true, if mday is defined to be exluded. + * Return true, if day is defined to be excluded. *

+ * + * @param day The day of the month (from 1 to 31) to check. */ public boolean isDayExcluded(int day) { + if ((day < 1) || (day > MAX_DAYS_IN_MONTH)) { + throw new IllegalArgumentException( + "The day parameter must be in the range of 1 to " + MAX_DAYS_IN_MONTH); + } + return excludeDays[day - 1]; } /** *

- * Redefine the array of days excluded. The array must of size greater or - * equal 31. + * Redefine the array of days excluded. The array must non-null and of size + * greater or equal to 31. The 0 index element represents the first day of + * the month. *

*/ public void setDaysExcluded(boolean[] days) { - if (days == null) return; + if (days == null) { + throw new IllegalArgumentException("The days parameter cannot be null."); + } + if (days.length < MAX_DAYS_IN_MONTH) { + throw new IllegalArgumentException( + "The days parameter must have a length of at least " + MAX_DAYS_IN_MONTH + " elements."); + } + excludeDays = days; excludeAll = areAllDaysExcluded(); } @@ -115,22 +127,29 @@ * Redefine a certain day of the month to be excluded (true) or included * (false). *

+ * + * @param day The day of the month (from 1 to 31) to set. */ public void setDayExcluded(int day, boolean exclude) { - excludeDays[day] = exclude; + if ((day < 1) || (day > MAX_DAYS_IN_MONTH)) { + throw new IllegalArgumentException( + "The day parameter must be in the range of 1 to " + MAX_DAYS_IN_MONTH); + } + + excludeDays[day - 1] = exclude; excludeAll = areAllDaysExcluded(); } /** *

* Check if all days are excluded. That is no day is included. *

- * - * @return boolean */ public boolean areAllDaysExcluded() { - for (int i = 1; i <= 31; i++) { - if (isDayExcluded(i) == false) return false; + for (int i = 1; i <= MAX_DAYS_IN_MONTH; i++) { + if (isDayExcluded(i) == false) { + return false; + } } return true; @@ -141,20 +160,22 @@ * Determine whether the given time (in milliseconds) is 'included' by the * Calendar. *

- * + * *

* Note that this Calendar is only has full-day precision. *

*/ + @Override public boolean isTimeIncluded(long timeStamp) { - if (excludeAll == true) return false; + if (excludeAll == true) { + return false; + } // Test the base calendar first. Only if the base calendar not already // excludes the time/date, continue evaluating this calendar instance. if (super.isTimeIncluded(timeStamp) == false) { return false; } - java.util.Calendar cl = java.util.Calendar.getInstance(); - cl.setTime(new Date(timeStamp)); + java.util.Calendar cl = createJavaCalendar(timeStamp); int day = cl.get(java.util.Calendar.DAY_OF_MONTH); return !(isDayExcluded(day)); @@ -166,29 +187,34 @@ * Calendar after the given time. Return the original value if timeStamp is * included. Return 0 if all days are excluded. *

- * + * *

* Note that this Calendar is only has full-day precision. *

*/ + @Override public long getNextIncludedTime(long timeStamp) { - if (excludeAll == true) return 0; + if (excludeAll == true) { + return 0; + } // Call base calendar implementation first long baseTime = super.getNextIncludedTime(timeStamp); - if ((baseTime > 0) && (baseTime > timeStamp)) timeStamp = baseTime; + if ((baseTime > 0) && (baseTime > timeStamp)) { + timeStamp = baseTime; + } // Get timestamp for 00:00:00 - long newTimeStamp = buildHoliday(timeStamp); - - java.util.Calendar cl = getJavaCalendar(newTimeStamp); + java.util.Calendar cl = getStartOfDayJavaCalendar(timeStamp); int day = cl.get(java.util.Calendar.DAY_OF_MONTH); - if (!isDayExcluded(day)) return timeStamp; // return the original value + if (!isDayExcluded(day)) { + return timeStamp; // return the original value + } while (isDayExcluded(day) == true) { cl.add(java.util.Calendar.DATE, 1); - day = cl.get(java.util.Calendar.DAY_OF_WEEK); + day = cl.get(java.util.Calendar.DAY_OF_MONTH); } return cl.getTime().getTime(); Index: 3rdParty_sources/quartz/org/quartz/impl/calendar/WeeklyCalendar.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/calendar/WeeklyCalendar.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/calendar/WeeklyCalendar.java 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/calendar/WeeklyCalendar.java 15 Dec 2014 10:09:54 -0000 1.1.2.1 @@ -1,46 +1,42 @@ -/* - * Copyright 2004-2005 OpenSymphony - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations +/* + * Copyright 2001-2009 Terracotta, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations * under the License. - * + * */ -/* - * Previously Copyright (c) 2001-2004 James House - * and Juergen Donnerstag (c) 2002, EDS 2002 - */ - package org.quartz.impl.calendar; import java.io.Serializable; -import java.util.Date; +import java.util.TimeZone; import org.quartz.Calendar; /** *

* This implementation of the Calendar excludes a set of days of the week. You * may use it to exclude weekends for example. But you may define any day of - * the week. + * the week. By default it excludes SATURDAY and SUNDAY. *

- * + * * @see org.quartz.Calendar * @see org.quartz.impl.calendar.BaseCalendar - * + * * @author Juergen Donnerstag */ public class WeeklyCalendar extends BaseCalendar implements Calendar, Serializable { + static final long serialVersionUID = -6809298821229007586L; // An array to store the week days which are to be excluded. // java.util.Calendar.MONDAY etc. are used as index. @@ -49,37 +45,33 @@ // Will be set to true, if all week days are excluded private boolean excludeAll = false; - /** - *

- * Constructor - *

- */ public WeeklyCalendar() { - super(); - init(); + this(null, null); } - /** - *

- * Constructor - *

- */ public WeeklyCalendar(Calendar baseCalendar) { - super(baseCalendar); - init(); + this(baseCalendar, null); } - /** - *

- * Initialize internal variables - *

- */ - private void init() { + public WeeklyCalendar(TimeZone timeZone) { + super(null, timeZone); + } + + public WeeklyCalendar(Calendar baseCalendar, TimeZone timeZone) { + super(baseCalendar, timeZone); + excludeDays[java.util.Calendar.SUNDAY] = true; excludeDays[java.util.Calendar.SATURDAY] = true; excludeAll = areAllDaysExcluded(); } + @Override + public Object clone() { + WeeklyCalendar clone = (WeeklyCalendar) super.clone(); + clone.excludeDays = excludeDays.clone(); + return clone; + } + /** *

* Get the array with the week days @@ -107,7 +99,9 @@ *

*/ public void setDaysExcluded(boolean[] weekDays) { - if (weekDays == null) return; + if (weekDays == null) { + return; + } excludeDays = weekDays; excludeAll = areAllDaysExcluded(); @@ -129,46 +123,41 @@ *

* Check if all week days are excluded. That is no day is included. *

- * + * * @return boolean */ public boolean areAllDaysExcluded() { - if (isDayExcluded(java.util.Calendar.SUNDAY) == false) return false; - - if (isDayExcluded(java.util.Calendar.MONDAY) == false) return false; - - if (isDayExcluded(java.util.Calendar.TUESDAY) == false) return false; - - if (isDayExcluded(java.util.Calendar.WEDNESDAY) == false) return false; - - if (isDayExcluded(java.util.Calendar.THURSDAY) == false) return false; - - if (isDayExcluded(java.util.Calendar.FRIDAY) == false) return false; - - if (isDayExcluded(java.util.Calendar.SATURDAY) == false) return false; - - return true; + return + isDayExcluded(java.util.Calendar.SUNDAY) && + isDayExcluded(java.util.Calendar.MONDAY) && + isDayExcluded(java.util.Calendar.TUESDAY) && + isDayExcluded(java.util.Calendar.WEDNESDAY) && + isDayExcluded(java.util.Calendar.THURSDAY) && + isDayExcluded(java.util.Calendar.FRIDAY) && + isDayExcluded(java.util.Calendar.SATURDAY); } /** *

* Determine whether the given time (in milliseconds) is 'included' by the * Calendar. *

- * + * *

* Note that this Calendar is only has full-day precision. *

*/ + @Override public boolean isTimeIncluded(long timeStamp) { - if (excludeAll == true) return false; + if (excludeAll == true) { + return false; + } // Test the base calendar first. Only if the base calendar not already // excludes the time/date, continue evaluating this calendar instance. if (super.isTimeIncluded(timeStamp) == false) { return false; } - java.util.Calendar cl = java.util.Calendar.getInstance(); - cl.setTime(new Date(timeStamp)); + java.util.Calendar cl = createJavaCalendar(timeStamp); int wday = cl.get(java.util.Calendar.DAY_OF_WEEK); return !(isDayExcluded(wday)); @@ -180,26 +169,30 @@ * Calendar after the given time. Return the original value if timeStamp is * included. Return 0 if all days are excluded. *

- * + * *

* Note that this Calendar is only has full-day precision. *

*/ + @Override public long getNextIncludedTime(long timeStamp) { - if (excludeAll == true) return 0; + if (excludeAll == true) { + return 0; + } // Call base calendar implementation first long baseTime = super.getNextIncludedTime(timeStamp); - if ((baseTime > 0) && (baseTime > timeStamp)) timeStamp = baseTime; + if ((baseTime > 0) && (baseTime > timeStamp)) { + timeStamp = baseTime; + } // Get timestamp for 00:00:00 - long newTimeStamp = buildHoliday(timeStamp); - - java.util.Calendar cl = getJavaCalendar(newTimeStamp); + java.util.Calendar cl = getStartOfDayJavaCalendar(timeStamp); int wday = cl.get(java.util.Calendar.DAY_OF_WEEK); - if (!isDayExcluded(wday)) return timeStamp; // return the original - // value + if (!isDayExcluded(wday)) { + return timeStamp; // return the original value + } while (isDayExcluded(wday) == true) { cl.add(java.util.Calendar.DATE, 1); Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/AttributeRestoringConnectionInvocationHandler.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/CUBRIDDelegate.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/CacheDelegate.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/CalendarIntervalTriggerPersistenceDelegate.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/CloudscapeDelegate.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/Constants.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/Constants.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/Constants.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/Constants.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,10 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ - package org.quartz.impl.jdbcjobstore; /** @@ -42,147 +38,158 @@ */ // Table names - public static final String TABLE_JOB_DETAILS = "JOB_DETAILS"; + String TABLE_JOB_DETAILS = "JOB_DETAILS"; - public static final String TABLE_TRIGGERS = "TRIGGERS"; + String TABLE_TRIGGERS = "TRIGGERS"; - public static final String TABLE_SIMPLE_TRIGGERS = "SIMPLE_TRIGGERS"; + String TABLE_SIMPLE_TRIGGERS = "SIMPLE_TRIGGERS"; - public static final String TABLE_CRON_TRIGGERS = "CRON_TRIGGERS"; + String TABLE_CRON_TRIGGERS = "CRON_TRIGGERS"; - public static final String TABLE_BLOB_TRIGGERS = "BLOB_TRIGGERS"; + String TABLE_BLOB_TRIGGERS = "BLOB_TRIGGERS"; - public static final String TABLE_FIRED_TRIGGERS = "FIRED_TRIGGERS"; + String TABLE_FIRED_TRIGGERS = "FIRED_TRIGGERS"; - public static final String TABLE_JOB_LISTENERS = "JOB_LISTENERS"; + String TABLE_CALENDARS = "CALENDARS"; - public static final String TABLE_TRIGGER_LISTENERS = "TRIGGER_LISTENERS"; + String TABLE_PAUSED_TRIGGERS = "PAUSED_TRIGGER_GRPS"; - public static final String TABLE_CALENDARS = "CALENDARS"; + String TABLE_LOCKS = "LOCKS"; - public static final String TABLE_PAUSED_TRIGGERS = "PAUSED_TRIGGER_GRPS"; + String TABLE_SCHEDULER_STATE = "SCHEDULER_STATE"; - public static final String TABLE_LOCKS = "LOCKS"; - - public static final String TABLE_SCHEDULER_STATE = "SCHEDULER_STATE"; - // TABLE_JOB_DETAILS columns names - public static final String COL_JOB_NAME = "JOB_NAME"; + + String COL_SCHEDULER_NAME = "SCHED_NAME"; + + String COL_JOB_NAME = "JOB_NAME"; - public static final String COL_JOB_GROUP = "JOB_GROUP"; + String COL_JOB_GROUP = "JOB_GROUP"; - public static final String COL_IS_DURABLE = "IS_DURABLE"; + String COL_IS_DURABLE = "IS_DURABLE"; - public static final String COL_IS_VOLATILE = "IS_VOLATILE"; + String COL_IS_VOLATILE = "IS_VOLATILE"; - public static final String COL_IS_STATEFUL = "IS_STATEFUL"; + String COL_IS_NONCONCURRENT = "IS_NONCONCURRENT"; - public static final String COL_REQUESTS_RECOVERY = "REQUESTS_RECOVERY"; + String COL_IS_UPDATE_DATA = "IS_UPDATE_DATA"; - public static final String COL_JOB_DATAMAP = "JOB_DATA"; + String COL_REQUESTS_RECOVERY = "REQUESTS_RECOVERY"; - public static final String COL_JOB_CLASS = "JOB_CLASS_NAME"; + String COL_JOB_DATAMAP = "JOB_DATA"; - public static final String COL_DESCRIPTION = "DESCRIPTION"; + String COL_JOB_CLASS = "JOB_CLASS_NAME"; - // TABLE_JOB_LISTENERS columns names - public static final String COL_JOB_LISTENER = "JOB_LISTENER"; + String COL_DESCRIPTION = "DESCRIPTION"; // TABLE_TRIGGERS columns names - public static final String COL_TRIGGER_NAME = "TRIGGER_NAME"; + String COL_TRIGGER_NAME = "TRIGGER_NAME"; - public static final String COL_TRIGGER_GROUP = "TRIGGER_GROUP"; + String COL_TRIGGER_GROUP = "TRIGGER_GROUP"; - public static final String COL_NEXT_FIRE_TIME = "NEXT_FIRE_TIME"; + String COL_NEXT_FIRE_TIME = "NEXT_FIRE_TIME"; - public static final String COL_PREV_FIRE_TIME = "PREV_FIRE_TIME"; + String COL_PREV_FIRE_TIME = "PREV_FIRE_TIME"; - public static final String COL_TRIGGER_STATE = "TRIGGER_STATE"; + String COL_TRIGGER_STATE = "TRIGGER_STATE"; - public static final String COL_TRIGGER_TYPE = "TRIGGER_TYPE"; + String COL_TRIGGER_TYPE = "TRIGGER_TYPE"; - public static final String COL_START_TIME = "START_TIME"; + String COL_START_TIME = "START_TIME"; - public static final String COL_END_TIME = "END_TIME"; + String COL_END_TIME = "END_TIME"; - public static final String COL_MISFIRE_INSTRUCTION = "MISFIRE_INSTR"; + String COL_PRIORITY = "PRIORITY"; - public static final String ALIAS_COL_NEXT_FIRE_TIME = "ALIAS_NXT_FR_TM"; + String COL_MISFIRE_INSTRUCTION = "MISFIRE_INSTR"; + String ALIAS_COL_NEXT_FIRE_TIME = "ALIAS_NXT_FR_TM"; + // TABLE_SIMPLE_TRIGGERS columns names - public static final String COL_REPEAT_COUNT = "REPEAT_COUNT"; + String COL_REPEAT_COUNT = "REPEAT_COUNT"; - public static final String COL_REPEAT_INTERVAL = "REPEAT_INTERVAL"; + String COL_REPEAT_INTERVAL = "REPEAT_INTERVAL"; - public static final String COL_TIMES_TRIGGERED = "TIMES_TRIGGERED"; + String COL_TIMES_TRIGGERED = "TIMES_TRIGGERED"; // TABLE_CRON_TRIGGERS columns names - public static final String COL_CRON_EXPRESSION = "CRON_EXPRESSION"; + String COL_CRON_EXPRESSION = "CRON_EXPRESSION"; // TABLE_BLOB_TRIGGERS columns names - public static final String COL_BLOB = "BLOB_DATA"; + String COL_BLOB = "BLOB_DATA"; - public static final String COL_TIME_ZONE_ID = "TIME_ZONE_ID"; + String COL_TIME_ZONE_ID = "TIME_ZONE_ID"; - // TABLE_TRIGGER_LISTENERS - public static final String COL_TRIGGER_LISTENER = "TRIGGER_LISTENER"; - // TABLE_FIRED_TRIGGERS columns names - public static final String COL_INSTANCE_NAME = "INSTANCE_NAME"; + String COL_INSTANCE_NAME = "INSTANCE_NAME"; - public static final String COL_FIRED_TIME = "FIRED_TIME"; + String COL_FIRED_TIME = "FIRED_TIME"; - public static final String COL_ENTRY_ID = "ENTRY_ID"; + String COL_SCHED_TIME = "SCHED_TIME"; + + String COL_ENTRY_ID = "ENTRY_ID"; - public static final String COL_ENTRY_STATE = "STATE"; + String COL_ENTRY_STATE = "STATE"; // TABLE_CALENDARS columns names - public static final String COL_CALENDAR_NAME = "CALENDAR_NAME"; + String COL_CALENDAR_NAME = "CALENDAR_NAME"; - public static final String COL_CALENDAR = "CALENDAR"; + String COL_CALENDAR = "CALENDAR"; // TABLE_LOCKS columns names - public static final String COL_LOCK_NAME = "LOCK_NAME"; + String COL_LOCK_NAME = "LOCK_NAME"; // TABLE_LOCKS columns names - public static final String COL_LAST_CHECKIN_TIME = "LAST_CHECKIN_TIME"; + String COL_LAST_CHECKIN_TIME = "LAST_CHECKIN_TIME"; - public static final String COL_CHECKIN_INTERVAL = "CHECKIN_INTERVAL"; + String COL_CHECKIN_INTERVAL = "CHECKIN_INTERVAL"; - public static final String COL_RECOVERER = "RECOVERER"; - // MISC CONSTANTS - public static final String DEFAULT_TABLE_PREFIX = "QRTZ_"; + String DEFAULT_TABLE_PREFIX = "QRTZ_"; // STATES - public final static String STATE_WAITING = "WAITING"; + String STATE_WAITING = "WAITING"; - public final static String STATE_ACQUIRED = "ACQUIRED"; + String STATE_ACQUIRED = "ACQUIRED"; - public final static String STATE_EXECUTING = "EXECUTING"; + String STATE_EXECUTING = "EXECUTING"; - public final static String STATE_COMPLETE = "COMPLETE"; + String STATE_COMPLETE = "COMPLETE"; - public final static String STATE_BLOCKED = "BLOCKED"; + String STATE_BLOCKED = "BLOCKED"; - public final static String STATE_ERROR = "ERROR"; + String STATE_ERROR = "ERROR"; - public final static String STATE_PAUSED = "PAUSED"; + String STATE_PAUSED = "PAUSED"; - public final static String STATE_PAUSED_BLOCKED = "PAUSED_BLOCKED"; + String STATE_PAUSED_BLOCKED = "PAUSED_BLOCKED"; - public final static String STATE_DELETED = "DELETED"; + String STATE_DELETED = "DELETED"; - public final static String STATE_MISFIRED = "MISFIRED"; + /** + * @deprecated Whether a trigger has misfired is no longer a state, but + * rather now identified dynamically by whether the trigger's next fire + * time is more than the misfire threshold time in the past. + */ + String STATE_MISFIRED = "MISFIRED"; - public final static String ALL_GROUPS_PAUSED = "_$_ALL_GROUPS_PAUSED_$_"; + String ALL_GROUPS_PAUSED = "_$_ALL_GROUPS_PAUSED_$_"; // TRIGGER TYPES - public final static String TTYPE_SIMPLE = "SIMPLE"; + /** Simple Trigger type. */ + String TTYPE_SIMPLE = "SIMPLE"; - public final static String TTYPE_CRON = "CRON"; + /** Cron Trigger type. */ + String TTYPE_CRON = "CRON"; - public final static String TTYPE_BLOB = "BLOB"; + /** Calendar Interval Trigger type. */ + String TTYPE_CAL_INT = "CAL_INT"; + + /** Daily Time Interval Trigger type. */ + String TTYPE_DAILY_TIME_INT = "DAILY_I"; + + /** A general blob Trigger type. */ + String TTYPE_BLOB = "BLOB"; } // EOF Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/CronTriggerPersistenceDelegate.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DB2v6Delegate.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DB2v6Delegate.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DB2v6Delegate.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DB2v6Delegate.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,18 +15,16 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; -import org.apache.commons.logging.Log; +import org.quartz.JobKey; +import org.quartz.spi.ClassLoadHelper; +import org.slf4j.Logger; /** * Quartz JDBC delegate for DB2 v6 databases. select count(name) @@ -36,31 +34,32 @@ * @author James House */ public class DB2v6Delegate extends StdJDBCDelegate { + @SuppressWarnings("hiding") public static final String SELECT_NUM_JOBS = "SELECT COUNT(*) FROM " - + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS; + + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; + @SuppressWarnings("hiding") public static final String SELECT_NUM_TRIGGERS_FOR_JOB = "SELECT COUNT(*) FROM " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_JOB_NAME + " = ? AND " + COL_JOB_GROUP + " = ?"; + @SuppressWarnings("hiding") public static final String SELECT_NUM_TRIGGERS = "SELECT COUNT(*) FROM " - + TABLE_PREFIX_SUBST + TABLE_TRIGGERS; + + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; + @SuppressWarnings("hiding") public static final String SELECT_NUM_CALENDARS = "SELECT COUNT(*) FROM " - + TABLE_PREFIX_SUBST + TABLE_CALENDARS; + + TABLE_PREFIX_SUBST + TABLE_CALENDARS + + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; - public DB2v6Delegate(Log logger, String tablePrefix, String instanceId) { - super(logger, tablePrefix, instanceId); - } - - public DB2v6Delegate(Log logger, String tablePrefix, String instanceId, - Boolean useProperties) { - super(logger, tablePrefix, instanceId, useProperties); - } - + @Override public int selectNumJobs(Connection conn) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; @@ -76,19 +75,20 @@ return count; } finally { - close(ps); + closeResultSet(rs); + closeStatement(ps); } } - public int selectNumTriggersForJob(Connection conn, String jobName, - String groupName) throws SQLException { + @Override + public int selectNumTriggersForJob(Connection conn, JobKey jobKey) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_NUM_TRIGGERS_FOR_JOB)); - ps.setString(1, jobName); - ps.setString(2, groupName); + ps.setString(1, jobKey.getName()); + ps.setString(2, jobKey.getGroup()); rs = ps.executeQuery(); if (rs.next()) { @@ -97,10 +97,12 @@ return 0; } } finally { - close(ps); + closeResultSet(rs); + closeStatement(ps); } } + @Override public int selectNumTriggers(Connection conn) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; @@ -116,10 +118,12 @@ return count; } finally { - close(ps); + closeResultSet(rs); + closeStatement(ps); } } + @Override public int selectNumCalendars(Connection conn) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; @@ -135,18 +139,10 @@ return count; } finally { - close(ps); + closeResultSet(rs); + closeStatement(ps); } } - - private void close(Statement stmt) { - if (stmt != null) { - try { - stmt.close(); - } catch (SQLException ignore) { - } - } - } } // EOF Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DB2v7Delegate.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DB2v7Delegate.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DB2v7Delegate.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DB2v7Delegate.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,536 +15,49 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.math.BigDecimal; -import java.sql.Connection; import java.sql.PreparedStatement; -import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Date; -import org.quartz.impl.jdbcjobstore.StdJDBCDelegate; -import org.apache.commons.logging.Log; -import org.quartz.Calendar; -import org.quartz.CronTrigger; -import org.quartz.JobDataMap; -import org.quartz.JobDetail; -import org.quartz.Scheduler; -import org.quartz.SimpleTrigger; -import org.quartz.Trigger; -import org.quartz.utils.Key; +import org.quartz.spi.ClassLoadHelper; +import org.slf4j.Logger; /** * Quartz JDBC delegate for DB2 v7 databases. + *

+ * This differs from the StdJDBCDelegate in that it stores + * boolean values in an varchar(1) column, and saves + * serialized data in a byte array using + * {@link PreparedStatement#setObject(int, java.lang.Object, int)} + * rather than {@link PreparedStatement#setBytes(int, byte[])}. + *

* * @author Blair Jensen */ public class DB2v7Delegate extends StdJDBCDelegate { - public DB2v7Delegate(Log logger, String tablePrefix, String instanceId) { - super(logger, tablePrefix, instanceId); + /** + * Sets the designated parameter to the byte array of the given + * ByteArrayOutputStream. Will set parameter value to null if the + * ByteArrayOutputStream is null. + * Wraps {@link PreparedStatement#setObject(int, java.lang.Object, int)} rather than + * {@link PreparedStatement#setBytes(int, byte[])} as required by the + * DB2 v7 database. + */ + @Override + protected void setBytes(PreparedStatement ps, int index, ByteArrayOutputStream baos) throws SQLException { + ps.setObject(index, ((baos == null) ? null : baos.toByteArray()), java.sql.Types.BLOB); } - public DB2v7Delegate(Log log, String tablePrefix, String instanceId, - Boolean useProperties) { - super(log, tablePrefix, instanceId, useProperties); + /** + * Sets the designated parameter to the given Java boolean value. + * This translates the boolean to 1/0 for true/false. + */ + @Override + protected void setBoolean(PreparedStatement ps, int index, boolean val) throws SQLException { + ps.setString(index, ((val) ? "1" : "0")); } - public Trigger[] selectTriggersForRecoveringJobs(Connection conn) - throws SQLException, IOException, ClassNotFoundException { - PreparedStatement ps = null; - ResultSet rs = null; - - try { - ps = conn - .prepareStatement(rtp(SELECT_INSTANCES_RECOVERABLE_FIRED_TRIGGERS)); - ps.setString(1, instanceId); - ps.setString(2, "1"); - //ps.setBoolean(2, true); - rs = ps.executeQuery(); - - long dumId = System.currentTimeMillis(); - ArrayList list = new ArrayList(); - while (rs.next()) { - String jobName = rs.getString(COL_JOB_NAME); - String jobGroup = rs.getString(COL_JOB_GROUP); - String trigName = rs.getString(COL_TRIGGER_NAME); - String trigGroup = rs.getString(COL_TRIGGER_GROUP); - long firedTime = rs.getLong(COL_FIRED_TIME); - SimpleTrigger rcvryTrig = new SimpleTrigger("recover_" - + instanceId + "_" + String.valueOf(dumId++), - Scheduler.DEFAULT_RECOVERY_GROUP, new Date(firedTime)); - rcvryTrig.setJobName(jobName); - rcvryTrig.setJobGroup(jobGroup); - rcvryTrig - .setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW); - - JobDataMap jd = selectTriggerJobDataMap(conn, trigName, trigGroup); - jd.put("QRTZ_FAILED_JOB_ORIG_TRIGGER_NAME", trigName); - jd.put("QRTZ_FAILED_JOB_ORIG_TRIGGER_GROUP", trigGroup); - jd.put("QRTZ_FAILED_JOB_ORIG_TRIGGER_FIRETIME_IN_MILLISECONDS_AS_STRING", String.valueOf(firedTime)); - rcvryTrig.setJobDataMap(jd); - - list.add(rcvryTrig); - } - Object[] oArr = list.toArray(); - Trigger[] tArr = new Trigger[oArr.length]; - System.arraycopy(oArr, 0, tArr, 0, oArr.length); - return tArr; - } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - public int insertJobDetail(Connection conn, JobDetail job) - throws IOException, SQLException { - ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap()); - - PreparedStatement ps = null; - - int insertResult = 0; - - try { - - ps = conn.prepareStatement(rtp(INSERT_JOB_DETAIL)); - ps.setString(1, job.getName()); - ps.setString(2, job.getGroup()); - ps.setString(3, job.getDescription()); - ps.setString(4, job.getJobClass().getName()); - ps.setString(5, toBooleanIntString(job.isDurable())); - ps.setString(6, toBooleanIntString(job.isVolatile())); - ps.setString(7, toBooleanIntString(job.isStateful())); - ps.setString(8, toBooleanIntString(job.requestsRecovery())); - //ps.setBoolean (5, job.isDurable()); - //ps.setBoolean (6, job.isVolatile()); - //ps.setBoolean (7, job.isStateful()); - //ps.setBoolean (8, job.requestsRecovery()); - ps.setObject(9, baos.toByteArray(), java.sql.Types.BLOB); - //ps.setBytes (9, baos.toByteArray()); - - insertResult = ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - - if (insertResult > 0) { - String[] jobListeners = job.getJobListenerNames(); - for (int i = 0; jobListeners != null && i < jobListeners.length; i++) - insertJobListener(conn, job, jobListeners[i]); - } - - return insertResult; - } - - public int updateJobDetail(Connection conn, JobDetail job) - throws IOException, SQLException { - ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap()); - - PreparedStatement ps = null; - - int insertResult = 0; - - try { - ps = conn.prepareStatement(rtp(UPDATE_JOB_DETAIL)); - ps.setString(1, job.getDescription()); - ps.setString(2, job.getJobClass().getName()); - ps.setString(3, toBooleanIntString(job.isDurable())); - ps.setString(4, toBooleanIntString(job.isVolatile())); - ps.setString(5, toBooleanIntString(job.isStateful())); - ps.setString(6, toBooleanIntString(job.requestsRecovery())); - //ps.setBoolean (3, job.isDurable()); - //ps.setBoolean (4, job.isVolatile()); - //ps.setBoolean (5, job.isStateful()); - //ps.setBoolean (6, job.requestsRecovery()); - ps.setObject(7, baos.toByteArray(), java.sql.Types.BLOB); - //ps.setBytes (7, baos.toByteArray()); - ps.setString(8, job.getName()); - ps.setString(9, job.getGroup()); - - insertResult = ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - - if (insertResult > 0) { - deleteJobListeners(conn, job.getName(), job.getGroup()); - - String[] jobListeners = job.getJobListenerNames(); - for (int i = 0; jobListeners != null && i < jobListeners.length; i++) - insertJobListener(conn, job, jobListeners[i]); - } - - return insertResult; - } - - public int insertTrigger(Connection conn, Trigger trigger, String state, - JobDetail jobDetail) throws SQLException, IOException { - - ByteArrayOutputStream baos = serializeJobData(trigger.getJobDataMap()); - - PreparedStatement ps = null; - - int insertResult = 0; - - try { - ps = conn.prepareStatement(rtp(INSERT_TRIGGER)); - ps.setString(1, trigger.getName()); - ps.setString(2, trigger.getGroup()); - ps.setString(3, trigger.getJobName()); - ps.setString(4, trigger.getJobGroup()); - ps.setString(5, toBooleanIntString(trigger.isVolatile())); - //ps.setBoolean(5, trigger.isVolatile()); - ps.setString(6, trigger.getDescription()); - ps.setBigDecimal(7, new BigDecimal(String.valueOf(trigger - .getNextFireTime().getTime()))); - long prevFireTime = -1; - if (trigger.getPreviousFireTime() != null) { - prevFireTime = trigger.getPreviousFireTime().getTime(); - } - ps.setBigDecimal(8, new BigDecimal(String.valueOf(prevFireTime))); - ps.setString(9, state); - if (trigger instanceof SimpleTrigger) { - ps.setString(10, TTYPE_SIMPLE); - } else if (trigger instanceof CronTrigger) { - ps.setString(10, TTYPE_CRON); - } else { // (trigger instanceof BlobTrigger) - ps.setString(10, TTYPE_BLOB); - } - ps.setBigDecimal(11, new BigDecimal(String.valueOf(trigger - .getStartTime().getTime()))); - long endTime = 0; - if (trigger.getEndTime() != null) { - endTime = trigger.getEndTime().getTime(); - } - ps.setBigDecimal(12, new BigDecimal(String.valueOf(endTime))); - ps.setString(13, trigger.getCalendarName()); - ps.setInt(14, trigger.getMisfireInstruction()); - ps.setObject(15, baos.toByteArray(), java.sql.Types.BLOB); - - insertResult = ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - - if (insertResult > 0) { - String[] trigListeners = trigger.getTriggerListenerNames(); - for (int i = 0; trigListeners != null && i < trigListeners.length; i++) - insertTriggerListener(conn, trigger, trigListeners[i]); - } - - return insertResult; - } - - public int updateTrigger(Connection conn, Trigger trigger, String state, - JobDetail jobDetail) throws SQLException, IOException { - ByteArrayOutputStream baos = serializeJobData(trigger.getJobDataMap()); - - PreparedStatement ps = null; - - int insertResult = 0; - - try { - ps = conn.prepareStatement(rtp(UPDATE_TRIGGER)); - ps.setString(1, trigger.getJobName()); - ps.setString(2, trigger.getJobGroup()); - ps.setString(3, toBooleanIntString(trigger.isVolatile())); - //ps.setBoolean(3, trigger.isVolatile()); - ps.setString(4, trigger.getDescription()); - long nextFireTime = -1; - if (trigger.getNextFireTime() != null) { - nextFireTime = trigger.getNextFireTime().getTime(); - } - ps.setBigDecimal(5, new BigDecimal(String.valueOf(nextFireTime))); - long prevFireTime = -1; - if (trigger.getPreviousFireTime() != null) { - prevFireTime = trigger.getPreviousFireTime().getTime(); - } - ps.setBigDecimal(6, new BigDecimal(String.valueOf(prevFireTime))); - ps.setString(7, state); - if (trigger instanceof SimpleTrigger) { - // updateSimpleTrigger(conn, (SimpleTrigger)trigger); - ps.setString(8, TTYPE_SIMPLE); - } else if (trigger instanceof CronTrigger) { - // updateCronTrigger(conn, (CronTrigger)trigger); - ps.setString(8, TTYPE_CRON); - } else { - // updateBlobTrigger(conn, trigger); - ps.setString(8, TTYPE_BLOB); - } - ps.setBigDecimal(9, new BigDecimal(String.valueOf(trigger - .getStartTime().getTime()))); - long endTime = 0; - if (trigger.getEndTime() != null) { - endTime = trigger.getEndTime().getTime(); - } - ps.setBigDecimal(10, new BigDecimal(String.valueOf(endTime))); - ps.setString(11, trigger.getCalendarName()); - ps.setInt(12, trigger.getMisfireInstruction()); - ps.setObject(13, baos.toByteArray(), java.sql.Types.BLOB); - ps.setString(14, trigger.getName()); - ps.setString(15, trigger.getGroup()); - - insertResult = ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - - if (insertResult > 0) { - deleteTriggerListeners(conn, trigger.getName(), trigger.getGroup()); - - String[] trigListeners = trigger.getTriggerListenerNames(); - for (int i = 0; trigListeners != null && i < trigListeners.length; i++) - insertTriggerListener(conn, trigger, trigListeners[i]); - } - - return insertResult; - } - - public int insertFiredTrigger(Connection conn, Trigger trigger, - String state, JobDetail job) throws SQLException { - PreparedStatement ps = null; - try { - ps = conn.prepareStatement(rtp(INSERT_FIRED_TRIGGER)); - ps.setString(1, trigger.getFireInstanceId()); - ps.setString(2, trigger.getName()); - ps.setString(3, trigger.getGroup()); - ps.setString(4, toBooleanIntString(trigger.isVolatile())); - //ps.setBoolean(4, trigger.isVolatile()); - ps.setString(5, instanceId); - ps.setBigDecimal(6, new BigDecimal(String.valueOf(trigger - .getNextFireTime().getTime()))); - ps.setString(7, state); - if (job != null) { - ps.setString(8, trigger.getJobName()); - ps.setString(9, trigger.getJobGroup()); - ps.setString(10, toBooleanIntString(job.isStateful())); - ps.setString(11, toBooleanIntString(job.requestsRecovery())); - //ps.setBoolean(10, job.isStateful()); - //ps.setBoolean(11, job.requestsRecovery()); - } else { - ps.setString(8, null); - ps.setString(9, null); - ps.setString(10, "0"); - ps.setString(11, "0"); - //ps.setBoolean(10, false); - //ps.setBoolean(11, false); - } - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - public int updateJobData(Connection conn, JobDetail job) - throws IOException, SQLException { - ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap()); - - PreparedStatement ps = null; - - try { - ps = conn.prepareStatement(rtp(UPDATE_JOB_DATA)); - ps.setObject(1, baos.toByteArray(), java.sql.Types.BLOB); - //ps.setBytes(1, baos.toByteArray()); - ps.setString(2, job.getName()); - ps.setString(3, job.getGroup()); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - public int insertCalendar(Connection conn, String calendarName, - Calendar calendar) throws IOException, SQLException { - ByteArrayOutputStream baos = serializeObject(calendar); - - PreparedStatement ps = null; - - try { - ps = conn.prepareStatement(rtp(INSERT_CALENDAR)); - ps.setString(1, calendarName); - ps.setObject(2, baos.toByteArray(), java.sql.Types.BLOB); - //ps.setBytes(2, baos.toByteArray()); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - public int updateCalendar(Connection conn, String calendarName, - Calendar calendar) throws IOException, SQLException { - ByteArrayOutputStream baos = serializeObject(calendar); - - PreparedStatement ps = null; - - try { - ps = conn.prepareStatement(rtp(UPDATE_CALENDAR)); - ps.setString(1, calendarName); - ps.setObject(2, baos.toByteArray(), java.sql.Types.BLOB); - //ps.setBytes(2, baos.toByteArray()); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - public int deleteVolatileFiredTriggers(Connection conn) throws SQLException { - PreparedStatement ps = null; - try { - ps = conn.prepareStatement(rtp(DELETE_VOLATILE_FIRED_TRIGGERS)); - ps.setString(1, "1"); - //ps.setBoolean(1, true); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - public Key[] selectVolatileTriggers(Connection conn) throws SQLException { - PreparedStatement ps = null; - ResultSet rs = null; - - try { - ps = conn.prepareStatement(rtp(SELECT_VOLATILE_TRIGGERS)); - ps.setString(1, "1"); - //ps.setBoolean(1, true); - rs = ps.executeQuery(); - - ArrayList list = new ArrayList(); - while (rs.next()) { - String triggerName = rs.getString(COL_TRIGGER_NAME); - String groupName = rs.getString(COL_TRIGGER_GROUP); - list.add(new Key(triggerName, groupName)); - } - Object[] oArr = list.toArray(); - Key[] kArr = new Key[oArr.length]; - System.arraycopy(oArr, 0, kArr, 0, oArr.length); - return kArr; - } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - public Key[] selectVolatileJobs(Connection conn) throws SQLException { - PreparedStatement ps = null; - ResultSet rs = null; - - try { - ps = conn.prepareStatement(rtp(SELECT_VOLATILE_JOBS)); - ps.setString(1, "1"); - //ps.setBoolean(1, true); - rs = ps.executeQuery(); - - ArrayList list = new ArrayList(); - while (rs.next()) { - String triggerName = rs.getString(COL_JOB_NAME); - String groupName = rs.getString(COL_JOB_GROUP); - list.add(new Key(triggerName, groupName)); - } - Object[] oArr = list.toArray(); - Key[] kArr = new Key[oArr.length]; - System.arraycopy(oArr, 0, kArr, 0, oArr.length); - return kArr; - } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - private static String toBooleanIntString(boolean theBoolean) { - if (String.valueOf(theBoolean).equals("true")) { - return "1"; - } else { - return "0"; - } - } - } Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DB2v8Delegate.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DB2v8Delegate.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DB2v8Delegate.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DB2v8Delegate.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,536 +16,29 @@ */ package org.quartz.impl.jdbcjobstore; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.math.BigDecimal; -import java.sql.Connection; import java.sql.PreparedStatement; -import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Date; -import org.apache.commons.logging.Log; -import org.quartz.Calendar; -import org.quartz.CronTrigger; -import org.quartz.JobDataMap; -import org.quartz.JobDetail; -import org.quartz.Scheduler; -import org.quartz.SimpleTrigger; -import org.quartz.Trigger; -import org.quartz.utils.Key; +import org.quartz.spi.ClassLoadHelper; +import org.slf4j.Logger; /** * Quartz JDBC delegate for DB2 v8 databases. + *

+ * This differs from the StdJDBCDelegate in that it stores + * boolean values in an integer column. + *

* * @author Blair Jensen */ public class DB2v8Delegate extends StdJDBCDelegate { - public DB2v8Delegate(Log logger, String tablePrefix, String instanceId) { - super(logger, tablePrefix, instanceId); + /** + * Sets the designated parameter to the given Java boolean value. + * This translates the boolean to 1/0 for true/false. + */ + @Override + protected void setBoolean(PreparedStatement ps, int index, boolean val) throws SQLException { + ps.setInt(index, ((val) ? 1 : 0)); } - - public DB2v8Delegate(Log log, String tablePrefix, String instanceId, - Boolean useProperties) { - super(log, tablePrefix, instanceId, useProperties); - } - - public Trigger[] selectTriggersForRecoveringJobs(Connection conn) - throws SQLException, IOException, ClassNotFoundException { - PreparedStatement ps = null; - ResultSet rs = null; - - try { - ps = conn - .prepareStatement(rtp(SELECT_INSTANCES_RECOVERABLE_FIRED_TRIGGERS)); - ps.setString(1, instanceId); - ps.setInt(2, 1); - //ps.setBoolean(2, true); - rs = ps.executeQuery(); - - long dumId = System.currentTimeMillis(); - ArrayList list = new ArrayList(); - while (rs.next()) { - String jobName = rs.getString(COL_JOB_NAME); - String jobGroup = rs.getString(COL_JOB_GROUP); - String trigName = rs.getString(COL_TRIGGER_NAME); - String trigGroup = rs.getString(COL_TRIGGER_GROUP); - long firedTime = rs.getLong(COL_FIRED_TIME); - SimpleTrigger rcvryTrig = new SimpleTrigger("recover_" - + instanceId + "_" + String.valueOf(dumId++), - Scheduler.DEFAULT_RECOVERY_GROUP, new Date(firedTime)); - rcvryTrig.setJobName(jobName); - rcvryTrig.setJobGroup(jobGroup); - rcvryTrig - .setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW); - - JobDataMap jd = selectTriggerJobDataMap(conn, trigName, trigGroup); - jd.put("QRTZ_FAILED_JOB_ORIG_TRIGGER_NAME", trigName); - jd.put("QRTZ_FAILED_JOB_ORIG_TRIGGER_GROUP", trigGroup); - jd.put("QRTZ_FAILED_JOB_ORIG_TRIGGER_FIRETIME_IN_MILLISECONDS_AS_STRING", String.valueOf(firedTime)); - rcvryTrig.setJobDataMap(jd); - - list.add(rcvryTrig); - } - Object[] oArr = list.toArray(); - Trigger[] tArr = new Trigger[oArr.length]; - System.arraycopy(oArr, 0, tArr, 0, oArr.length); - return tArr; - } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - public int insertJobDetail(Connection conn, JobDetail job) - throws IOException, SQLException { - ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap()); - - PreparedStatement ps = null; - - int insertResult = 0; - - try { - - ps = conn.prepareStatement(rtp(INSERT_JOB_DETAIL)); - ps.setString(1, job.getName()); - ps.setString(2, job.getGroup()); - ps.setString(3, job.getDescription()); - ps.setString(4, job.getJobClass().getName()); - ps.setInt(5, toBooleanInt(job.isDurable())); - ps.setInt(6, toBooleanInt(job.isVolatile())); - ps.setInt(7, toBooleanInt(job.isStateful())); - ps.setInt(8, toBooleanInt(job.requestsRecovery())); - //ps.setBoolean (5, job.isDurable()); - //ps.setBoolean (6, job.isVolatile()); - //ps.setBoolean (7, job.isStateful()); - //ps.setBoolean (8, job.requestsRecovery()); - ps.setBytes(9, baos.toByteArray()); - //ps.setObject(9, baos.toByteArray(), Types.BLOB); - - insertResult = ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - - if (insertResult > 0) { - String[] jobListeners = job.getJobListenerNames(); - for (int i = 0; jobListeners != null && i < jobListeners.length; i++) - insertJobListener(conn, job, jobListeners[i]); - } - - return insertResult; - } - - public int updateJobDetail(Connection conn, JobDetail job) - throws IOException, SQLException { - ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap()); - - PreparedStatement ps = null; - - int insertResult = 0; - - try { - ps = conn.prepareStatement(rtp(UPDATE_JOB_DETAIL)); - ps.setString(1, job.getDescription()); - ps.setString(2, job.getJobClass().getName()); - ps.setInt(3, toBooleanInt(job.isDurable())); - ps.setInt(4, toBooleanInt(job.isVolatile())); - ps.setInt(5, toBooleanInt(job.isStateful())); - ps.setInt(6, toBooleanInt(job.requestsRecovery())); - //ps.setBoolean (3, job.isDurable()); - //ps.setBoolean (4, job.isVolatile()); - //ps.setBoolean (5, job.isStateful()); - //ps.setBoolean (6, job.requestsRecovery()); - ps.setBytes (7, baos.toByteArray()); - //ps.setObject(7, baos.toByteArray(), java.sql.Types.BLOB); - ps.setString(8, job.getName()); - ps.setString(9, job.getGroup()); - - insertResult = ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - - if (insertResult > 0) { - deleteJobListeners(conn, job.getName(), job.getGroup()); - - String[] jobListeners = job.getJobListenerNames(); - for (int i = 0; jobListeners != null && i < jobListeners.length; i++) - insertJobListener(conn, job, jobListeners[i]); - } - - return insertResult; - } - - public int insertTrigger(Connection conn, Trigger trigger, String state, - JobDetail jobDetail) throws SQLException, IOException { - ByteArrayOutputStream baos = serializeJobData(trigger.getJobDataMap()); - - PreparedStatement ps = null; - - int insertResult = 0; - - try { - ps = conn.prepareStatement(rtp(INSERT_TRIGGER)); - ps.setString(1, trigger.getName()); - ps.setString(2, trigger.getGroup()); - ps.setString(3, trigger.getJobName()); - ps.setString(4, trigger.getJobGroup()); - ps.setInt(5, toBooleanInt(trigger.isVolatile())); - //ps.setBoolean(5, trigger.isVolatile()); - ps.setString(6, trigger.getDescription()); - ps.setBigDecimal(7, new BigDecimal(String.valueOf(trigger - .getNextFireTime().getTime()))); - long prevFireTime = -1; - if (trigger.getPreviousFireTime() != null) { - prevFireTime = trigger.getPreviousFireTime().getTime(); - } - ps.setBigDecimal(8, new BigDecimal(String.valueOf(prevFireTime))); - ps.setString(9, state); - if (trigger instanceof SimpleTrigger) { - ps.setString(10, TTYPE_SIMPLE); - } else if (trigger instanceof CronTrigger) { - ps.setString(10, TTYPE_CRON); - } else { // (trigger instanceof BlobTrigger) - ps.setString(10, TTYPE_BLOB); - } - ps.setBigDecimal(11, new BigDecimal(String.valueOf(trigger - .getStartTime().getTime()))); - long endTime = 0; - if (trigger.getEndTime() != null) { - endTime = trigger.getEndTime().getTime(); - } - ps.setBigDecimal(12, new BigDecimal(String.valueOf(endTime))); - ps.setString(13, trigger.getCalendarName()); - ps.setInt(14, trigger.getMisfireInstruction()); - ps.setBytes(15, baos.toByteArray()); - - insertResult = ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - - if (insertResult > 0) { - String[] trigListeners = trigger.getTriggerListenerNames(); - for (int i = 0; trigListeners != null && i < trigListeners.length; i++) - insertTriggerListener(conn, trigger, trigListeners[i]); - } - - return insertResult; - } - - public int updateTrigger(Connection conn, Trigger trigger, String state, - JobDetail jobDetail) throws SQLException, IOException { - ByteArrayOutputStream baos = serializeJobData(trigger.getJobDataMap()); - - PreparedStatement ps = null; - - int insertResult = 0; - - try { - ps = conn.prepareStatement(rtp(UPDATE_TRIGGER)); - ps.setString(1, trigger.getJobName()); - ps.setString(2, trigger.getJobGroup()); - ps.setInt(3, toBooleanInt(trigger.isVolatile())); - //ps.setBoolean(3, trigger.isVolatile()); - ps.setString(4, trigger.getDescription()); - long nextFireTime = -1; - if (trigger.getNextFireTime() != null) { - nextFireTime = trigger.getNextFireTime().getTime(); - } - ps.setBigDecimal(5, new BigDecimal(String.valueOf(nextFireTime))); - long prevFireTime = -1; - if (trigger.getPreviousFireTime() != null) { - prevFireTime = trigger.getPreviousFireTime().getTime(); - } - ps.setBigDecimal(6, new BigDecimal(String.valueOf(prevFireTime))); - ps.setString(7, state); - if (trigger instanceof SimpleTrigger) { - // updateSimpleTrigger(conn, (SimpleTrigger)trigger); - ps.setString(8, TTYPE_SIMPLE); - } else if (trigger instanceof CronTrigger) { - // updateCronTrigger(conn, (CronTrigger)trigger); - ps.setString(8, TTYPE_CRON); - } else { - // updateBlobTrigger(conn, trigger); - ps.setString(8, TTYPE_BLOB); - } - ps.setBigDecimal(9, new BigDecimal(String.valueOf(trigger - .getStartTime().getTime()))); - long endTime = 0; - if (trigger.getEndTime() != null) { - endTime = trigger.getEndTime().getTime(); - } - ps.setBigDecimal(10, new BigDecimal(String.valueOf(endTime))); - ps.setString(11, trigger.getCalendarName()); - ps.setInt(12, trigger.getMisfireInstruction()); - ps.setBytes (13, baos.toByteArray()); - ps.setString(14, trigger.getName()); - ps.setString(15, trigger.getGroup()); - - insertResult = ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - - if (insertResult > 0) { - deleteTriggerListeners(conn, trigger.getName(), trigger.getGroup()); - - String[] trigListeners = trigger.getTriggerListenerNames(); - for (int i = 0; trigListeners != null && i < trigListeners.length; i++) - insertTriggerListener(conn, trigger, trigListeners[i]); - } - - return insertResult; - } - - public int insertFiredTrigger(Connection conn, Trigger trigger, - String state, JobDetail job) throws SQLException { - PreparedStatement ps = null; - try { - ps = conn.prepareStatement(rtp(INSERT_FIRED_TRIGGER)); - ps.setString(1, trigger.getFireInstanceId()); - ps.setString(2, trigger.getName()); - ps.setString(3, trigger.getGroup()); - ps.setInt(4, toBooleanInt(trigger.isVolatile())); - //ps.setBoolean(4, trigger.isVolatile()); - ps.setString(5, instanceId); - ps.setBigDecimal(6, new BigDecimal(String.valueOf(trigger - .getNextFireTime().getTime()))); - ps.setString(7, state); - if (job != null) { - ps.setString(8, trigger.getJobName()); - ps.setString(9, trigger.getJobGroup()); - ps.setInt(10, toBooleanInt(job.isStateful())); - ps.setInt(11, toBooleanInt(job.requestsRecovery())); - //ps.setBoolean(10, job.isStateful()); - //ps.setBoolean(11, job.requestsRecovery()); - } else { - ps.setString(8, null); - ps.setString(9, null); - ps.setInt(10, 0); - ps.setInt(11, 0); - //ps.setBoolean(10, false); - //ps.setBoolean(11, false); - } - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - public int updateJobData(Connection conn, JobDetail job) - throws IOException, SQLException { - ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap()); - - PreparedStatement ps = null; - - try { - ps = conn.prepareStatement(rtp(UPDATE_JOB_DATA)); - ps.setBytes(1, baos.toByteArray()); - //ps.setObject(1, baos.toByteArray(), java.sql.Types.BLOB); - ps.setString(2, job.getName()); - ps.setString(3, job.getGroup()); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - public int insertCalendar(Connection conn, String calendarName, - Calendar calendar) throws IOException, SQLException { - ByteArrayOutputStream baos = serializeObject(calendar); - - PreparedStatement ps = null; - - try { - ps = conn.prepareStatement(rtp(INSERT_CALENDAR)); - ps.setString(1, calendarName); - ps.setBytes(2, baos.toByteArray()); - //ps.setObject(2, baos.toByteArray(), java.sql.Types.BLOB); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - public int updateCalendar(Connection conn, String calendarName, - Calendar calendar) throws IOException, SQLException { - ByteArrayOutputStream baos = serializeObject(calendar); - - PreparedStatement ps = null; - - try { - ps = conn.prepareStatement(rtp(UPDATE_CALENDAR)); - ps.setBytes(1, baos.toByteArray()); - ps.setString(2, calendarName); - //ps.setObject(2, calendar, java.sql.Types.BLOB); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - public int deleteVolatileFiredTriggers(Connection conn) throws SQLException { - PreparedStatement ps = null; - try { - ps = conn.prepareStatement(rtp(DELETE_VOLATILE_FIRED_TRIGGERS)); - ps.setInt(1, 1); - //ps.setBoolean(1, true); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - public Key[] selectVolatileTriggers(Connection conn) throws SQLException { - PreparedStatement ps = null; - ResultSet rs = null; - - try { - ps = conn.prepareStatement(rtp(SELECT_VOLATILE_TRIGGERS)); - ps.setInt(1, 1); // boolean true - //ps.setBoolean(1, true); - rs = ps.executeQuery(); - - ArrayList list = new ArrayList(); - while (rs.next()) { - String triggerName = rs.getString(COL_TRIGGER_NAME); - String groupName = rs.getString(COL_TRIGGER_GROUP); - list.add(new Key(triggerName, groupName)); - } - Object[] oArr = list.toArray(); - Key[] kArr = new Key[oArr.length]; - System.arraycopy(oArr, 0, kArr, 0, oArr.length); - return kArr; - } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - public Key[] selectVolatileJobs(Connection conn) throws SQLException { - PreparedStatement ps = null; - ResultSet rs = null; - - try { - ps = conn.prepareStatement(rtp(SELECT_VOLATILE_JOBS)); - ps.setInt(1, 1); - //ps.setBoolean(1, true); - rs = ps.executeQuery(); - - ArrayList list = new ArrayList(); - while (rs.next()) { - String triggerName = rs.getString(COL_JOB_NAME); - String groupName = rs.getString(COL_JOB_GROUP); - list.add(new Key(triggerName, groupName)); - } - Object[] oArr = list.toArray(); - Key[] kArr = new Key[oArr.length]; - System.arraycopy(oArr, 0, kArr, 0, oArr.length); - return kArr; - } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - -// private static String toBooleanIntString(boolean theBoolean) { -// if (String.valueOf(theBoolean).equals("true")) { -// return "1"; -// } else { -// return "0"; -// } -// } -// - private static int toBooleanInt(boolean theBoolean) { - if (String.valueOf(theBoolean).equals("true")) { - return 1; - } else { - return 0; - } - } } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DBSemaphore.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DailyTimeIntervalTriggerPersistenceDelegate.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DriverDelegate.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DriverDelegate.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DriverDelegate.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/DriverDelegate.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; import java.io.IOException; @@ -27,14 +24,18 @@ import java.util.Set; import org.quartz.Calendar; -import org.quartz.CronTrigger; +import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobDetail; -import org.quartz.SimpleTrigger; +import org.quartz.JobKey; +import org.quartz.JobPersistenceException; import org.quartz.Trigger; +import org.quartz.TriggerKey; +import org.quartz.impl.matchers.GroupMatcher; import org.quartz.spi.ClassLoadHelper; +import org.quartz.spi.OperableTrigger; import org.quartz.utils.Key; -import org.quartz.utils.TriggerStatus; +import org.slf4j.Logger; /** *

@@ -67,6 +68,12 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + /** + * @param initString of the format: settingName=settingValue|otherSettingName=otherSettingValue|... + * @throws NoSuchDelegateException + */ + public void initialize(Logger logger, String tablePrefix, String schedName, String instanceId, ClassLoadHelper classLoadHelper, boolean useProperties, String initString) throws NoSuchDelegateException; + //--------------------------------------------------------------------------- // startup / recovery //--------------------------------------------------------------------------- @@ -86,9 +93,9 @@ * the second old state to update * @return number of rows updated */ - public int updateTriggerStatesFromOtherStates(Connection conn, - String newState, String oldState1, String oldState2) - throws SQLException; + int updateTriggerStatesFromOtherStates(Connection conn, + String newState, String oldState1, String oldState2) + throws SQLException; /** *

@@ -101,8 +108,8 @@ * @return an array of {@link * org.quartz.utils.Key} objects */ - public Key[] selectMisfiredTriggers(Connection conn, long ts) - throws SQLException; + List selectMisfiredTriggers(Connection conn, long ts) + throws SQLException; /** *

@@ -115,8 +122,37 @@ * @return an array of {@link * org.quartz.utils.Key} objects */ - public Key[] selectMisfiredTriggersInState(Connection conn, String state, - long ts) throws SQLException; + List selectMisfiredTriggersInState(Connection conn, String state, + long ts) throws SQLException; + + /** + *

+ * Get the names of all of the triggers in the given states that have + * misfired - according to the given timestamp. No more than count will + * be returned. + *

+ * + * @param conn the DB Connection + * @param count the most misfired triggers to return, negative for all + * @param resultList Output parameter. A List of + * {@link org.quartz.utils.Key} objects. Must not be null. + * + * @return Whether there are more misfired triggers left to find beyond + * the given count. + */ + boolean hasMisfiredTriggersInState(Connection conn, String state1, + long ts, int count, List resultList) throws SQLException; + + /** + *

+ * Get the number of triggers in the given state that have + * misfired - according to the given timestamp. + *

+ * + * @param conn the DB Connection + */ + int countMisfiredTriggersInState( + Connection conn, String state1, long ts) throws SQLException; /** *

@@ -129,8 +165,9 @@ * @return an array of {@link * org.quartz.utils.Key} objects */ - public Key[] selectMisfiredTriggersInGroupInState(Connection conn, - String groupName, String state, long ts) throws SQLException; + List selectMisfiredTriggersInGroupInState(Connection conn, + String groupName, String state, long ts) throws SQLException; + /** *

@@ -153,8 +190,8 @@ * the DB Connection * @return an array of {@link org.quartz.Trigger} objects */ - public Trigger[] selectTriggersForRecoveringJobs(Connection conn) - throws SQLException, IOException, ClassNotFoundException; + List selectTriggersForRecoveringJobs(Connection conn) + throws SQLException, IOException, ClassNotFoundException; /** *

@@ -165,7 +202,7 @@ * the DB Connection * @return the number of rows deleted */ - public int deleteFiredTriggers(Connection conn) throws SQLException; + int deleteFiredTriggers(Connection conn) throws SQLException; /** *

@@ -176,44 +213,9 @@ * the DB Connection * @return the number of rows deleted */ - public int deleteFiredTriggers(Connection conn, String instanceId) - throws SQLException; + int deleteFiredTriggers(Connection conn, String instanceId) + throws SQLException; - /** - *

- * Delete all volatile fired triggers. - *

- * - * @param conn - * the DB Connection - * @return the number of rows deleted - */ - public int deleteVolatileFiredTriggers(Connection conn) throws SQLException; - - /** - *

- * Get the names of all of the triggers that are volatile. - *

- * - * @param conn - * the DB Connection - * @return an array of {@link - * org.quartz.utils.Key} objects - */ - public Key[] selectVolatileTriggers(Connection conn) throws SQLException; - - /** - *

- * Get the names of all of the jobs that are volatile. - *

- * - * @param conn - * the DB Connection - * @return an array of {@link - * org.quartz.utils.Key} objects - */ - public Key[] selectVolatileJobs(Connection conn) throws SQLException; - //--------------------------------------------------------------------------- // jobs //--------------------------------------------------------------------------- @@ -231,8 +233,8 @@ * @throws IOException * if there were problems serializing the JobDataMap */ - public int insertJobDetail(Connection conn, JobDetail job) - throws IOException, SQLException; + int insertJobDetail(Connection conn, JobDetail job) + throws IOException, SQLException; /** *

@@ -247,8 +249,8 @@ * @throws IOException * if there were problems serializing the JobDataMap */ - public int updateJobDetail(Connection conn, JobDetail job) - throws IOException, SQLException; + int updateJobDetail(Connection conn, JobDetail job) + throws IOException, SQLException; /** *

@@ -257,63 +259,36 @@ * * @param conn * the DB Connection - * @param jobName - * the job name - * @param groupName - * the job group + * * @return an array of {@link * org.quartz.utils.Key} objects */ - public Key[] selectTriggerNamesForJob(Connection conn, String jobName, - String groupName) throws SQLException; + List selectTriggerKeysForJob(Connection conn, JobKey jobKey) throws SQLException; /** *

- * Delete all job listeners for the given job. - *

- * - * @param conn - * the DB Connection - * @param jobName - * the name of the job - * @param groupName - * the group containing the job - * @return the number of rows deleted - */ - public int deleteJobListeners(Connection conn, String jobName, - String groupName) throws SQLException; - - /** - *

* Delete the job detail record for the given job. *

* * @param conn * the DB Connection - * @param jobName - * the name of the job - * @param groupName - * the group containing the job + * * @return the number of rows deleted */ - public int deleteJobDetail(Connection conn, String jobName, String groupName) - throws SQLException; + int deleteJobDetail(Connection conn, JobKey jobKey) + throws SQLException; /** *

- * Check whether or not the given job is stateful. + * Check whether or not the given job disallows concurrent execution. *

* * @param conn * the DB Connection - * @param jobName - * the name of the job - * @param groupName - * the group containing the job - * @return true if the job exists and is stateful, false otherwise + * + * @return true if the job exists and disallows concurrent execution, false otherwise */ - public boolean isJobStateful(Connection conn, String jobName, - String groupName) throws SQLException; + boolean isJobNonConcurrent(Connection conn, JobKey jobKey) throws SQLException; /** *

@@ -322,14 +297,11 @@ * * @param conn * the DB Connection - * @param jobName - * the name of the job - * @param groupName - * the group containing the job + * * @return true if the job exists, false otherwise */ - public boolean jobExists(Connection conn, String jobName, String groupName) - throws SQLException; + boolean jobExists(Connection conn, JobKey jobKey) + throws SQLException; /** *

@@ -344,62 +316,27 @@ * @throws IOException * if there were problems serializing the JobDataMap */ - public int updateJobData(Connection conn, JobDetail job) - throws IOException, SQLException; + int updateJobData(Connection conn, JobDetail job) + throws IOException, SQLException; /** *

- * Associate a listener with a job. - *

- * - * @param conn - * the DB Connection - * @param job - * the job to associate with the listener - * @param listener - * the listener to insert - * @return the number of rows inserted - */ - public int insertJobListener(Connection conn, JobDetail job, String listener) - throws SQLException; - - /** - *

- * Get all of the listeners for a given job. - *

- * - * @param conn - * the DB Connection - * @param jobName - * the job name whose listeners are wanted - * @param groupName - * the group containing the job - * @return array of String listener names - */ - public String[] selectJobListeners(Connection conn, String jobName, - String groupName) throws SQLException; - - /** - *

* Select the JobDetail object for a given job name / group name. *

* * @param conn * the DB Connection - * @param jobName - * the job name whose listeners are wanted - * @param groupName - * the group containing the job + * * @return the populated JobDetail object * @throws ClassNotFoundException * if a class found during deserialization cannot be found or if * the job class could not be found * @throws IOException * if deserialization causes an error */ - public JobDetail selectJobDetail(Connection conn, String jobName, - String groupName, ClassLoadHelper loadHelper) - throws ClassNotFoundException, IOException, SQLException; + JobDetail selectJobDetail(Connection conn, JobKey jobKey, + ClassLoadHelper loadHelper) + throws ClassNotFoundException, IOException, SQLException; /** *

@@ -410,7 +347,7 @@ * the DB Connection * @return the total number of jobs stored */ - public int selectNumJobs(Connection conn) throws SQLException; + int selectNumJobs(Connection conn) throws SQLException; /** *

@@ -421,7 +358,7 @@ * the DB Connection * @return an array of String group names */ - public String[] selectJobGroups(Connection conn) throws SQLException; + List selectJobGroups(Connection conn) throws SQLException; /** *

@@ -430,12 +367,12 @@ * * @param conn * the DB Connection - * @param groupName - * the group containing the jobs + * @param matcher + * the group matcher to evaluate against the known jobs * @return an array of String job names */ - public String[] selectJobsInGroup(Connection conn, String groupName) - throws SQLException; + Set selectJobsInGroup(Connection conn, GroupMatcher matcher) + throws SQLException; //--------------------------------------------------------------------------- // triggers @@ -454,53 +391,11 @@ * the state that the trigger should be stored in * @return the number of rows inserted */ - public int insertTrigger(Connection conn, Trigger trigger, String state, - JobDetail jobDetail) throws SQLException, IOException; + int insertTrigger(Connection conn, OperableTrigger trigger, String state, + JobDetail jobDetail) throws SQLException, IOException; /** *

- * Insert the simple trigger data. - *

- * - * @param conn - * the DB Connection - * @param trigger - * the trigger to insert - * @return the number of rows inserted - */ - public int insertSimpleTrigger(Connection conn, SimpleTrigger trigger) - throws SQLException; - - /** - *

- * Insert the blob trigger data. - *

- * - * @param conn - * the DB Connection - * @param trigger - * the trigger to insert - * @return the number of rows inserted - */ - public int insertBlobTrigger(Connection conn, Trigger trigger) - throws SQLException, IOException; - - /** - *

- * Insert the cron trigger data. - *

- * - * @param conn - * the DB Connection - * @param trigger - * the trigger to insert - * @return the number of rows inserted - */ - public int insertCronTrigger(Connection conn, CronTrigger trigger) - throws SQLException; - - /** - *

* Update the base trigger data. *

* @@ -512,84 +407,35 @@ * the state that the trigger should be stored in * @return the number of rows updated */ - public int updateTrigger(Connection conn, Trigger trigger, String state, - JobDetail jobDetail) throws SQLException, IOException; + int updateTrigger(Connection conn, OperableTrigger trigger, String state, + JobDetail jobDetail) throws SQLException, IOException; /** *

- * Update the simple trigger data. + * Check whether or not a trigger exists. *

* * @param conn * the DB Connection - * @param trigger - * the trigger to insert - * @return the number of rows updated - */ - public int updateSimpleTrigger(Connection conn, SimpleTrigger trigger) - throws SQLException; - - /** - *

- * Update the cron trigger data. - *

* - * @param conn - * the DB Connection - * @param trigger - * the trigger to insert * @return the number of rows updated */ - public int updateCronTrigger(Connection conn, CronTrigger trigger) - throws SQLException; + boolean triggerExists(Connection conn, TriggerKey triggerKey) throws SQLException; /** *

- * Update the blob trigger data. - *

- * - * @param conn - * the DB Connection - * @param trigger - * the trigger to insert - * @return the number of rows updated - */ - public int updateBlobTrigger(Connection conn, Trigger trigger) - throws SQLException, IOException; - - /** - *

- * Check whether or not a trigger exists. - *

- * - * @param conn - * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger - * @return the number of rows updated - */ - public boolean triggerExists(Connection conn, String triggerName, - String groupName) throws SQLException; - - /** - *

* Update the state for a given trigger. *

* * @param conn * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger + * * @param state * the new state for the trigger * @return the number of rows updated */ - public int updateTriggerState(Connection conn, String triggerName, - String groupName, String state) throws SQLException; + int updateTriggerState(Connection conn, TriggerKey triggerKey, + String state) throws SQLException; /** *

@@ -599,20 +445,16 @@ * * @param conn * the DB connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger + * * @param newState * the new state for the trigger * @param oldState * the old state the trigger must be in * @return int the number of rows updated * @throws SQLException */ - public int updateTriggerStateFromOtherState(Connection conn, - String triggerName, String groupName, String newState, - String oldState) throws SQLException; + int updateTriggerStateFromOtherState(Connection conn, + TriggerKey triggerKey, String newState, String oldState) throws SQLException; /** *

@@ -622,10 +464,7 @@ * * @param conn * the DB connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger + * * @param newState * the new state for the trigger * @param oldState1 @@ -637,44 +476,21 @@ * @return int the number of rows updated * @throws SQLException */ - public int updateTriggerStateFromOtherStates(Connection conn, - String triggerName, String groupName, String newState, - String oldState1, String oldState2, String oldState3) - throws SQLException; + int updateTriggerStateFromOtherStates(Connection conn, + TriggerKey triggerKey, String newState, String oldState1, + String oldState2, String oldState3) + throws SQLException; /** *

- * Update the all triggers to the given new state, if they are in one of - * the given old states AND its next fire time is before the given time. - *

- * - * @param conn - * the DB connection - * @param newState - * the new state for the trigger - * @param oldState1 - * one of the old state the trigger must be in - * @param oldState2 - * one of the old state the trigger must be in - * @param time - * the time before which the trigger's next fire time must be - * @return int the number of rows updated - * @throws SQLException - */ - public int updateTriggerStateFromOtherStatesBeforeTime(Connection conn, - String newState, String oldState1, String oldState2, long time) - throws SQLException; - - /** - *

* Update all triggers in the given group to the given new state, if they * are in one of the given old states. *

* * @param conn * the DB connection - * @param groupName - * the group containing the trigger + * @param matcher + * the group matcher to evaluate against the known triggers * @param newState * the new state for the trigger * @param oldState1 @@ -686,9 +502,9 @@ * @return int the number of rows updated * @throws SQLException */ - public int updateTriggerGroupStateFromOtherStates(Connection conn, - String groupName, String newState, String oldState1, - String oldState2, String oldState3) throws SQLException; + int updateTriggerGroupStateFromOtherStates(Connection conn, + GroupMatcher matcher, String newState, String oldState1, + String oldState2, String oldState3) throws SQLException; /** *

@@ -698,18 +514,18 @@ * * @param conn * the DB connection - * @param groupName - * the group containing the triggers + * @param matcher + * the matcher to evaluate against the known triggers * @param newState * the new state for the trigger group * @param oldState * the old state the triggers must be in * @return int the number of rows updated * @throws SQLException */ - public int updateTriggerGroupStateFromOtherState(Connection conn, - String groupName, String newState, String oldState) - throws SQLException; + int updateTriggerGroupStateFromOtherState(Connection conn, + GroupMatcher matcher, String newState, String oldState) + throws SQLException; /** *

@@ -718,16 +534,13 @@ * * @param conn * the DB Connection - * @param jobName - * the name of the job - * @param groupName - * the group containing the job + * * @param state * the new state for the triggers * @return the number of rows updated */ - public int updateTriggerStatesForJob(Connection conn, String jobName, - String groupName, String state) throws SQLException; + int updateTriggerStatesForJob(Connection conn, JobKey jobKey, + String state) throws SQLException; /** *

@@ -737,147 +550,39 @@ * * @param conn * the DB Connection - * @param jobName - * the name of the job - * @param groupName - * the group containing the job + * * @param state * the new state for the triggers * @param oldState * the old state of the triggers * @return the number of rows updated */ - public int updateTriggerStatesForJobFromOtherState(Connection conn, - String jobName, String groupName, String state, String oldState) - throws SQLException; + int updateTriggerStatesForJobFromOtherState(Connection conn, + JobKey jobKey, String state, String oldState) + throws SQLException; /** *

- * Delete all of the listeners associated with a given trigger. + * Delete the base trigger data for a trigger. *

* * @param conn * the DB Connection - * @param triggerName - * the name of the trigger whose listeners will be deleted - * @param groupName - * the name of the group containing the trigger - * @return the number of rows deleted - */ - public int deleteTriggerListeners(Connection conn, String triggerName, - String groupName) throws SQLException; - - /** - *

- * Associate a listener with the given trigger. - *

* - * @param conn - * the DB Connection - * @param trigger - * the trigger - * @param listener - * the name of the listener to associate with the trigger - * @return the number of rows inserted - */ - public int insertTriggerListener(Connection conn, Trigger trigger, - String listener) throws SQLException; - - /** - *

- * Select the listeners associated with a given trigger. - *

- * - * @param conn - * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger - * @return array of String trigger listener names - */ - public String[] selectTriggerListeners(Connection conn, String triggerName, - String groupName) throws SQLException; - - /** - *

- * Delete the simple trigger data for a trigger. - *

- * - * @param conn - * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger * @return the number of rows deleted */ - public int deleteSimpleTrigger(Connection conn, String triggerName, - String groupName) throws SQLException; + int deleteTrigger(Connection conn, TriggerKey triggerKey) throws SQLException; /** *

- * Delete the BLOB trigger data for a trigger. - *

- * - * @param conn - * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger - * @return the number of rows deleted - */ - public int deleteBlobTrigger(Connection conn, String triggerName, - String groupName) throws SQLException; - - /** - *

- * Delete the cron trigger data for a trigger. - *

- * - * @param conn - * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger - * @return the number of rows deleted - */ - public int deleteCronTrigger(Connection conn, String triggerName, - String groupName) throws SQLException; - - /** - *

- * Delete the base trigger data for a trigger. - *

- * - * @param conn - * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger - * @return the number of rows deleted - */ - public int deleteTrigger(Connection conn, String triggerName, - String groupName) throws SQLException; - - /** - *

* Select the number of triggers associated with a given job. *

* * @param conn * the DB Connection - * @param jobName - * the name of the job - * @param groupName - * the group containing the job * @return the number of triggers for the given job */ - public int selectNumTriggersForJob(Connection conn, String jobName, - String groupName) throws SQLException; + int selectNumTriggersForJob(Connection conn, JobKey jobKey) throws SQLException; /** *

@@ -886,31 +591,22 @@ * * @param conn * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger + * * @return the {@link org.quartz.JobDetail} object * associated with the given trigger */ - public JobDetail selectJobForTrigger(Connection conn, String triggerName, - String groupName, ClassLoadHelper loadHelper) + JobDetail selectJobForTrigger(Connection conn, ClassLoadHelper loadHelper, + TriggerKey triggerKey) throws ClassNotFoundException, SQLException; /** *

- * Select the stateful jobs which are referenced by triggers in the given - * trigger group. + * Select the job to which the trigger is associated. Allow option to load actual job class or not. When case of + * remove, we do not need to load the class, which in many cases, it's no longer exists. *

- * - * @param conn - * the DB Connection - * @param groupName - * the trigger group - * @return a List of Keys to jobs. */ - public List selectStatefulJobsOfTriggerGroup(Connection conn, - String groupName) throws SQLException; + public JobDetail selectJobForTrigger(Connection conn, ClassLoadHelper loadHelper, + TriggerKey triggerKey, boolean loadJobClass) throws ClassNotFoundException, SQLException; /** *

@@ -919,17 +615,14 @@ * * @param conn * the DB Connection - * @param jobName - * the name of the trigger - * @param groupName - * the group containing the trigger + * * @return an array of (@link org.quartz.Trigger) objects * associated with a given job. * @throws SQLException + * @throws JobPersistenceException */ - public Trigger[] selectTriggersForJob(Connection conn, String jobName, - String groupName) throws SQLException, ClassNotFoundException, - IOException; + List selectTriggersForJob(Connection conn, JobKey jobKey) throws SQLException, ClassNotFoundException, + IOException, JobPersistenceException; /** *

@@ -938,32 +631,28 @@ * * @param conn * the DB Connection - * @param jobName - * the name of the trigger - * @param groupName - * the group containing the trigger + * @param calName + * the name of the calendar * @return an array of (@link org.quartz.Trigger) objects - * associated with a given job. + * associated with the given calendar. * @throws SQLException + * @throws JobPersistenceException */ - public Trigger[] selectTriggersForCalendar(Connection conn, String calName) - throws SQLException, ClassNotFoundException, IOException; + List selectTriggersForCalendar(Connection conn, String calName) + throws SQLException, ClassNotFoundException, IOException, JobPersistenceException; /** *

* Select a trigger. *

* * @param conn * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger + * * @return the {@link org.quartz.Trigger} object + * @throws JobPersistenceException */ - public Trigger selectTrigger(Connection conn, String triggerName, - String groupName) throws SQLException, ClassNotFoundException, - IOException; + OperableTrigger selectTrigger(Connection conn, TriggerKey triggerKey) throws SQLException, ClassNotFoundException, + IOException, JobPersistenceException; /** *

@@ -979,9 +668,9 @@ * @return the {@link org.quartz.JobDataMap} of the Trigger, * never null, but possibly empty. */ - public JobDataMap selectTriggerJobDataMap(Connection conn, String triggerName, - String groupName) throws SQLException, ClassNotFoundException, - IOException; + JobDataMap selectTriggerJobDataMap(Connection conn, String triggerName, + String groupName) throws SQLException, ClassNotFoundException, + IOException; /** *

@@ -990,14 +679,10 @@ * * @param conn * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger + * * @return the {@link org.quartz.Trigger} object */ - public String selectTriggerState(Connection conn, String triggerName, - String groupName) throws SQLException; + String selectTriggerState(Connection conn, TriggerKey triggerKey) throws SQLException; /** *

@@ -1006,14 +691,11 @@ * * @param conn * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger + * * @return a TriggerStatus object, or null */ - public TriggerStatus selectTriggerStatus(Connection conn, - String triggerName, String groupName) throws SQLException; + TriggerStatus selectTriggerStatus(Connection conn, + TriggerKey triggerKey) throws SQLException; /** *

@@ -1024,7 +706,7 @@ * the DB Connection * @return the total number of triggers stored */ - public int selectNumTriggers(Connection conn) throws SQLException; + int selectNumTriggers(Connection conn) throws SQLException; /** *

@@ -1035,21 +717,23 @@ * the DB Connection * @return an array of String group names */ - public String[] selectTriggerGroups(Connection conn) throws SQLException; + List selectTriggerGroups(Connection conn) throws SQLException; + List selectTriggerGroups(Connection conn, GroupMatcher matcher) throws SQLException; + /** *

* Select all of the triggers contained in a given group. *

* * @param conn * the DB Connection - * @param groupName - * the group containing the triggers - * @return an array of String trigger names + * @param matcher + * to evaluate against known triggers + * @return a Set of TriggerKeys */ - public String[] selectTriggersInGroup(Connection conn, String groupName) - throws SQLException; + Set selectTriggersInGroup(Connection conn, GroupMatcher matcher) + throws SQLException; /** *

@@ -1062,26 +746,29 @@ * the state the triggers must be in * @return an array of trigger Key s */ - public Key[] selectTriggersInState(Connection conn, String state) - throws SQLException; + List selectTriggersInState(Connection conn, String state) + throws SQLException; - public int insertPausedTriggerGroup(Connection conn, String groupName) - throws SQLException; + int insertPausedTriggerGroup(Connection conn, String groupName) + throws SQLException; - public int deletePausedTriggerGroup(Connection conn, String groupName) - throws SQLException; + int deletePausedTriggerGroup(Connection conn, String groupName) + throws SQLException; - public int deleteAllPausedTriggerGroups(Connection conn) - throws SQLException; + int deletePausedTriggerGroup(Connection conn, GroupMatcher matcher) + throws SQLException; - public boolean isTriggerGroupPaused(Connection conn, String groupName) - throws SQLException; + int deleteAllPausedTriggerGroups(Connection conn) + throws SQLException; - public Set selectPausedTriggerGroups(Connection conn) + boolean isTriggerGroupPaused(Connection conn, String groupName) throws SQLException; + + Set selectPausedTriggerGroups(Connection conn) + throws SQLException; - public boolean isExistingTriggerGroup(Connection conn, String groupName) - throws SQLException; + boolean isExistingTriggerGroup(Connection conn, String groupName) + throws SQLException; //--------------------------------------------------------------------------- // calendars @@ -1102,8 +789,8 @@ * @throws IOException * if there were problems serializing the calendar */ - public int insertCalendar(Connection conn, String calendarName, - Calendar calendar) throws IOException, SQLException; + int insertCalendar(Connection conn, String calendarName, + Calendar calendar) throws IOException, SQLException; /** *

@@ -1120,8 +807,8 @@ * @throws IOException * if there were problems serializing the calendar */ - public int updateCalendar(Connection conn, String calendarName, - Calendar calendar) throws IOException, SQLException; + int updateCalendar(Connection conn, String calendarName, + Calendar calendar) throws IOException, SQLException; /** *

@@ -1134,8 +821,8 @@ * the name of the calendar * @return true if the trigger exists, false otherwise */ - public boolean calendarExists(Connection conn, String calendarName) - throws SQLException; + boolean calendarExists(Connection conn, String calendarName) + throws SQLException; /** *

@@ -1153,8 +840,8 @@ * @throws IOException * if there were problems deserializing the calendar */ - public Calendar selectCalendar(Connection conn, String calendarName) - throws ClassNotFoundException, IOException, SQLException; + Calendar selectCalendar(Connection conn, String calendarName) + throws ClassNotFoundException, IOException, SQLException; /** *

@@ -1167,8 +854,8 @@ * the name of the calendar * @return true if any triggers reference the calendar, false otherwise */ - public boolean calendarIsReferenced(Connection conn, String calendarName) - throws SQLException; + boolean calendarIsReferenced(Connection conn, String calendarName) + throws SQLException; /** *

@@ -1181,8 +868,8 @@ * the name of the trigger * @return the number of rows deleted */ - public int deleteCalendar(Connection conn, String calendarName) - throws SQLException; + int deleteCalendar(Connection conn, String calendarName) + throws SQLException; /** *

@@ -1193,7 +880,7 @@ * the DB Connection * @return the total number of calendars stored */ - public int selectNumCalendars(Connection conn) throws SQLException; + int selectNumCalendars(Connection conn) throws SQLException; /** *

@@ -1204,7 +891,7 @@ * the DB Connection * @return an array of String calendar names */ - public String[] selectCalendars(Connection conn) throws SQLException; + List selectCalendars(Connection conn) throws SQLException; //--------------------------------------------------------------------------- // trigger firing @@ -1218,8 +905,10 @@ * @param conn * the DB Connection * @return the next fire time, or 0 if no trigger will be fired + * + * @deprecated Does not account for misfires. */ - public long selectNextFireTime(Connection conn) throws SQLException; + long selectNextFireTime(Connection conn) throws SQLException; /** *

@@ -1234,11 +923,51 @@ * trigger that will be fired at the given fire time, or null if no * trigger will be fired at that time */ - public Key selectTriggerForFireTime(Connection conn, long fireTime) - throws SQLException; + Key selectTriggerForFireTime(Connection conn, long fireTime) + throws SQLException; /** *

+ * Select the next trigger which will fire to fire between the two given timestamps + * in ascending order of fire time, and then descending by priority. + *

+ * + * @param conn + * the DB Connection + * @param noLaterThan + * highest value of getNextFireTime() of the triggers (exclusive) + * @param noEarlierThan + * highest value of getNextFireTime() of the triggers (inclusive) + * + * @return A (never null, possibly empty) list of the identifiers (Key objects) of the next triggers to be fired. + * + * @deprecated - This remained for compatibility reason. Use {@link #selectTriggerToAcquire(Connection, long, long, int)} instead. + */ + public List selectTriggerToAcquire(Connection conn, long noLaterThan, long noEarlierThan) + throws SQLException; + + /** + *

+ * Select the next trigger which will fire to fire between the two given timestamps + * in ascending order of fire time, and then descending by priority. + *

+ * + * @param conn + * the DB Connection + * @param noLaterThan + * highest value of getNextFireTime() of the triggers (exclusive) + * @param noEarlierThan + * highest value of getNextFireTime() of the triggers (inclusive) + * @param maxCount + * maximum number of trigger keys allow to acquired in the returning list. + * + * @return A (never null, possibly empty) list of the identifiers (Key objects) of the next triggers to be fired. + */ + public List selectTriggerToAcquire(Connection conn, long noLaterThan, long noEarlierThan, int maxCount) + throws SQLException; + + /** + *

* Insert a fired trigger. *

* @@ -1250,19 +979,35 @@ * the state that the trigger should be stored in * @return the number of rows inserted */ - public int insertFiredTrigger(Connection conn, Trigger trigger, - String state, JobDetail jobDetail) throws SQLException; + int insertFiredTrigger(Connection conn, OperableTrigger trigger, + String state, JobDetail jobDetail) throws SQLException; /** *

+ * Update a fired trigger record. Will update the fields + * "firing instance", "fire time", and "state". + *

+ * + * @param conn + * the DB Connection + * @param trigger + * the trigger + * @param state + * the state that the trigger should be stored in + * @return the number of rows inserted + */ + int updateFiredTrigger(Connection conn, OperableTrigger trigger, + String state, JobDetail jobDetail) throws SQLException; + + /** + *

* Select the states of all fired-trigger records for a given trigger, or * trigger group if trigger name is null. *

* * @return a List of FiredTriggerRecord objects. */ - public List selectFiredTriggerRecords(Connection conn, String triggerName, - String groupName) throws SQLException; + List selectFiredTriggerRecords(Connection conn, String triggerName, String groupName) throws SQLException; /** *

@@ -1272,8 +1017,7 @@ * * @return a List of FiredTriggerRecord objects. */ - public List selectFiredTriggerRecordsByJob(Connection conn, String jobName, - String groupName) throws SQLException; + List selectFiredTriggerRecordsByJob(Connection conn, String jobName, String groupName) throws SQLException; /** *

@@ -1283,11 +1027,27 @@ * * @return a List of FiredTriggerRecord objects. */ - public List selectInstancesFiredTriggerRecords(Connection conn, - String instanceName) throws SQLException; + List selectInstancesFiredTriggerRecords(Connection conn, + String instanceName) throws SQLException; + /** *

+ * Select the distinct instance names of all fired-trigger records. + *

+ * + *

+ * This is useful when trying to identify orphaned fired triggers (a + * fired trigger without a scheduler state record.) + *

+ * + * @return a Set of String objects. + */ + Set selectFiredTriggerInstanceNames(Connection conn) + throws SQLException; + + /** + *

* Delete a fired trigger. *

* @@ -1297,8 +1057,8 @@ * the fired trigger entry to delete * @return the number of rows deleted */ - public int deleteFiredTrigger(Connection conn, String entryId) - throws SQLException; + int deleteFiredTrigger(Connection conn, String entryId) + throws SQLException; /** *

@@ -1307,10 +1067,10 @@ * * @param conn * the DB Connection + * * @return the number instances of the identified job currently executing. */ - public int selectJobExecutionCount(Connection conn, String jobName, - String jobGroup) throws SQLException; + int selectJobExecutionCount(Connection conn, JobKey jobKey) throws SQLException; /** *

@@ -1321,9 +1081,9 @@ * the DB Connection * @return the number of inserted rows. */ - public int insertSchedulerState(Connection conn, String instanceId, - long checkInTime, long interval, String recoverer) - throws SQLException; + int insertSchedulerState(Connection conn, String instanceId, + long checkInTime, long interval) + throws SQLException; /** *

@@ -1334,8 +1094,8 @@ * the DB Connection * @return the number of deleted rows. */ - public int deleteSchedulerState(Connection conn, String instanceId) - throws SQLException; + int deleteSchedulerState(Connection conn, String instanceId) + throws SQLException; /** @@ -1347,8 +1107,8 @@ * the DB Connection * @return the number of updated rows. */ - public int updateSchedulerState(Connection conn, String instanceId, long checkInTime, String recoverer) - throws SQLException; + int updateSchedulerState(Connection conn, String instanceId, long checkInTime) + throws SQLException; /** *

@@ -1363,9 +1123,18 @@ * @param conn * the DB Connection */ - public List selectSchedulerStateRecords(Connection conn, String instanceId) // TODO: this method would be more handy if it returned a map. - throws SQLException; + List selectSchedulerStateRecords(Connection conn, String instanceId) + throws SQLException; + /** + * Clear (delete!) all scheduling data - all {@link Job}s, {@link Trigger}s + * {@link Calendar}s. + * + * @throws JobPersistenceException + */ + void clearData(Connection conn) + throws SQLException; + } // EOF Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/FiredTriggerRecord.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/FiredTriggerRecord.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/FiredTriggerRecord.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/FiredTriggerRecord.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,12 +15,10 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; -import org.quartz.utils.Key; +import org.quartz.JobKey; +import org.quartz.TriggerKey; /** *

@@ -31,6 +29,8 @@ */ public class FiredTriggerRecord implements java.io.Serializable { + private static final long serialVersionUID = -7183096398865657533L; + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -43,20 +43,22 @@ private long fireTimestamp; + private long scheduleTimestamp; + private String schedulerInstanceId; - private Key triggerKey; + private TriggerKey triggerKey; private String fireInstanceState; - private boolean triggerIsVolatile; + private JobKey jobKey; - private Key jobKey; + private boolean jobDisallowsConcurrentExecution; - private boolean jobIsStateful; - private boolean jobRequestsRecovery; + private int priority; + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -73,19 +75,23 @@ return fireTimestamp; } - public boolean isJobIsStateful() { - return jobIsStateful; + public long getScheduleTimestamp() { + return scheduleTimestamp; } - public Key getJobKey() { + public boolean isJobDisallowsConcurrentExecution() { + return jobDisallowsConcurrentExecution; + } + + public JobKey getJobKey() { return jobKey; } public String getSchedulerInstanceId() { return schedulerInstanceId; } - public Key getTriggerKey() { + public TriggerKey getTriggerKey() { return triggerKey; } @@ -101,19 +107,23 @@ fireTimestamp = l; } - public void setJobIsStateful(boolean b) { - jobIsStateful = b; + public void setScheduleTimestamp(long l) { + scheduleTimestamp = l; } - public void setJobKey(Key key) { + public void setJobDisallowsConcurrentExecution(boolean b) { + jobDisallowsConcurrentExecution = b; + } + + public void setJobKey(JobKey key) { jobKey = key; } public void setSchedulerInstanceId(String string) { schedulerInstanceId = string; } - public void setTriggerKey(Key key) { + public void setTriggerKey(TriggerKey key) { triggerKey = key; } @@ -125,18 +135,20 @@ return jobRequestsRecovery; } - public boolean isTriggerIsVolatile() { - return triggerIsVolatile; - } - public void setJobRequestsRecovery(boolean b) { jobRequestsRecovery = b; } - public void setTriggerIsVolatile(boolean b) { - triggerIsVolatile = b; + public int getPriority() { + return priority; } + + public void setPriority(int priority) { + this.priority = priority; + } + + } // EOF Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/HSQLDBDelegate.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/HSQLDBDelegate.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/HSQLDBDelegate.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/HSQLDBDelegate.java 15 Dec 2014 10:09:49 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,7 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ + package org.quartz.impl.jdbcjobstore; import java.io.IOException; @@ -26,7 +24,8 @@ import java.sql.ResultSet; import java.sql.SQLException; -import org.apache.commons.logging.Log; +import org.quartz.spi.ClassLoadHelper; +import org.slf4j.Logger; /** *

@@ -37,37 +36,7 @@ * @author Jeffrey Wescott */ public class HSQLDBDelegate extends StdJDBCDelegate { - /** - *

- * Create new HSQLDBDelegate instance. - *

- * - * @param logger - * the logger to use during execution - * @param tablePrefix - * the prefix of all table names - */ - public HSQLDBDelegate(Log log, String tablePrefix, String instanceId) { - super(log, tablePrefix, instanceId); - } - /** - *

- * Create new MSSQLDelegate instance. - *

- * - * @param logger - * the logger to use during execution - * @param tablePrefix - * the prefix of all table names - * @param useProperties - * use java.util.Properties for storage - */ - public HSQLDBDelegate(Log log, String tablePrefix, String instanceId, - Boolean useProperties) { - super(log, tablePrefix, instanceId, useProperties); - } - //--------------------------------------------------------------------------- // protected methods that can be overridden by subclasses //--------------------------------------------------------------------------- @@ -89,22 +58,30 @@ * @throws IOException * if deserialization causes an error */ + @Override protected Object getObjectFromBlob(ResultSet rs, String colName) - throws ClassNotFoundException, IOException, SQLException { + throws ClassNotFoundException, IOException, SQLException { InputStream binaryInput = rs.getBinaryStream(colName); - if(binaryInput == null) + if(binaryInput == null || binaryInput.available() == 0) { return null; + } + Object obj = null; + ObjectInputStream in = new ObjectInputStream(binaryInput); - Object obj = in.readObject(); - in.close(); + try { + obj = in.readObject(); + } finally { + in.close(); + } return obj; } - protected Object getJobDetailFromBlob(ResultSet rs, String colName) - throws ClassNotFoundException, IOException, SQLException { + @Override + protected Object getJobDataFromBlob(ResultSet rs, String colName) + throws ClassNotFoundException, IOException, SQLException { if (canUseProperties()) { InputStream binaryInput = rs.getBinaryStream(colName); return binaryInput; Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/InvalidConfigurationException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/InvalidConfigurationException.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/InvalidConfigurationException.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/InvalidConfigurationException.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; /** @@ -30,6 +27,8 @@ */ public class InvalidConfigurationException extends Exception { + private static final long serialVersionUID = 1836325935209404611L; + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/JTANonClusteredSemaphore.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/JobStoreCMT.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/JobStoreCMT.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/JobStoreCMT.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/JobStoreCMT.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,27 +15,16 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ + package org.quartz.impl.jdbcjobstore; import java.sql.Connection; import java.sql.SQLException; -import java.util.List; -import java.util.Set; -import org.quartz.Calendar; -import org.quartz.JobDetail; import org.quartz.JobPersistenceException; -import org.quartz.ObjectAlreadyExistsException; import org.quartz.SchedulerConfigException; -import org.quartz.SchedulerException; -import org.quartz.Trigger; -import org.quartz.core.SchedulingContext; import org.quartz.spi.ClassLoadHelper; import org.quartz.spi.SchedulerSignaler; -import org.quartz.spi.TriggerFiredBundle; import org.quartz.utils.DBConnectionManager; /** @@ -132,20 +121,31 @@ } + @Override public void initialize(ClassLoadHelper loadHelper, SchedulerSignaler signaler) throws SchedulerConfigException { - if (nonManagedTxDsName == null) - throw new SchedulerConfigException( - "Non-ManagedTX DataSource name not set!"); + if (nonManagedTxDsName == null) { + throw new SchedulerConfigException( + "Non-ManagedTX DataSource name not set! " + + "If your 'org.quartz.jobStore.dataSource' is XA, then set " + + "'org.quartz.jobStore.nonManagedTXDataSource' to a non-XA "+ + "datasource (for the same DB). " + + "Otherwise, you can set them to be the same."); + } - setUseDBLocks(true); // *must* use DB locks with CMT... + if (getLockHandler() == null) { + // If the user hasn't specified an explicit lock handler, + // then we *must* use DB locks with CMT... + setUseDBLocks(true); + } super.initialize(loadHelper, signaler); getLog().info("JobStoreCMT initialized."); } + @Override public void shutdown() { super.shutdown(); @@ -156,1314 +156,101 @@ getLog().warn("Database connection shutdown unsuccessful.", sqle); } } - - //--------------------------------------------------------------------------- - // JobStoreSupport methods - //--------------------------------------------------------------------------- - - /** - *

- * Recover any failed or misfired jobs and clean up the data store as - * appropriate. - *

- * - * @throws JobPersistenceException - * if jobs could not be recovered - */ - protected void recoverJobs() throws JobPersistenceException { + @Override + protected Connection getNonManagedTXConnection() + throws JobPersistenceException { Connection conn = null; - - boolean transOwner = false; - try { - conn = getNonManagedTXConnection(); - - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - recoverJobs(conn); - - conn.commit(); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } catch (Exception e) { - rollbackConnection(conn); - throw new JobPersistenceException("Error recovering jobs: " - + e.getMessage(), e); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } + conn = DBConnectionManager.getInstance().getConnection( + getNonManagedTXDataSource()); + } catch (SQLException sqle) { + throw new JobPersistenceException( + "Failed to obtain DB connection from data source '" + + getNonManagedTXDataSource() + "': " + + sqle.toString(), sqle); + } catch (Throwable e) { + throw new JobPersistenceException( + "Failed to obtain DB connection from data source '" + + getNonManagedTXDataSource() + "': " + + e.toString(), e); } - } - protected void cleanVolatileTriggerAndJobs() throws JobPersistenceException { - Connection conn = null; - - boolean transOwner = false; - - try { - conn = getNonManagedTXConnection(); - - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - cleanVolatileTriggerAndJobs(conn); - - conn.commit(); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } catch (Exception e) { - rollbackConnection(conn); - throw new JobPersistenceException("Error cleaning volatile data: " - + e.getMessage(), e); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } + if (conn == null) { + throw new JobPersistenceException( + "Could not get connection from DataSource '" + + getNonManagedTXDataSource() + "'"); } - } - //--------------------------------------------------------------------------- - // job / trigger storage methods - //--------------------------------------------------------------------------- - - /** - *

- * Store the given {@link org.quartz.JobDetail} and {@link org.quartz.Trigger}. - *

- * - * @param newJob - * The JobDetail to be stored. - * @param newTrigger - * The Trigger to be stored. - * @throws ObjectAlreadyExistsException - * if a Job with the same name/group already - * exists. - */ - public void storeJobAndTrigger(SchedulingContext ctxt, JobDetail newJob, - Trigger newTrigger) throws ObjectAlreadyExistsException, - JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; + // Protect connection attributes we might change. + conn = getAttributeRestoringConnection(conn); + + // Set any connection connection attributes we are to override. try { - if(isLockOnInsert()) { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); + if (!isDontSetNonManagedTXConnectionAutoCommitFalse()) { + conn.setAutoCommit(false); } - - if (newJob.isVolatile() && !newTrigger.isVolatile()) { - JobPersistenceException jpe = new JobPersistenceException( - "Cannot associate non-volatile " - + "trigger with a volatile job!"); - jpe.setErrorCode(SchedulerException.ERR_CLIENT_ERROR); - throw jpe; - } - - storeJob(conn, ctxt, newJob, false); - storeTrigger(conn, ctxt, newTrigger, newJob, false, - Constants.STATE_WAITING, false, false); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Store the given {@link org.quartz.JobDetail}. - *

- * - * @param newJob - * The JobDetail to be stored. - * @param replaceExisting - * If true, any Job existing in the - * JobStore with the same name & group should be - * over-written. - * @throws ObjectAlreadyExistsException - * if a Job with the same name/group already - * exists, and replaceExisting is set to false. - */ - public void storeJob(SchedulingContext ctxt, JobDetail newJob, - boolean replaceExisting) throws ObjectAlreadyExistsException, - JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - if(isLockOnInsert() || replaceExisting) { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - } - storeJob(conn, ctxt, newJob, replaceExisting); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Remove (delete) the {@link org.quartz.Job} with the given - * name, and any {@link org.quartz.Trigger} s that reference - * it. - *

- * - *

- * If removal of the Job results in an empty group, the - * group should be removed from the JobStore's list of - * known group names. - *

- * - * @param jobName - * The name of the Job to be removed. - * @param groupName - * The group name of the Job to be removed. - * @return true if a Job with the given name & - * group was found and removed from the store. - */ - public boolean removeJob(SchedulingContext ctxt, String jobName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - return removeJob(conn, ctxt, jobName, groupName, true); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Retrieve the {@link org.quartz.JobDetail} for the given - * {@link org.quartz.Job}. - *

- * - * @param jobName - * The name of the Job to be retrieved. - * @param groupName - * The group name of the Job to be retrieved. - * @return The desired Job, or null if there is no match. - */ - public JobDetail retrieveJob(SchedulingContext ctxt, String jobName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - return retrieveJob(conn, ctxt, jobName, groupName); - } finally { - closeConnection(conn); - } - } - - /** - *

- * Store the given {@link org.quartz.Trigger}. - *

- * - * @param newTrigger - * The Trigger to be stored. - * @param replaceExisting - * If true, any Trigger existing in - * the JobStore with the same name & group should - * be over-written. - * @throws ObjectAlreadyExistsException - * if a Trigger with the same name/group already - * exists, and replaceExisting is set to false. - */ - public void storeTrigger(SchedulingContext ctxt, Trigger newTrigger, - boolean replaceExisting) throws ObjectAlreadyExistsException, - JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - if(isLockOnInsert() || replaceExisting) { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; + if (isTxIsolationLevelReadCommitted()) { + conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); } - - storeTrigger(conn, ctxt, newTrigger, null, replaceExisting, - STATE_WAITING, false, false); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Remove (delete) the {@link org.quartz.Trigger} with the - * given name. - *

- * - *

- * If removal of the Trigger results in an empty group, the - * group should be removed from the JobStore's list of - * known group names. - *

- * - *

- * If removal of the Trigger results in an 'orphaned' Job - * that is not 'durable', then the Job should be deleted - * also. - *

- * - * @param triggerName - * The name of the Trigger to be removed. - * @param groupName - * The group name of the Trigger to be removed. - * @return true if a Trigger with the given - * name & group was found and removed from the store. - */ - public boolean removeTrigger(SchedulingContext ctxt, String triggerName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - - return removeTrigger(conn, ctxt, triggerName, groupName); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - - /** - * @see org.quartz.spi.JobStore#replaceTrigger(org.quartz.core.SchedulingContext, java.lang.String, java.lang.String, org.quartz.Trigger) - */ - public boolean replaceTrigger(SchedulingContext ctxt, String triggerName, String groupName, Trigger newTrigger) throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - - return replaceTrigger(conn, ctxt, triggerName, groupName, newTrigger); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Retrieve the given {@link org.quartz.Trigger}. - *

- * - * @param triggerName - * The name of the Trigger to be retrieved. - * @param groupName - * The group name of the Trigger to be retrieved. - * @return The desired Trigger, or null if there is no - * match. - */ - public Trigger retrieveTrigger(SchedulingContext ctxt, String triggerName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - return retrieveTrigger(conn, ctxt, triggerName, groupName); - } finally { - closeConnection(conn); - } - } - - /** - *

- * Store the given {@link org.quartz.Calendar}. - *

- * - * @param calName - * The name of the calendar. - * @param calendar - * The Calendar to be stored. - * @param replaceExisting - * If true, any Calendar existing - * in the JobStore with the same name & group - * should be over-written. - * @throws ObjectAlreadyExistsException - * if a Calendar with the same name already - * exists, and replaceExisting is set to false. - */ - public void storeCalendar(SchedulingContext ctxt, String calName, - Calendar calendar, boolean replaceExisting, boolean updateTriggers) - throws ObjectAlreadyExistsException, JobPersistenceException { - Connection conn = getConnection(); - boolean lockOwner = false; - try { - if(isLockOnInsert() || updateTriggers) { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - lockOwner = true; - } + } catch (SQLException sqle) { + getLog().warn("Failed to override connection auto commit/transaction isolation.", sqle); + } catch (Throwable e) { + try { conn.close(); } catch(Throwable tt) {} - storeCalendar(conn, ctxt, calName, calendar, replaceExisting, updateTriggers); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, lockOwner); - } finally { - closeConnection(conn); - } + throw new JobPersistenceException( + "Failure setting up connection.", e); } + + return conn; } - - /** - *

- * Remove (delete) the {@link org.quartz.Calendar} with the - * given name. - *

- * - *

- * If removal of the Calendar would result in - * s pointing to non-existent calendars, then a - * JobPersistenceException will be thrown.

- * * - * @param calName The name of the Calendar to be removed. - * @return true if a Calendar with the given name - * was found and removed from the store. - */ - public boolean removeCalendar(SchedulingContext ctxt, String calName) - throws JobPersistenceException { - Connection conn = getConnection(); - boolean lockOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_CALENDAR_ACCESS); - lockOwner = true; - - return removeCalendar(conn, ctxt, calName); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, lockOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Retrieve the given {@link org.quartz.Trigger}. - *

- * - * @param calName - * The name of the Calendar to be retrieved. - * @return The desired Calendar, or null if there is no - * match. - */ - public Calendar retrieveCalendar(SchedulingContext ctxt, String calName) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - return retrieveCalendar(conn, ctxt, calName); - } finally { - closeConnection(conn); - } - } - - //--------------------------------------------------------------------------- - // informational methods - //--------------------------------------------------------------------------- - - /** - *

- * Get the number of {@link org.quartz.Job} s that are - * stored in the JobStore. - *

- */ - public int getNumberOfJobs(SchedulingContext ctxt) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - return getNumberOfJobs(conn, ctxt); - } finally { - closeConnection(conn); - } - } - - /** - *

- * Get the number of {@link org.quartz.Trigger} s that are - * stored in the JobsStore. - *

- */ - public int getNumberOfTriggers(SchedulingContext ctxt) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - return getNumberOfTriggers(conn, ctxt); - } finally { - closeConnection(conn); - } - } - - /** - *

- * Get the number of {@link org.quartz.Calendar} s that are - * stored in the JobsStore. - *

- */ - public int getNumberOfCalendars(SchedulingContext ctxt) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - return getNumberOfCalendars(conn, ctxt); - } finally { - closeConnection(conn); - } - } - - public Set getPausedTriggerGroups(SchedulingContext ctxt) - throws JobPersistenceException { - - Connection conn = getConnection(); - try { - // no locks necessary for read... - Set groups = getPausedTriggerGroups(conn, ctxt); - return groups; - } finally { - closeConnection(conn); - } - } /** - *

- * Get the names of all of the {@link org.quartz.Job} s that - * have the given group name. - *

+ * Execute the given callback having optionally acquired the given lock. + * Because CMT assumes that the connection is already part of a managed + * transaction, it does not attempt to commit or rollback the + * enclosing transaction. * - *

- * If there are no jobs in the given group name, the result should be a - * zero-length array (not null). - *

- */ - public String[] getJobNames(SchedulingContext ctxt, String groupName) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - return getJobNames(conn, ctxt, groupName); - } finally { - closeConnection(conn); - } - } - - /** - *

- * Get the names of all of the {@link org.quartz.Trigger} s - * that have the given group name. - *

+ * @param lockName The name of the lock to acquire, for example + * "TRIGGER_ACCESS". If null, then no lock is acquired, but the + * txCallback is still executed in a transaction. * - *

- * If there are no triggers in the given group name, the result should be a - * zero-length array (not null). - *

+ * @see JobStoreSupport#executeInNonManagedTXLock(String, TransactionCallback) + * @see JobStoreTX#executeInLock(String, TransactionCallback) + * @see JobStoreSupport#getNonManagedTXConnection() + * @see JobStoreSupport#getConnection() */ - public String[] getTriggerNames(SchedulingContext ctxt, String groupName) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - return getTriggerNames(conn, ctxt, groupName); - } finally { - closeConnection(conn); - } - } - - /** - *

- * Get the names of all of the {@link org.quartz.Job} - * groups. - *

- * - *

- * If there are no known group names, the result should be a zero-length - * array (not null). - *

- */ - public String[] getJobGroupNames(SchedulingContext ctxt) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - return getJobGroupNames(conn, ctxt); - } finally { - closeConnection(conn); - } - } - - /** - *

- * Get the names of all of the {@link org.quartz.Trigger} - * groups. - *

- * - *

- * If there are no known group names, the result should be a zero-length - * array (not null). - *

- */ - public String[] getTriggerGroupNames(SchedulingContext ctxt) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - return getTriggerGroupNames(conn, ctxt); - } finally { - closeConnection(conn); - } - } - - /** - *

- * Get the names of all of the {@link org.quartz.Calendar} s - * in the JobStore. - *

- * - *

- * If there are no Calendars in the given group name, the result should be - * a zero-length array (not null). - *

- */ - public String[] getCalendarNames(SchedulingContext ctxt) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - return getCalendarNames(conn, ctxt); - } finally { - closeConnection(conn); - } - } - - /** - *

- * Get all of the Triggers that are associated to the given Job. - *

- * - *

- * If there are no matches, a zero-length array should be returned. - *

- */ - public Trigger[] getTriggersForJob(SchedulingContext ctxt, String jobName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - return getTriggersForJob(conn, ctxt, jobName, groupName); - } finally { - closeConnection(conn); - } - } - - /** - *

- * Get the current state of the identified {@link Trigger}. - *

- * - * @see Trigger#STATE_NORMAL - * @see Trigger#STATE_PAUSED - * @see Trigger#STATE_COMPLETE - * @see Trigger#STATE_ERROR - * @see Trigger#STATE_NONE - */ - public int getTriggerState(SchedulingContext ctxt, String triggerName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - return getTriggerState(conn, ctxt, triggerName, groupName); - } finally { - closeConnection(conn); - } - } - - //--------------------------------------------------------------------------- - // trigger state manipulation methods - //--------------------------------------------------------------------------- - - /** - *

- * Pause the {@link org.quartz.Trigger} with the given name. - *

- * - * @see #resumeTrigger(SchedulingContext, String, String) - */ - public void pauseTrigger(SchedulingContext ctxt, String triggerName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); + @Override + protected Object executeInLock( + String lockName, + TransactionCallback txCallback) throws JobPersistenceException { boolean transOwner = false; + Connection conn = null; try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - pauseTrigger(conn, ctxt, triggerName, groupName); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Pause all of the {@link org.quartz.Trigger}s in the - * given group. - *

- * - * @see #resumeTriggerGroup(SchedulingContext, String) - */ - public void pauseTriggerGroup(SchedulingContext ctxt, String groupName) - throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - pauseTriggerGroup(conn, ctxt, groupName); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Pause the {@link org.quartz.Job} with the given name - by - * pausing all of its current Triggers. - *

- * - * @see #resumeJob(SchedulingContext, String, String) - */ - public void pauseJob(SchedulingContext ctxt, String jobName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - Trigger[] triggers = getTriggersForJob(conn, ctxt, jobName, - groupName); - for (int j = 0; j < triggers.length; j++) { - pauseTrigger(conn, ctxt, triggers[j].getName(), triggers[j] - .getGroup()); - } - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Pause all of the {@link org.quartz.Job}s in the given - * group - by pausing all of their Triggers. - *

- * - * @see #resumeJobGroup(SchedulingContext, String) - */ - public void pauseJobGroup(SchedulingContext ctxt, String groupName) - throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - String[] jobNames = getJobNames(conn, ctxt, groupName); - - for (int i = 0; i < jobNames.length; i++) { - Trigger[] triggers = getTriggersForJob(conn, ctxt, jobNames[i], - groupName); - for (int j = 0; j < triggers.length; j++) { - pauseTrigger(conn, ctxt, triggers[j].getName(), triggers[j] - .getGroup()); + if (lockName != null) { + // If we aren't using db locks, then delay getting DB connection + // until after acquiring the lock since it isn't needed. + if (getLockHandler().requiresConnection()) { + conn = getConnection(); } + + transOwner = getLockHandler().obtainLock(conn, lockName); } - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - /** - *

- * Resume (un-pause) the {@link org.quartz.Trigger} with the - * given name. - *

- * - *

- * If the Trigger missed one or more fire-times, then the - * Trigger's misfire instruction will be applied. - *

- * - * @see #pauseTrigger(SchedulingContext, String, String) - */ - public void resumeTrigger(SchedulingContext ctxt, String triggerName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - resumeTrigger(conn, ctxt, triggerName, groupName); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Resume (un-pause) all of the {@link org.quartz.Trigger}s - * in the given group. - *

- * - *

- * If any Trigger missed one or more fire-times, then the - * Trigger's misfire instruction will be applied. - *

- * - * @see #pauseTriggerGroup(SchedulingContext, String) - */ - public void resumeTriggerGroup(SchedulingContext ctxt, String groupName) - throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - resumeTriggerGroup(conn, ctxt, groupName); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Resume (un-pause) the {@link org.quartz.Job} with the - * given name. - *

- * - *

- * If any of the Job'sTrigger s missed one - * or more fire-times, then the Trigger's misfire - * instruction will be applied. - *

- * - * @see #pauseJob(SchedulingContext, String, String) - */ - public void resumeJob(SchedulingContext ctxt, String jobName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - Trigger[] triggers = getTriggersForJob(conn, ctxt, jobName, - groupName); - for (int j = 0; j < triggers.length; j++) { - resumeTrigger(conn, ctxt, triggers[j].getName(), triggers[j] - .getGroup()); + if (conn == null) { + conn = getConnection(); } - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - /** - *

- * Resume (un-pause) all of the {@link org.quartz.Job}s in - * the given group. - *

- * - *

- * If any of the Job s had Trigger s that - * missed one or more fire-times, then the Trigger's - * misfire instruction will be applied. - *

- * - * @see #pauseJobGroup(SchedulingContext, String) - */ - public void resumeJobGroup(SchedulingContext ctxt, String groupName) - throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - String[] jobNames = getJobNames(conn, ctxt, groupName); - - for (int i = 0; i < jobNames.length; i++) { - Trigger[] triggers = getTriggersForJob(conn, ctxt, jobNames[i], - groupName); - for (int j = 0; j < triggers.length; j++) { - resumeTrigger(conn, ctxt, triggers[j].getName(), - triggers[j].getGroup()); - } - } + return txCallback.execute(conn); } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Pause all triggers - equivalent of calling pauseTriggerGroup(group) - * on every group. - *

- * - *

- * When resumeAll() is called (to un-pause), trigger misfire - * instructions WILL be applied. - *

- * - * @see #resumeAll(SchedulingContext) - * @see #pauseTriggerGroup(SchedulingContext, String) - */ - public void pauseAll(SchedulingContext ctxt) throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - pauseAll(conn, ctxt); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Resume (un-pause) all triggers - equivalent of calling resumeTriggerGroup(group) - * on every group. - *

- * - *

- * If any Trigger missed one or more fire-times, then the - * Trigger's misfire instruction will be applied. - *

- * - * @see #pauseAll(SchedulingContext) - */ - public void resumeAll(SchedulingContext ctxt) - throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - resumeAll(conn, ctxt); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - //--------------------------------------------------------------------------- - // trigger firing methods - //--------------------------------------------------------------------------- - - /** - *

- * Get a handle to the next trigger to be fired, and mark it as 'reserved' - * by the calling scheduler. - *

- * - * @see #releaseAcquiredTrigger(SchedulingContext, Trigger) - */ - public Trigger acquireNextTrigger(SchedulingContext ctxt, long noLaterThan) - throws JobPersistenceException { - Connection conn = null; - boolean transOwner = false; - - try { - conn = getNonManagedTXConnection(); - - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - Trigger trigger = acquireNextTrigger(conn, ctxt, noLaterThan); - - conn.commit(); - return trigger; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } catch (Exception e) { - rollbackConnection(conn); - throw new JobPersistenceException( - "Error acquiring next firable trigger: " + e.getMessage(), - e); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Inform the JobStore that the scheduler no longer plans to - * fire the given Trigger, that it had previously acquired - * (reserved). - *

- */ - public void releaseAcquiredTrigger(SchedulingContext ctxt, Trigger trigger) - throws JobPersistenceException { - Connection conn = null; - boolean transOwner = false; - - try { - conn = getNonManagedTXConnection(); - - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - releaseAcquiredTrigger(conn, ctxt, trigger); - conn.commit(); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } catch (Exception e) { - rollbackConnection(conn); - throw new JobPersistenceException( - "Error releasing acquired trigger: " + e.getMessage(), e); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Inform the JobStore that the scheduler is now firing the - * given Trigger (executing its associated Job), - * that it had previously acquired (reserved). - *

- * - * @return null if the trigger or it's job or calendar no longer exist, or - * if the trigger was not successfully put into the 'executing' - * state. - */ - public TriggerFiredBundle triggerFired(SchedulingContext ctxt, - Trigger trigger) throws JobPersistenceException { - Connection conn = null; - boolean transOwner = false; - - try { - conn = getNonManagedTXConnection(); - - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - TriggerFiredBundle tfb = null; - JobPersistenceException err = null; try { - tfb = triggerFired(conn, ctxt, trigger); - } catch (JobPersistenceException jpe) { - if (jpe.getErrorCode() != SchedulerException.ERR_PERSISTENCE_JOB_DOES_NOT_EXIST) - throw jpe; - err = jpe; + releaseLock(LOCK_TRIGGER_ACCESS, transOwner); + } finally { + cleanupConnection(conn); } - - if (err != null) throw err; - - conn.commit(); - return tfb; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } catch (Exception e) { - rollbackConnection(conn); - throw new JobPersistenceException("TX failure: " + e.getMessage(), - e); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } } } - - /** - *

- * Inform the JobStore that the scheduler has completed the - * firing of the given Trigger (and the execution its - * associated Job), and that the {@link org.quartz.JobDataMap} - * in the given JobDetail should be updated if the Job - * is stateful. - *

- */ - public void triggeredJobComplete(SchedulingContext ctxt, Trigger trigger, - JobDetail jobDetail, int triggerInstCode) - throws JobPersistenceException { - Connection conn = null; - boolean transOwner = false; - - try { - conn = getNonManagedTXConnection(); - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - triggeredJobComplete(conn, ctxt, trigger, jobDetail, - triggerInstCode); - - conn.commit(); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } catch (Exception e) { - rollbackConnection(conn); - throw new JobPersistenceException("TX failure: " + e.getMessage(), - e); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - protected boolean doRecoverMisfires() throws JobPersistenceException { - Connection conn = null; - boolean transOwner = false; - boolean moreToDo = false; - - try { - conn = getNonManagedTXConnection(); - - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - - try { - moreToDo = recoverMisfiredJobs(conn, false); - } catch (Exception e) { - throw new JobPersistenceException(e.getMessage(), e); - } - - conn.commit(); - - return moreToDo; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } catch (Exception e) { - rollbackConnection(conn); - throw new JobPersistenceException("TX failure: " + e.getMessage(), - e); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - - } - - protected boolean doCheckin() throws JobPersistenceException { - Connection conn = null; - - boolean transOwner = false; - boolean transStateOwner = false; - boolean recovered = false; - - try { - conn = getNonManagedTXConnection(); - - // Other than the first time, always checkin first to make sure there is - // work to be done before we aquire / the lock (since that is expensive, - // and is almost never necessary) - List failedRecords = (firstCheckIn) ? null : clusterCheckIn(conn); - - if (firstCheckIn || (failedRecords.size() > 0)) { - getLockHandler().obtainLock(conn, LOCK_STATE_ACCESS); - transStateOwner = true; - - // Now that we own the lock, make sure we still have work to do. - // The first time through, we also need to make sure we update/create our state record - failedRecords = (firstCheckIn) ? clusterCheckIn(conn) : findFailedInstances(conn); - - if (failedRecords.size() > 0) { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - transOwner = true; - - clusterRecover(conn, failedRecords); - recovered = true; - } - } - conn.commit(); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } catch (Exception e) { - rollbackConnection(conn); - throw new JobPersistenceException("TX failure: " + e.getMessage(), - e); - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - try { - releaseLock(conn, LOCK_STATE_ACCESS, transStateOwner); - } finally { - closeConnection(conn); - } - } - } - - firstCheckIn = false; - - return recovered; - } - - //--------------------------------------------------------------------------- - // private helpers - //--------------------------------------------------------------------------- - - - protected Connection getNonManagedTXConnection() - throws JobPersistenceException { - try { - Connection conn = DBConnectionManager.getInstance().getConnection( - getNonManagedTXDataSource()); - - if (conn == null) { throw new SQLException( - "Could not get connection from DataSource '" - + getNonManagedTXDataSource() + "'"); } - - try { - if (!isDontSetNonManagedTXConnectionAutoCommitFalse()) - conn.setAutoCommit(false); - - if (isTxIsolationLevelReadCommitted()) - conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); - } catch (SQLException ingore) { - } catch (Exception e) { - if(conn != null) - try { conn.close(); } catch(Throwable tt) {} - throw new JobPersistenceException( - "Failure setting up connection.", e); - } - - return conn; - } catch (SQLException sqle) { - throw new JobPersistenceException( - "Failed to obtain DB connection from data source '" - + getNonManagedTXDataSource() + "': " - + sqle.toString(), sqle); - } catch (Exception e) { - throw new JobPersistenceException( - "Failed to obtain DB connection from data source '" - + getNonManagedTXDataSource() + "': " - + e.toString(), e, - JobPersistenceException.ERR_PERSISTENCE_CRITICAL_FAILURE); - } - } - } // EOF Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/JobStoreSupport.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/JobStoreSupport.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/JobStoreSupport.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/JobStoreSupport.java 15 Dec 2014 10:09:51 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,44 +15,52 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.SQLException; +import java.util.ArrayList; import java.util.Date; import java.util.HashMap; -import java.util.Iterator; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Set; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.quartz.Calendar; -import org.quartz.CronTrigger; +import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobDetail; +import org.quartz.JobKey; import org.quartz.JobPersistenceException; import org.quartz.ObjectAlreadyExistsException; import org.quartz.Scheduler; import org.quartz.SchedulerConfigException; import org.quartz.SchedulerException; import org.quartz.SimpleTrigger; import org.quartz.Trigger; -import org.quartz.core.SchedulingContext; +import org.quartz.Trigger.CompletedExecutionInstruction; +import org.quartz.Trigger.TriggerState; +import org.quartz.TriggerKey; +import org.quartz.impl.DefaultThreadExecutor; +import org.quartz.impl.matchers.GroupMatcher; +import org.quartz.impl.matchers.StringMatcher; +import org.quartz.impl.matchers.StringMatcher.StringOperatorName; +import org.quartz.impl.triggers.SimpleTriggerImpl; import org.quartz.spi.ClassLoadHelper; import org.quartz.spi.JobStore; +import org.quartz.spi.OperableTrigger; import org.quartz.spi.SchedulerSignaler; +import org.quartz.spi.ThreadExecutor; import org.quartz.spi.TriggerFiredBundle; +import org.quartz.spi.TriggerFiredResult; import org.quartz.utils.DBConnectionManager; -import org.quartz.utils.Key; -import org.quartz.utils.TriggerStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** @@ -73,16 +81,10 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - protected static String LOCK_TRIGGER_ACCESS = "TRIGGER_ACCESS"; + protected static final String LOCK_TRIGGER_ACCESS = "TRIGGER_ACCESS"; - protected static String LOCK_JOB_ACCESS = "JOB_ACCESS"; + protected static final String LOCK_STATE_ACCESS = "STATE_ACCESS"; - protected static String LOCK_CALENDAR_ACCESS = "CALENDAR_ACCESS"; - - protected static String LOCK_STATE_ACCESS = "STATE_ACCESS"; - - protected static String LOCK_MISFIRE_ACCESS = "MISFIRE_ACCESS"; - /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -102,10 +104,13 @@ protected String instanceName; protected String delegateClassName; - protected Class delegateClass = StdJDBCDelegate.class; - protected HashMap calendarCache = new HashMap(); + protected String delegateInitString; + + protected Class delegateClass = StdJDBCDelegate.class; + protected HashMap calendarCache = new HashMap(); + private DriverDelegate delegate; private long misfireThreshold = 60000L; // one minute @@ -130,14 +135,30 @@ private ClassLoadHelper classLoadHelper; - private SchedulerSignaler signaler; + private SchedulerSignaler schedSignaler; protected int maxToRecoverAtATime = 20; private boolean setTxIsolationLevelSequential = false; - private long dbRetryInterval = 10000; + private boolean acquireTriggersWithinLock = false; + private long dbRetryInterval = 15000L; // 15 secs + + private boolean makeThreadsDaemons = false; + + private boolean threadsInheritInitializersClassLoadContext = false; + private ClassLoader initializersLoader = null; + + private boolean doubleCheckLockMisfireHandler = true; + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private ThreadExecutor threadExecutor = new DefaultThreadExecutor(); + + private volatile boolean schedulerRunning = false; + private volatile boolean shutdown = false; + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -172,7 +193,9 @@ *

*/ public void setTablePrefix(String prefix) { - if (prefix == null) prefix = ""; + if (prefix == null) { + prefix = ""; + } this.tablePrefix = prefix; } @@ -191,10 +214,13 @@ * Set whether String-only properties will be handled in JobDataMaps. *

*/ + @SuppressWarnings("UnusedDeclaration") /* called reflectively */ public void setUseProperties(String useProp) { - if (useProp == null) useProp = "false"; + if (useProp == null) { + useProp = "false"; + } - this.useProperties = Boolean.valueOf(useProp).booleanValue(); + this.useProperties = Boolean.valueOf(useProp); } /** @@ -226,29 +252,43 @@ } /** - *

- * Set the instance Id of the Scheduler (must be unique within a cluster). - *

+ * Set the instance name of the Scheduler (must be unique within this server instance). */ public void setInstanceName(String instanceName) { this.instanceName = instanceName; } + public void setThreadPoolSize(final int poolSize) { + // + } + + public void setThreadExecutor(ThreadExecutor threadExecutor) { + this.threadExecutor = threadExecutor; + } + + public ThreadExecutor getThreadExecutor() { + return threadExecutor; + } + + /** - *

- * Get the instance Id of the Scheduler (must be unique within a cluster). - *

+ * Get the instance name of the Scheduler (must be unique within this server instance). */ public String getInstanceName() { return instanceName; } + public long getEstimatedTimeToReleaseAndAcquireTrigger() { + return 70; + } + /** *

* Set whether this instance is part of a cluster. *

*/ + @SuppressWarnings("UnusedDeclaration") /* called reflectively */ public void setIsClustered(boolean isClustered) { this.isClustered = isClustered; } @@ -280,6 +320,7 @@ * detecting failed instances. *

*/ + @SuppressWarnings("UnusedDeclaration") /* called reflectively */ public void setClusterCheckinInterval(long l) { clusterCheckinInterval = l; } @@ -302,6 +343,7 @@ * default is 20. *

*/ + @SuppressWarnings("UnusedDeclaration") /* called reflectively */ public void setMaxMisfiresToHandleAtATime(int maxToRecoverAtATime) { this.maxToRecoverAtATime = maxToRecoverAtATime; } @@ -345,16 +387,21 @@ /** * Whether or not to obtain locks when inserting new jobs/triggers. - * Defaults to true, which is safest - some db's (such as + *

+ * Defaults to true, which is safest. Some databases (such as * MS SQLServer) seem to require this to avoid deadlocks under high load, - * while others seem to do fine without. + * while others seem to do fine without. Settings this to false means + * isolation guarantees between job scheduling and trigger acquisition are + * entirely enforced by the database. Depending on the database and it's + * configuration this may cause unusual scheduling behaviors. * *

Setting this property to false will provide a * significant performance increase during the addition of new jobs * and triggers.

* - * @param lockOnInsert + * @param lockOnInsert whether locking should be used when inserting new jobs/triggers */ + @SuppressWarnings("UnusedDeclaration") /* called reflectively */ public void setLockOnInsert(boolean lockOnInsert) { this.lockOnInsert = lockOnInsert; } @@ -368,12 +415,14 @@ * next-fire-time, in order for it to be considered "misfired" and thus * have its misfire instruction applied. * - * @param misfireThreshold + * @param misfireThreshold the misfire threshold to use, in millis */ + @SuppressWarnings("UnusedDeclaration") /* called reflectively */ public void setMisfireThreshold(long misfireThreshold) { - if (misfireThreshold < 1) - throw new IllegalArgumentException( - "Misfirethreashold must be larger than 0"); + if (misfireThreshold < 1) { + throw new IllegalArgumentException( + "Misfirethreshold must be larger than 0"); + } this.misfireThreshold = misfireThreshold; } @@ -383,28 +432,56 @@ /** * Don't call set autocommit(false) on connections obtained from the - * DataSource. This can be helpfull in a few situations, such as if you + * DataSource. This can be helpful in a few situations, such as if you * have a driver that complains if it is called when it is already off. * - * @param b + * @param b whether or not autocommit should be set to false on db connections */ + @SuppressWarnings("UnusedDeclaration") /* called reflectively */ public void setDontSetAutoCommitFalse(boolean b) { dontSetAutoCommitFalse = b; } public boolean isTxIsolationLevelSerializable() { - return setTxIsolationLevelSequential; + return setTxIsolationLevelSequential; } /** * Set the transaction isolation level of DB connections to sequential. * - * @param b + * @param b whether isolation level should be set to sequential. */ + @SuppressWarnings("UnusedDeclaration") /* called reflectively */ public void setTxIsolationLevelSerializable(boolean b) { - setTxIsolationLevelSequential = b; + setTxIsolationLevelSequential = b; } + /** + * Whether or not the query and update to acquire a Trigger for firing + * should be performed after obtaining an explicit DB lock (to avoid + * possible race conditions on the trigger's db row). This is the + * behavior prior to Quartz 1.6.3, but is considered unnecessary for most + * databases (due to the nature of the SQL update that is performed), + * and therefore a superfluous performance hit. + */ + public boolean isAcquireTriggersWithinLock() { + return acquireTriggersWithinLock; + } + + /** + * Whether or not the query and update to acquire a Trigger for firing + * should be performed after obtaining an explicit DB lock. This is the + * behavior prior to Quartz 1.6.3, but is considered unnecessary for most + * databases, and therefore a superfluous performance hit. + * + * However, if batch acquisition is used, it is important for this behavior + * to be used for all dbs. + */ + @SuppressWarnings("UnusedDeclaration") /* called reflectively */ + public void setAcquireTriggersWithinLock(boolean acquireTriggersWithinLock) { + this.acquireTriggersWithinLock = acquireTriggersWithinLock; + } + /** *

@@ -414,9 +491,12 @@ * @param delegateClassName * the delegate class name */ + @SuppressWarnings("UnusedDeclaration") /* called reflectively */ public void setDriverDelegateClass(String delegateClassName) - throws InvalidConfigurationException { - this.delegateClassName = delegateClassName; + throws InvalidConfigurationException { + synchronized(this) { + this.delegateClassName = delegateClassName; + } } /** @@ -430,6 +510,31 @@ return delegateClassName; } + /** + *

+ * Set the JDBC driver delegate's initialization string. + *

+ * + * @param delegateInitString + * the delegate init string + */ + @SuppressWarnings("UnusedDeclaration") /* called reflectively */ + public void setDriverDelegateInitString(String delegateInitString) + throws InvalidConfigurationException { + this.delegateInitString = delegateInitString; + } + + /** + *

+ * Get the JDBC driver delegate's initialization string. + *

+ * + * @return the delegate init string + */ + public String getDriverDelegateInitString() { + return delegateInitString; + } + public String getSelectWithLockSQL() { return selectWithLockSQL; } @@ -450,62 +555,137 @@ return classLoadHelper; } + /** + * Get whether the threads spawned by this JobStore should be + * marked as daemon. Possible threads include the MisfireHandler + * and the ClusterManager. + * + * @see Thread#setDaemon(boolean) + */ + public boolean getMakeThreadsDaemons() { + return makeThreadsDaemons; + } + + /** + * Set whether the threads spawned by this JobStore should be + * marked as daemon. Possible threads include the MisfireHandler + * and the ClusterManager. + * + * @see Thread#setDaemon(boolean) + */ + @SuppressWarnings("UnusedDeclaration") /* called reflectively */ + public void setMakeThreadsDaemons(boolean makeThreadsDaemons) { + this.makeThreadsDaemons = makeThreadsDaemons; + } + + /** + * Get whether to set the class load context of spawned threads to that + * of the initializing thread. + */ + public boolean isThreadsInheritInitializersClassLoadContext() { + return threadsInheritInitializersClassLoadContext; + } + + /** + * Set whether to set the class load context of spawned threads to that + * of the initializing thread. + */ + public void setThreadsInheritInitializersClassLoadContext( + boolean threadsInheritInitializersClassLoadContext) { + this.threadsInheritInitializersClassLoadContext = threadsInheritInitializersClassLoadContext; + } + + /** + * Get whether to check to see if there are Triggers that have misfired + * before actually acquiring the lock to recover them. This should be + * set to false if the majority of the time, there are are misfired + * Triggers. + */ + public boolean getDoubleCheckLockMisfireHandler() { + return doubleCheckLockMisfireHandler; + } + + /** + * Set whether to check to see if there are Triggers that have misfired + * before actually acquiring the lock to recover them. This should be + * set to false if the majority of the time, there are are misfired + * Triggers. + */ + @SuppressWarnings("UnusedDeclaration") /* called reflectively */ + public void setDoubleCheckLockMisfireHandler( + boolean doubleCheckLockMisfireHandler) { + this.doubleCheckLockMisfireHandler = doubleCheckLockMisfireHandler; + } + //--------------------------------------------------------------------------- // interface methods //--------------------------------------------------------------------------- - Log getLog() { - return LogFactory.getLog(getClass()); + protected Logger getLog() { + return log; } /** *

* Called by the QuartzScheduler before the JobStore is - * used, in order to give the it a chance to initialize. + * used, in order to give it a chance to initialize. *

*/ public void initialize(ClassLoadHelper loadHelper, SchedulerSignaler signaler) throws SchedulerConfigException { - if (dsName == null) { throw new SchedulerConfigException( - "DataSource name not set."); } + if (dsName == null) { + throw new SchedulerConfigException("DataSource name not set."); + } classLoadHelper = loadHelper; - this.signaler = signaler; - - if (!getUseDBLocks() && !isClustered()) { - getLog() - .info( - "Using thread monitor-based data access locking (synchronization)."); - lockHandler = new SimpleSemaphore(); - } else { - getLog() - .info( - "Using db table-based data access locking (synchronization)."); - lockHandler = new StdRowLockSemaphore(getTablePrefix(), - getSelectWithLockSQL()); + if(isThreadsInheritInitializersClassLoadContext()) { + log.info("JDBCJobStore threads will inherit ContextClassLoader of thread: " + Thread.currentThread().getName()); + initializersLoader = Thread.currentThread().getContextClassLoader(); } + + this.schedSignaler = signaler; - if (!isClustered()) { - try { - cleanVolatileTriggerAndJobs(); - } catch (SchedulerException se) { - throw new SchedulerConfigException( - "Failure occured during job recovery.", se); + // If the user hasn't specified an explicit lock handler, then + // choose one based on CMT/Clustered/UseDBLocks. + if (getLockHandler() == null) { + + // If the user hasn't specified an explicit lock handler, + // then we *must* use DB locks with clustering + if (isClustered()) { + setUseDBLocks(true); } + + if (getUseDBLocks()) { + if(getDriverDelegateClass() != null && getDriverDelegateClass().equals(MSSQLDelegate.class.getName())) { + if(getSelectWithLockSQL() == null) { + String msSqlDflt = "SELECT * FROM {0}LOCKS WITH (UPDLOCK,ROWLOCK) WHERE " + COL_SCHEDULER_NAME + " = {1} AND LOCK_NAME = ?"; + getLog().info("Detected usage of MSSQLDelegate class - defaulting 'selectWithLockSQL' to '" + msSqlDflt + "'."); + setSelectWithLockSQL(msSqlDflt); + } + } + getLog().info("Using db table-based data access locking (synchronization)."); + setLockHandler(new StdRowLockSemaphore(getTablePrefix(), getInstanceName(), getSelectWithLockSQL())); + } else { + getLog().info( + "Using thread monitor-based data access locking (synchronization)."); + setLockHandler(new SimpleSemaphore()); + } } - } + } + /** * @see org.quartz.spi.JobStore#schedulerStarted() */ public void schedulerStarted() throws SchedulerException { if (isClustered()) { - clusterManagementThread = new ClusterManager(this); + clusterManagementThread = new ClusterManager(); + if(initializersLoader != null) + clusterManagementThread.setContextClassLoader(initializersLoader); clusterManagementThread.initialize(); - } - else { + } else { try { recoverJobs(); } catch (SchedulerException se) { @@ -514,10 +694,23 @@ } } - misfireHandler = new MisfireHandler(this); + misfireHandler = new MisfireHandler(); + if(initializersLoader != null) + misfireHandler.setContextClassLoader(initializersLoader); misfireHandler.initialize(); + schedulerRunning = true; + + getLog().debug("JobStore background threads started (as scheduler was started)."); } + public void schedulerPaused() { + schedulerRunning = false; + } + + public void schedulerResumed() { + schedulerRunning = true; + } + /** *

* Called by the QuartzScheduler to inform the JobStore that @@ -526,16 +719,31 @@ *

*/ public void shutdown() { - if (clusterManagementThread != null) - clusterManagementThread.shutdown(); - - if (misfireHandler != null) misfireHandler.shutdown(); + shutdown = true; + if (misfireHandler != null) { + misfireHandler.shutdown(); + try { + misfireHandler.join(); + } catch (InterruptedException ignore) { + } + } + + if (clusterManagementThread != null) { + clusterManagementThread.shutdown(); + try { + clusterManagementThread.join(); + } catch (InterruptedException ignore) { + } + } + try { DBConnectionManager.getInstance().shutdown(getDataSource()); } catch (SQLException sqle) { getLog().warn("Database connection shutdown unsuccessful.", sqle); } + + getLog().debug("JobStore background threads shutdown."); } public boolean supportsPersistence() { @@ -546,115 +754,92 @@ // helper methods for subclasses //--------------------------------------------------------------------------- - + protected abstract Connection getNonManagedTXConnection() + throws JobPersistenceException; + /** + * Wrap the given Connection in a Proxy such that attributes + * that might be set will be restored before the connection is closed + * (and potentially restored to a pool). + */ + protected Connection getAttributeRestoringConnection(Connection conn) { + return (Connection)Proxy.newProxyInstance( + Thread.currentThread().getContextClassLoader(), + new Class[] { Connection.class }, + new AttributeRestoringConnectionInvocationHandler(conn)); + } + protected Connection getConnection() throws JobPersistenceException { + Connection conn; try { - Connection conn = DBConnectionManager.getInstance().getConnection( + conn = DBConnectionManager.getInstance().getConnection( getDataSource()); - - if (conn == null) { throw new SQLException( - "Could not get connection from DataSource '" - + getDataSource() + "'"); } - - try { - if (!isDontSetAutoCommitFalse()) conn.setAutoCommit(false); - - if(isTxIsolationLevelSerializable()) - conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); - } catch (SQLException ingore) { - } catch (Exception e) { - if(conn != null) - try { conn.close(); } catch(Throwable tt) {} - throw new JobPersistenceException( - "Failure setting up connection.", e); - } - - return conn; } catch (SQLException sqle) { throw new JobPersistenceException( "Failed to obtain DB connection from data source '" + getDataSource() + "': " + sqle.toString(), sqle); - } catch (Exception e) { + } catch (Throwable e) { throw new JobPersistenceException( "Failed to obtain DB connection from data source '" - + getDataSource() + "': " + e.toString(), e, - JobPersistenceException.ERR_PERSISTENCE_CRITICAL_FAILURE); + + getDataSource() + "': " + e.toString(), e); } - } - - protected void releaseLock(Connection conn, String lockName, boolean doIt) { - if (doIt && conn != null) { - try { - getLockHandler().releaseLock(conn, lockName); - } catch (LockException le) { - getLog().error("Error returning lock: " + le.getMessage(), - le); + + if (conn == null) { + throw new JobPersistenceException( + "Could not get connection from DataSource '" + + getDataSource() + "'"); } - } - } - - /** - *

- * Removes all volatile data - *

- * - * @throws JobPersistenceException - * if jobs could not be recovered - */ - protected abstract void cleanVolatileTriggerAndJobs() - throws JobPersistenceException; - /** - *

- * Removes all volatile data. - *

- * - * @throws JobPersistenceException - * if jobs could not be recovered - */ - protected void cleanVolatileTriggerAndJobs(Connection conn) - throws JobPersistenceException { - try { - // find volatile jobs & triggers... - Key[] volatileTriggers = getDelegate().selectVolatileTriggers(conn); - Key[] volatileJobs = getDelegate().selectVolatileJobs(conn); + // Protect connection attributes we might change. + conn = getAttributeRestoringConnection(conn); - for (int i = 0; i < volatileTriggers.length; i++) { - removeTrigger(conn, null, volatileTriggers[i].getName(), - volatileTriggers[i].getGroup()); + // Set any connection connection attributes we are to override. + try { + if (!isDontSetAutoCommitFalse()) { + conn.setAutoCommit(false); } - getLog().info( - "Removed " + volatileTriggers.length - + " Volatile Trigger(s)."); - for (int i = 0; i < volatileJobs.length; i++) { - removeJob(conn, null, volatileJobs[i].getName(), - volatileJobs[i].getGroup(), true); + if(isTxIsolationLevelSerializable()) { + conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); } - getLog().info( - "Removed " + volatileJobs.length + " Volatile Job(s)."); + } catch (SQLException sqle) { + getLog().warn("Failed to override connection auto commit/transaction isolation.", sqle); + } catch (Throwable e) { + try { conn.close(); } catch(Throwable ignored) {} + + throw new JobPersistenceException( + "Failure setting up connection.", e); + } + + return conn; + } - // clean up any fired trigger entries - getDelegate().deleteVolatileFiredTriggers(conn); - - } catch (Exception e) { - throw new JobPersistenceException("Couldn't clean volatile data: " - + e.getMessage(), e); + protected void releaseLock(String lockName, boolean doIt) { + if (doIt) { + try { + getLockHandler().releaseLock(lockName); + } catch (LockException le) { + getLog().error("Error returning lock: " + le.getMessage(), le); + } } } /** - *

- * Will recover any failed or misfired jobs and clean up the data store as + * Recover any failed or misfired jobs and clean up the data store as * appropriate. - *

* - * @throws JobPersistenceException - * if jobs could not be recovered + * @throws JobPersistenceException if jobs could not be recovered */ - protected abstract void recoverJobs() throws JobPersistenceException; - + protected void recoverJobs() throws JobPersistenceException { + executeInNonManagedTXLock( + LOCK_TRIGGER_ACCESS, + new VoidTransactionCallback() { + public void executeVoid(Connection conn) throws JobPersistenceException { + recoverJobs(conn); + } + }, null); + } + /** *

* Will recover any failed or misfired jobs and clean up the data store as @@ -678,41 +863,39 @@ + " triggers from 'acquired' / 'blocked' state."); // clean up misfired jobs - getDelegate().updateTriggerStateFromOtherStatesBeforeTime(conn, - STATE_MISFIRED, STATE_WAITING, STATE_WAITING, - getMisfireTime()); // only waiting recoverMisfiredJobs(conn, true); // recover jobs marked for recovery that were not fully executed - Trigger[] recoveringJobTriggers = getDelegate() + List recoveringJobTriggers = getDelegate() .selectTriggersForRecoveringJobs(conn); getLog() .info( "Recovering " - + recoveringJobTriggers.length + + recoveringJobTriggers.size() + " jobs that were in-progress at the time of the last shut-down."); - for (int i = 0; i < recoveringJobTriggers.length; ++i) { - if (jobExists(conn, recoveringJobTriggers[i].getJobName(), - recoveringJobTriggers[i].getJobGroup())) { - recoveringJobTriggers[i].computeFirstFireTime(null); - storeTrigger(conn, null, recoveringJobTriggers[i], null, false, + for (OperableTrigger recoveringJobTrigger: recoveringJobTriggers) { + if (jobExists(conn, recoveringJobTrigger.getJobKey())) { + recoveringJobTrigger.computeFirstFireTime(null); + storeTrigger(conn, recoveringJobTrigger, null, false, STATE_WAITING, false, true); } } getLog().info("Recovery complete."); // remove lingering 'complete' triggers... - Key[] ct = getDelegate().selectTriggersInState(conn, STATE_COMPLETE); - for(int i=0; ct != null && i < ct.length; i++) - removeTrigger(conn, null, ct[i].getName(), ct[i].getGroup()); + List cts = getDelegate().selectTriggersInState(conn, STATE_COMPLETE); + for(TriggerKey ct: cts) { + removeTrigger(conn, ct); + } getLog().info( - "Removed " + ct.length - + " 'complete' triggers."); + "Removed " + cts.size() + " 'complete' triggers."); // clean up any fired trigger entries int n = getDelegate().deleteFiredTriggers(conn); getLog().info("Removed " + n + " stale fired job entries."); + } catch (JobPersistenceException e) { + throw e; } catch (Exception e) { throw new JobPersistenceException("Couldn't recover jobs: " + e.getMessage(), e); @@ -721,131 +904,209 @@ protected long getMisfireTime() { long misfireTime = System.currentTimeMillis(); - if (getMisfireThreshold() > 0) misfireTime -= getMisfireThreshold(); + if (getMisfireThreshold() > 0) { + misfireTime -= getMisfireThreshold(); + } - return misfireTime; + return (misfireTime > 0) ? misfireTime : 0; } - private int lastRecoverCount = 0; + /** + * Helper class for returning the composite result of trying + * to recover misfired jobs. + */ + protected static class RecoverMisfiredJobsResult { + public static final RecoverMisfiredJobsResult NO_OP = + new RecoverMisfiredJobsResult(false, 0, Long.MAX_VALUE); + + private boolean _hasMoreMisfiredTriggers; + private int _processedMisfiredTriggerCount; + private long _earliestNewTime; + + public RecoverMisfiredJobsResult( + boolean hasMoreMisfiredTriggers, int processedMisfiredTriggerCount, long earliestNewTime) { + _hasMoreMisfiredTriggers = hasMoreMisfiredTriggers; + _processedMisfiredTriggerCount = processedMisfiredTriggerCount; + _earliestNewTime = earliestNewTime; + } + + public boolean hasMoreMisfiredTriggers() { + return _hasMoreMisfiredTriggers; + } + public int getProcessedMisfiredTriggerCount() { + return _processedMisfiredTriggerCount; + } + public long getEarliestNewTime() { + return _earliestNewTime; + } + } + + protected RecoverMisfiredJobsResult recoverMisfiredJobs( + Connection conn, boolean recovering) + throws JobPersistenceException, SQLException { - protected boolean recoverMisfiredJobs(Connection conn, boolean recovering) - throws JobPersistenceException, NoSuchDelegateException, - SQLException, ClassNotFoundException, IOException { + // If recovering, we want to handle all of the misfired + // triggers right away. + int maxMisfiresToHandleAtATime = + (recovering) ? -1 : getMaxMisfiresToHandleAtATime(); + + List misfiredTriggers = new LinkedList(); + long earliestNewTime = Long.MAX_VALUE; + // We must still look for the MISFIRED state in case triggers were left + // in this state when upgrading to this version that does not support it. + boolean hasMoreMisfiredTriggers = + getDelegate().hasMisfiredTriggersInState( + conn, STATE_WAITING, getMisfireTime(), + maxMisfiresToHandleAtATime, misfiredTriggers); - Key[] misfiredTriggers = getDelegate().selectTriggersInState(conn, - STATE_MISFIRED); - - if (misfiredTriggers.length > 0 - && misfiredTriggers.length > getMaxMisfiresToHandleAtATime()) getLog() - .info( - "Handling " - + getMaxMisfiresToHandleAtATime() - + " of " - + misfiredTriggers.length - + " triggers that missed their scheduled fire-time."); - else if (misfiredTriggers.length > 0) getLog().info( - "Handling " + misfiredTriggers.length - + " triggers that missed their scheduled fire-time."); - else + if (hasMoreMisfiredTriggers) { + getLog().info( + "Handling the first " + misfiredTriggers.size() + + " triggers that missed their scheduled fire-time. " + + "More misfired triggers remain to be processed."); + } else if (misfiredTriggers.size() > 0) { + getLog().info( + "Handling " + misfiredTriggers.size() + + " trigger(s) that missed their scheduled fire-time."); + } else { getLog().debug( - "Found 0 triggers that missed their scheduled fire-time."); + "Found 0 triggers that missed their scheduled fire-time."); + return RecoverMisfiredJobsResult.NO_OP; + } - lastRecoverCount = misfiredTriggers.length; + for (TriggerKey triggerKey: misfiredTriggers) { + + OperableTrigger trig = + retrieveTrigger(conn, triggerKey); - for (int i = 0; i < misfiredTriggers.length && i < getMaxMisfiresToHandleAtATime(); i++) { - Trigger trig = getDelegate().selectTrigger(conn, - misfiredTriggers[i].getName(), - misfiredTriggers[i].getGroup()); - - if (trig == null) continue; - - Calendar cal = null; - if (trig.getCalendarName() != null) - cal = retrieveCalendar(conn, null, trig.getCalendarName()); - - String[] listeners = getDelegate().selectTriggerListeners(conn, - trig.getName(), trig.getGroup()); - for (int l = 0; l < listeners.length; ++l) { - trig.addTriggerListener(listeners[l]); + if (trig == null) { + continue; } - - signaler.notifyTriggerListenersMisfired(trig); - trig.updateAfterMisfire(cal); + doUpdateOfMisfiredTrigger(conn, trig, false, STATE_WAITING, recovering); - if (trig.getNextFireTime() == null) - storeTrigger(conn, null, trig, null, true, STATE_COMPLETE, - false, recovering); - else - storeTrigger(conn, null, trig, null, true, STATE_WAITING, - false, recovering); + if(trig.getNextFireTime() != null && trig.getNextFireTime().getTime() < earliestNewTime) + earliestNewTime = trig.getNextFireTime().getTime(); } - if (misfiredTriggers.length > getMaxMisfiresToHandleAtATime()) return true; - - return false; + return new RecoverMisfiredJobsResult( + hasMoreMisfiredTriggers, misfiredTriggers.size(), earliestNewTime); } protected boolean updateMisfiredTrigger(Connection conn, - SchedulingContext ctxt, String triggerName, String groupName, - String newStateIfNotComplete, boolean forceState) // TODO: probably - // get rid of - // this - throws JobPersistenceException { + TriggerKey triggerKey, String newStateIfNotComplete, boolean forceState) + throws JobPersistenceException { try { - Trigger trig = getDelegate().selectTrigger(conn, triggerName, - groupName); + OperableTrigger trig = retrieveTrigger(conn, triggerKey); long misfireTime = System.currentTimeMillis(); - if (getMisfireThreshold() > 0) - misfireTime -= getMisfireThreshold(); + if (getMisfireThreshold() > 0) { + misfireTime -= getMisfireThreshold(); + } - if (trig.getNextFireTime().getTime() > misfireTime) return false; + if (trig.getNextFireTime().getTime() > misfireTime) { + return false; + } - Calendar cal = null; - if (trig.getCalendarName() != null) - cal = retrieveCalendar(conn, ctxt, trig.getCalendarName()); + doUpdateOfMisfiredTrigger(conn, trig, forceState, newStateIfNotComplete, false); - signaler.notifyTriggerListenersMisfired(trig); - - trig.updateAfterMisfire(cal); - - if (trig.getNextFireTime() == null) storeTrigger(conn, ctxt, trig, - null, true, STATE_COMPLETE, forceState, false); - else { - storeTrigger(conn, ctxt, trig, null, true, newStateIfNotComplete, - forceState, false); - } - return true; } catch (Exception e) { throw new JobPersistenceException( - "Couldn't update misfired trigger '" + groupName + "." - + triggerName + "': " + e.getMessage(), e); + "Couldn't update misfired trigger '" + triggerKey + "': " + e.getMessage(), e); } } + private void doUpdateOfMisfiredTrigger(Connection conn, OperableTrigger trig, boolean forceState, String newStateIfNotComplete, boolean recovering) throws JobPersistenceException { + Calendar cal = null; + if (trig.getCalendarName() != null) { + cal = retrieveCalendar(conn, trig.getCalendarName()); + } + + schedSignaler.notifyTriggerListenersMisfired(trig); + + trig.updateAfterMisfire(cal); + + if (trig.getNextFireTime() == null) { + storeTrigger(conn, trig, + null, true, STATE_COMPLETE, forceState, recovering); + schedSignaler.notifySchedulerListenersFinalized(trig); + } else { + storeTrigger(conn, trig, null, true, newStateIfNotComplete, + forceState, false); + } + } + /** *

+ * Store the given {@link org.quartz.JobDetail} and {@link org.quartz.Trigger}. + *

+ * + * @param newJob + * The JobDetail to be stored. + * @param newTrigger + * The Trigger to be stored. + * @throws ObjectAlreadyExistsException + * if a Job with the same name/group already + * exists. + */ + public void storeJobAndTrigger(final JobDetail newJob, + final OperableTrigger newTrigger) + throws JobPersistenceException { + executeInLock( + (isLockOnInsert()) ? LOCK_TRIGGER_ACCESS : null, + new VoidTransactionCallback() { + public void executeVoid(Connection conn) throws JobPersistenceException { + storeJob(conn, newJob, false); + storeTrigger(conn, newTrigger, newJob, false, + Constants.STATE_WAITING, false, false); + } + }); + } + + /** + *

+ * Store the given {@link org.quartz.JobDetail}. + *

+ * + * @param newJob + * The JobDetail to be stored. + * @param replaceExisting + * If true, any Job existing in the + * JobStore with the same name & group should be + * over-written. + * @throws ObjectAlreadyExistsException + * if a Job with the same name/group already + * exists, and replaceExisting is set to false. + */ + public void storeJob(final JobDetail newJob, + final boolean replaceExisting) throws JobPersistenceException { + executeInLock( + (isLockOnInsert() || replaceExisting) ? LOCK_TRIGGER_ACCESS : null, + new VoidTransactionCallback() { + public void executeVoid(Connection conn) throws JobPersistenceException { + storeJob(conn, newJob, replaceExisting); + } + }); + } + + /** + *

* Insert or update a job. *

*/ - protected void storeJob(Connection conn, SchedulingContext ctxt, + protected void storeJob(Connection conn, JobDetail newJob, boolean replaceExisting) - throws ObjectAlreadyExistsException, JobPersistenceException { - if (newJob.isVolatile() && isClustered()) - getLog() - .info( - "note: volatile jobs are effectively non-volatile in a clustered environment."); + throws JobPersistenceException { - boolean existingJob = jobExists(conn, newJob.getName(), newJob - .getGroup()); + boolean existingJob = jobExists(conn, newJob.getKey()); try { if (existingJob) { - if (!replaceExisting) { throw new ObjectAlreadyExistsException( - newJob); } + if (!replaceExisting) { + throw new ObjectAlreadyExistsException(newJob); + } getDelegate().updateJobDetail(conn, newJob); } else { getDelegate().insertJobDetail(conn, newJob); @@ -864,105 +1125,103 @@ * Check existence of a given job. *

*/ - protected boolean jobExists(Connection conn, String jobName, - String groupName) throws JobPersistenceException { + protected boolean jobExists(Connection conn, JobKey jobKey) throws JobPersistenceException { try { - return getDelegate().jobExists(conn, jobName, groupName); + return getDelegate().jobExists(conn, jobKey); } catch (SQLException e) { throw new JobPersistenceException( - "Couldn't determine job existence (" + groupName + "." - + jobName + "): " + e.getMessage(), e); + "Couldn't determine job existence (" + jobKey + "): " + e.getMessage(), e); } } + /** *

+ * Store the given {@link org.quartz.Trigger}. + *

+ * + * @param newTrigger + * The Trigger to be stored. + * @param replaceExisting + * If true, any Trigger existing in + * the JobStore with the same name & group should + * be over-written. + * @throws ObjectAlreadyExistsException + * if a Trigger with the same name/group already + * exists, and replaceExisting is set to false. + */ + public void storeTrigger(final OperableTrigger newTrigger, + final boolean replaceExisting) throws JobPersistenceException { + executeInLock( + (isLockOnInsert() || replaceExisting) ? LOCK_TRIGGER_ACCESS : null, + new VoidTransactionCallback() { + public void executeVoid(Connection conn) throws JobPersistenceException { + storeTrigger(conn, newTrigger, null, replaceExisting, + STATE_WAITING, false, false); + } + }); + } + + /** + *

* Insert or update a trigger. *

*/ - protected void storeTrigger(Connection conn, SchedulingContext ctxt, - Trigger newTrigger, JobDetail job, boolean replaceExisting, String state, + @SuppressWarnings("ConstantConditions") + protected void storeTrigger(Connection conn, + OperableTrigger newTrigger, JobDetail job, boolean replaceExisting, String state, boolean forceState, boolean recovering) - throws ObjectAlreadyExistsException, JobPersistenceException { - if (newTrigger.isVolatile() && isClustered()) - getLog() - .info( - "note: volatile triggers are effectively non-volatile in a clustered environment."); + throws JobPersistenceException { - boolean existingTrigger = triggerExists(conn, newTrigger.getName(), - newTrigger.getGroup()); + boolean existingTrigger = triggerExists(conn, newTrigger.getKey()); + if ((existingTrigger) && (!replaceExisting)) { + throw new ObjectAlreadyExistsException(newTrigger); + } + try { - boolean shouldBepaused = false; + boolean shouldBepaused; if (!forceState) { shouldBepaused = getDelegate().isTriggerGroupPaused( - conn, newTrigger.getGroup()); + conn, newTrigger.getKey().getGroup()); if(!shouldBepaused) { shouldBepaused = getDelegate().isTriggerGroupPaused(conn, ALL_GROUPS_PAUSED); - if (shouldBepaused) - getDelegate().insertPausedTriggerGroup(conn, - newTrigger.getGroup()); + if (shouldBepaused) { + getDelegate().insertPausedTriggerGroup(conn, newTrigger.getKey().getGroup()); + } } - if (shouldBepaused && (state.equals(STATE_WAITING) || state.equals(STATE_ACQUIRED))) - state = STATE_PAUSED; + if (shouldBepaused && (state.equals(STATE_WAITING) || state.equals(STATE_ACQUIRED))) { + state = STATE_PAUSED; + } } if(job == null) { - job = getDelegate().selectJobDetail(conn, - newTrigger.getJobName(), newTrigger.getJobGroup(), - getClassLoadHelper()); + job = getDelegate().selectJobDetail(conn, newTrigger.getJobKey(), getClassLoadHelper()); } - if (job == null) - throw new JobPersistenceException("The job (" - + newTrigger.getFullJobName() - + ") referenced by the trigger does not exist."); - if (job.isVolatile() && !newTrigger.isVolatile()) - throw new JobPersistenceException( - "It does not make sense to " - + "associate a non-volatile Trigger with a volatile Job!"); + if (job == null) { + throw new JobPersistenceException("The job (" + + newTrigger.getJobKey() + + ") referenced by the trigger does not exist."); + } - if (job.isStateful() && !recovering) { - String bstate = getNewStatusForTrigger(conn, ctxt, job.getName(), job - .getGroup()); - if(STATE_BLOCKED.equals(bstate) && STATE_WAITING.equals(state)) - state = STATE_BLOCKED; - if(STATE_BLOCKED.equals(bstate) && STATE_PAUSED.equals(state)) - state = STATE_PAUSED_BLOCKED; + if (job.isConcurrentExectionDisallowed() && !recovering) { + state = checkBlockedState(conn, job.getKey(), state); } + if (existingTrigger) { - if (!replaceExisting) { throw new ObjectAlreadyExistsException( - newTrigger); } - if (newTrigger instanceof SimpleTrigger) { - getDelegate().updateSimpleTrigger(conn, - (SimpleTrigger) newTrigger); - } else if (newTrigger instanceof CronTrigger) { - getDelegate().updateCronTrigger(conn, - (CronTrigger) newTrigger); - } else { - getDelegate().updateBlobTrigger(conn, newTrigger); - } getDelegate().updateTrigger(conn, newTrigger, state, job); } else { getDelegate().insertTrigger(conn, newTrigger, state, job); - if (newTrigger instanceof SimpleTrigger) { - getDelegate().insertSimpleTrigger(conn, - (SimpleTrigger) newTrigger); - } else if (newTrigger instanceof CronTrigger) { - getDelegate().insertCronTrigger(conn, - (CronTrigger) newTrigger); - } else { - getDelegate().insertBlobTrigger(conn, newTrigger); - } } } catch (Exception e) { - throw new JobPersistenceException("Couldn't store trigger: " - + e.getMessage(), e); + throw new JobPersistenceException("Couldn't store trigger '" + newTrigger.getKey() + "' for '" + + newTrigger.getJobKey() + "' job:" + e.getMessage(), e); } } @@ -971,99 +1230,224 @@ * Check existence of a given trigger. *

*/ - protected boolean triggerExists(Connection conn, String triggerName, - String groupName) throws JobPersistenceException { + protected boolean triggerExists(Connection conn, TriggerKey key) throws JobPersistenceException { try { - return getDelegate().triggerExists(conn, triggerName, groupName); + return getDelegate().triggerExists(conn, key); } catch (SQLException e) { throw new JobPersistenceException( - "Couldn't determine trigger existence (" + groupName + "." - + triggerName + "): " + e.getMessage(), e); + "Couldn't determine trigger existence (" + key + "): " + e.getMessage(), e); } } - protected boolean removeJob(Connection conn, SchedulingContext ctxt, - String jobName, String groupName, boolean activeDeleteSafe) - throws JobPersistenceException { + /** + *

+ * Remove (delete) the {@link org.quartz.Job} with the given + * name, and any {@link org.quartz.Trigger} s that reference + * it. + *

+ * + *

+ * If removal of the Job results in an empty group, the + * group should be removed from the JobStore's list of + * known group names. + *

+ * + * @return true if a Job with the given name & + * group was found and removed from the store. + */ + public boolean removeJob(final JobKey jobKey) throws JobPersistenceException { + return (Boolean) executeInLock( + LOCK_TRIGGER_ACCESS, + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return removeJob(conn, jobKey) ? + Boolean.TRUE : Boolean.FALSE; + } + }); + } + + protected boolean removeJob(Connection conn, final JobKey jobKey) + throws JobPersistenceException { try { - Key[] jobTriggers = getDelegate().selectTriggerNamesForJob(conn, - jobName, groupName); - for (int i = 0; i < jobTriggers.length; ++i) { - getDelegate().deleteSimpleTrigger(conn, - jobTriggers[i].getName(), jobTriggers[i].getGroup()); - getDelegate().deleteCronTrigger(conn, jobTriggers[i].getName(), - jobTriggers[i].getGroup()); - getDelegate().deleteBlobTrigger(conn, jobTriggers[i].getName(), - jobTriggers[i].getGroup()); - getDelegate().deleteTriggerListeners(conn, - jobTriggers[i].getName(), jobTriggers[i].getGroup()); - getDelegate().deleteTrigger(conn, jobTriggers[i].getName(), - jobTriggers[i].getGroup()); + List jobTriggers = getDelegate().selectTriggerKeysForJob(conn, jobKey); + for (TriggerKey jobTrigger: jobTriggers) { + deleteTriggerAndChildren(conn, jobTrigger); } - getDelegate().deleteJobListeners(conn, jobName, groupName); - - if (getDelegate().deleteJobDetail(conn, jobName, groupName) > 0) { - return true; - } else { - return false; - } + return deleteJobAndChildren(conn, jobKey); } catch (SQLException e) { throw new JobPersistenceException("Couldn't remove job: " + e.getMessage(), e); } } - protected JobDetail retrieveJob(Connection conn, SchedulingContext ctxt, - String jobName, String groupName) throws JobPersistenceException { + public boolean removeJobs(final List jobKeys) throws JobPersistenceException { + + return (Boolean) executeInLock( + LOCK_TRIGGER_ACCESS, + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + boolean allFound = true; + + // FUTURE_TODO: make this more efficient with a true bulk operation... + for (JobKey jobKey : jobKeys) + allFound = removeJob(conn, jobKey) && allFound; + + return allFound ? Boolean.TRUE : Boolean.FALSE; + } + }); + } + + public boolean removeTriggers(final List triggerKeys) + throws JobPersistenceException { + return (Boolean) executeInLock( + LOCK_TRIGGER_ACCESS, + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + boolean allFound = true; + + // FUTURE_TODO: make this more efficient with a true bulk operation... + for (TriggerKey triggerKey : triggerKeys) + allFound = removeTrigger(conn, triggerKey) && allFound; + + return allFound ? Boolean.TRUE : Boolean.FALSE; + } + }); + } + + public void storeJobsAndTriggers( + final Map> triggersAndJobs, final boolean replace) + throws JobPersistenceException { + + executeInLock( + (isLockOnInsert() || replace) ? LOCK_TRIGGER_ACCESS : null, + new VoidTransactionCallback() { + public void executeVoid(Connection conn) throws JobPersistenceException { + + // FUTURE_TODO: make this more efficient with a true bulk operation... + for(JobDetail job: triggersAndJobs.keySet()) { + storeJob(conn, job, replace); + for(Trigger trigger: triggersAndJobs.get(job)) { + storeTrigger(conn, (OperableTrigger) trigger, job, replace, + Constants.STATE_WAITING, false, false); + } + } + } + }); + } + + /** + * Delete a job and its listeners. + * + * @see #removeJob(java.sql.Connection, org.quartz.JobKey) + * @see #removeTrigger(Connection, TriggerKey) + */ + private boolean deleteJobAndChildren(Connection conn, JobKey key) + throws NoSuchDelegateException, SQLException { + + return (getDelegate().deleteJobDetail(conn, key) > 0); + } + + /** + * Delete a trigger, its listeners, and its Simple/Cron/BLOB sub-table entry. + * + * @see #removeJob(java.sql.Connection, org.quartz.JobKey) + * @see #removeTrigger(Connection, TriggerKey) + * @see #replaceTrigger(Connection, TriggerKey, OperableTrigger) + */ + private boolean deleteTriggerAndChildren(Connection conn, TriggerKey key) + throws SQLException, NoSuchDelegateException { + + return (getDelegate().deleteTrigger(conn, key) > 0); + } + + /** + *

+ * Retrieve the {@link org.quartz.JobDetail} for the given + * {@link org.quartz.Job}. + *

+ * + * @return The desired Job, or null if there is no match. + */ + public JobDetail retrieveJob(final JobKey jobKey) throws JobPersistenceException { + return (JobDetail)executeWithoutLock( // no locks necessary for read... + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return retrieveJob(conn, jobKey); + } + }); + } + + protected JobDetail retrieveJob(Connection conn, JobKey key) throws JobPersistenceException { try { - JobDetail job = getDelegate().selectJobDetail(conn, jobName, - groupName, getClassLoadHelper()); - String[] listeners = getDelegate().selectJobListeners(conn, - jobName, groupName); - for (int i = 0; i < listeners.length; ++i) { - job.addJobListener(listeners[i]); - } - return job; + return getDelegate().selectJobDetail(conn, key, + getClassLoadHelper()); } catch (ClassNotFoundException e) { throw new JobPersistenceException( "Couldn't retrieve job because a required class was not found: " - + e.getMessage(), e, - SchedulerException.ERR_PERSISTENCE_JOB_DOES_NOT_EXIST); + + e.getMessage(), e); } catch (IOException e) { throw new JobPersistenceException( "Couldn't retrieve job because the BLOB couldn't be deserialized: " - + e.getMessage(), e, - SchedulerException.ERR_PERSISTENCE_JOB_DOES_NOT_EXIST); + + e.getMessage(), e); } catch (SQLException e) { throw new JobPersistenceException("Couldn't retrieve job: " + e.getMessage(), e); } } - protected boolean removeTrigger(Connection conn, SchedulingContext ctxt, - String triggerName, String groupName) - throws JobPersistenceException { - boolean removedTrigger = false; + /** + *

+ * Remove (delete) the {@link org.quartz.Trigger} with the + * given name. + *

+ * + *

+ * If removal of the Trigger results in an empty group, the + * group should be removed from the JobStore's list of + * known group names. + *

+ * + *

+ * If removal of the Trigger results in an 'orphaned' Job + * that is not 'durable', then the Job should be deleted + * also. + *

+ * + * @return true if a Trigger with the given + * name & group was found and removed from the store. + */ + public boolean removeTrigger(final TriggerKey triggerKey) throws JobPersistenceException { + return (Boolean) executeInLock( + LOCK_TRIGGER_ACCESS, + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return removeTrigger(conn, triggerKey) ? + Boolean.TRUE : Boolean.FALSE; + } + }); + } + + protected boolean removeTrigger(Connection conn, TriggerKey key) + throws JobPersistenceException { + boolean removedTrigger; try { // this must be called before we delete the trigger, obviously JobDetail job = getDelegate().selectJobForTrigger(conn, - triggerName, groupName, getClassLoadHelper()); + getClassLoadHelper(), key, false); - getDelegate().deleteSimpleTrigger(conn, triggerName, groupName); - getDelegate().deleteCronTrigger(conn, triggerName, groupName); - getDelegate().deleteBlobTrigger(conn, triggerName, groupName); - getDelegate().deleteTriggerListeners(conn, triggerName, groupName); - removedTrigger = (getDelegate().deleteTrigger(conn, triggerName, - groupName) > 0); + removedTrigger = + deleteTriggerAndChildren(conn, key); if (null != job && !job.isDurable()) { int numTriggers = getDelegate().selectNumTriggersForJob(conn, - job.getName(), job.getGroup()); + job.getKey()); if (numTriggers == 0) { - removeJob(conn, ctxt, job.getName(), job.getGroup(), true); + // Don't call removeJob() because we don't want to check for + // triggers again. + deleteJobAndChildren(conn, job.getKey()); } } } catch (ClassNotFoundException e) { @@ -1077,118 +1461,204 @@ return removedTrigger; } - protected boolean replaceTrigger(Connection conn, SchedulingContext ctxt, - String triggerName, String groupName, Trigger newTrigger) - throws JobPersistenceException { - boolean removedTrigger = false; + /** + * @see org.quartz.spi.JobStore#replaceTrigger(TriggerKey, OperableTrigger) + */ + public boolean replaceTrigger(final TriggerKey triggerKey, + final OperableTrigger newTrigger) throws JobPersistenceException { + return (Boolean) executeInLock( + LOCK_TRIGGER_ACCESS, + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return replaceTrigger(conn, triggerKey, newTrigger) ? + Boolean.TRUE : Boolean.FALSE; + } + }); + } + + protected boolean replaceTrigger(Connection conn, + TriggerKey key, OperableTrigger newTrigger) + throws JobPersistenceException { try { // this must be called before we delete the trigger, obviously JobDetail job = getDelegate().selectJobForTrigger(conn, - triggerName, groupName, getClassLoadHelper()); + getClassLoadHelper(), key); - if(job == null) + if (job == null) { return false; + } - if(!newTrigger.getJobName().equals(job.getName()) || - !newTrigger.getJobGroup().equals(job.getGroup())) + if (!newTrigger.getJobKey().equals(job.getKey())) { throw new JobPersistenceException("New trigger is not related to the same job as the old trigger."); + } - getDelegate().deleteSimpleTrigger(conn, triggerName, groupName); - getDelegate().deleteCronTrigger(conn, triggerName, groupName); - getDelegate().deleteBlobTrigger(conn, triggerName, groupName); - getDelegate().deleteTriggerListeners(conn, triggerName, groupName); - removedTrigger = (getDelegate().deleteTrigger(conn, triggerName, - groupName) > 0); + boolean removedTrigger = + deleteTriggerAndChildren(conn, key); - storeTrigger(conn, ctxt, newTrigger, job, false, STATE_WAITING, false, false); + storeTrigger(conn, newTrigger, job, false, STATE_WAITING, false, false); + return removedTrigger; } catch (ClassNotFoundException e) { throw new JobPersistenceException("Couldn't remove trigger: " + e.getMessage(), e); } catch (SQLException e) { throw new JobPersistenceException("Couldn't remove trigger: " + e.getMessage(), e); } - - return removedTrigger; } - protected Trigger retrieveTrigger(Connection conn, SchedulingContext ctxt, - String triggerName, String groupName) - throws JobPersistenceException { + /** + *

+ * Retrieve the given {@link org.quartz.Trigger}. + *

+ * + * @return The desired Trigger, or null if there is no + * match. + */ + public OperableTrigger retrieveTrigger(final TriggerKey triggerKey) throws JobPersistenceException { + return (OperableTrigger)executeWithoutLock( // no locks necessary for read... + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return retrieveTrigger(conn, triggerKey); + } + }); + } + + protected OperableTrigger retrieveTrigger(Connection conn, TriggerKey key) + throws JobPersistenceException { try { - Trigger trigger = getDelegate().selectTrigger(conn, triggerName, - groupName); - if (trigger == null) return null; - String[] listeners = getDelegate().selectTriggerListeners(conn, - triggerName, groupName); - for (int i = 0; i < listeners.length; ++i) { - trigger.addTriggerListener(listeners[i]); - } - return trigger; + return getDelegate().selectTrigger(conn, key); } catch (Exception e) { throw new JobPersistenceException("Couldn't retrieve trigger: " + e.getMessage(), e); } } - public int getTriggerState(Connection conn, SchedulingContext ctxt, - String triggerName, String groupName) - throws JobPersistenceException { + /** + *

+ * Get the current state of the identified {@link Trigger}. + *

+ * + * @see TriggerState#NORMAL + * @see TriggerState#PAUSED + * @see TriggerState#COMPLETE + * @see TriggerState#ERROR + * @see TriggerState#NONE + */ + public TriggerState getTriggerState(final TriggerKey triggerKey) throws JobPersistenceException { + return (TriggerState)executeWithoutLock( // no locks necessary for read... + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return getTriggerState(conn, triggerKey); + } + }); + } + + public TriggerState getTriggerState(Connection conn, TriggerKey key) + throws JobPersistenceException { try { - String ts = getDelegate().selectTriggerState(conn, triggerName, - groupName); + String ts = getDelegate().selectTriggerState(conn, key); - if (ts == null) return Trigger.STATE_NONE; + if (ts == null) { + return TriggerState.NONE; + } - if (ts.equals(STATE_DELETED)) return Trigger.STATE_NONE; + if (ts.equals(STATE_DELETED)) { + return TriggerState.NONE; + } - if (ts.equals(STATE_COMPLETE)) return Trigger.STATE_COMPLETE; + if (ts.equals(STATE_COMPLETE)) { + return TriggerState.COMPLETE; + } - if (ts.equals(STATE_PAUSED)) return Trigger.STATE_PAUSED; + if (ts.equals(STATE_PAUSED)) { + return TriggerState.PAUSED; + } - if (ts.equals(STATE_PAUSED_BLOCKED)) return Trigger.STATE_PAUSED; + if (ts.equals(STATE_PAUSED_BLOCKED)) { + return TriggerState.PAUSED; + } - if (ts.equals(STATE_ERROR)) return Trigger.STATE_ERROR; + if (ts.equals(STATE_ERROR)) { + return TriggerState.ERROR; + } - if (ts.equals(STATE_BLOCKED)) return Trigger.STATE_BLOCKED; + if (ts.equals(STATE_BLOCKED)) { + return TriggerState.BLOCKED; + } - return Trigger.STATE_NORMAL; + return TriggerState.NORMAL; } catch (SQLException e) { throw new JobPersistenceException( - "Couldn't determine state of trigger (" + groupName + "." - + triggerName + "): " + e.getMessage(), e); + "Couldn't determine state of trigger (" + key + "): " + e.getMessage(), e); } } - protected void storeCalendar(Connection conn, SchedulingContext ctxt, + /** + *

+ * Store the given {@link org.quartz.Calendar}. + *

+ * + * @param calName + * The name of the calendar. + * @param calendar + * The Calendar to be stored. + * @param replaceExisting + * If true, any Calendar existing + * in the JobStore with the same name & group + * should be over-written. + * @throws ObjectAlreadyExistsException + * if a Calendar with the same name already + * exists, and replaceExisting is set to false. + */ + public void storeCalendar(final String calName, + final Calendar calendar, final boolean replaceExisting, final boolean updateTriggers) + throws JobPersistenceException { + executeInLock( + (isLockOnInsert() || updateTriggers) ? LOCK_TRIGGER_ACCESS : null, + new VoidTransactionCallback() { + public void executeVoid(Connection conn) throws JobPersistenceException { + storeCalendar(conn, calName, calendar, replaceExisting, updateTriggers); + } + }); + } + + protected void storeCalendar(Connection conn, String calName, Calendar calendar, boolean replaceExisting, boolean updateTriggers) - throws ObjectAlreadyExistsException, JobPersistenceException { + throws JobPersistenceException { try { boolean existingCal = calendarExists(conn, calName); - if (existingCal && !replaceExisting) { throw new ObjectAlreadyExistsException( - "Calendar with name '" + calName + "' already exists."); } + if (existingCal && !replaceExisting) { + throw new ObjectAlreadyExistsException( + "Calendar with name '" + calName + "' already exists."); + } if (existingCal) { - if (getDelegate().updateCalendar(conn, calName, calendar) < 1) { throw new JobPersistenceException( - "Couldn't store calendar. Update failed."); } + if (getDelegate().updateCalendar(conn, calName, calendar) < 1) { + throw new JobPersistenceException( + "Couldn't store calendar. Update failed."); + } if(updateTriggers) { - Trigger[] trigs = getDelegate().selectTriggersForCalendar(conn, calName); + List trigs = getDelegate().selectTriggersForCalendar(conn, calName); - for(int i=0; i < trigs.length; i++) { - trigs[i].updateWithNewCalendar(calendar, getMisfireThreshold()); - storeTrigger(conn, ctxt, trigs[i], null, true, STATE_WAITING, false, false); + for(OperableTrigger trigger: trigs) { + trigger.updateWithNewCalendar(calendar, getMisfireThreshold()); + storeTrigger(conn, trigger, null, true, STATE_WAITING, false, false); } } } else { - if (getDelegate().insertCalendar(conn, calName, calendar) < 1) { throw new JobPersistenceException( - "Couldn't store calendar. Insert failed."); } + if (getDelegate().insertCalendar(conn, calName, calendar) < 1) { + throw new JobPersistenceException( + "Couldn't store calendar. Insert failed."); + } } - calendarCache.put(calName, calendar); // lazy-cache + if (!isClustered) { + calendarCache.put(calName, calendar); // lazy-cache + } } catch (IOException e) { throw new JobPersistenceException( @@ -1204,7 +1674,7 @@ } protected boolean calendarExists(Connection conn, String calName) - throws JobPersistenceException { + throws JobPersistenceException { try { return getDelegate().calendarExists(conn, calName); } catch (SQLException e) { @@ -1214,13 +1684,44 @@ } } - protected boolean removeCalendar(Connection conn, SchedulingContext ctxt, + /** + *

+ * Remove (delete) the {@link org.quartz.Calendar} with the + * given name. + *

+ * + *

+ * If removal of the Calendar would result in + * Triggers pointing to non-existent calendars, then a + * JobPersistenceException will be thrown.

+ * * + * @param calName The name of the Calendar to be removed. + * @return true if a Calendar with the given name + * was found and removed from the store. + */ + public boolean removeCalendar(final String calName) + throws JobPersistenceException { + return (Boolean) executeInLock( + LOCK_TRIGGER_ACCESS, + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return removeCalendar(conn, calName) ? + Boolean.TRUE : Boolean.FALSE; + } + }); + } + + protected boolean removeCalendar(Connection conn, String calName) throws JobPersistenceException { try { - if (getDelegate().calendarIsReferenced(conn, calName)) { throw new JobPersistenceException( - "Calender cannot be removed if it referenced by a trigger!"); } + if (getDelegate().calendarIsReferenced(conn, calName)) { + throw new JobPersistenceException( + "Calender cannot be removed if it referenced by a trigger!"); + } - calendarCache.remove(calName); + if (!isClustered) { + calendarCache.remove(calName); + } return (getDelegate().deleteCalendar(conn, calName) > 0); } catch (SQLException e) { @@ -1229,17 +1730,41 @@ } } + /** + *

+ * Retrieve the given {@link org.quartz.Trigger}. + *

+ * + * @param calName + * The name of the Calendar to be retrieved. + * @return The desired Calendar, or null if there is no + * match. + */ + public Calendar retrieveCalendar(final String calName) + throws JobPersistenceException { + return (Calendar)executeWithoutLock( // no locks necessary for read... + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return retrieveCalendar(conn, calName); + } + }); + } + protected Calendar retrieveCalendar(Connection conn, - SchedulingContext ctxt, String calName) - throws JobPersistenceException { - // all calendars are persistent, but we lazy-cache them during run - // time... - Calendar cal = (Calendar) calendarCache.get(calName); - if (cal != null) return cal; + String calName) + throws JobPersistenceException { + // all calendars are persistent, but we can lazy-cache them during run + // time as long as we aren't running clustered. + Calendar cal = (isClustered) ? null : calendarCache.get(calName); + if (cal != null) { + return cal; + } try { cal = getDelegate().selectCalendar(conn, calName); - calendarCache.put(calName, cal); // lazy-cache... + if (!isClustered) { + calendarCache.put(calName, cal); // lazy-cache... + } return cal; } catch (ClassNotFoundException e) { throw new JobPersistenceException( @@ -1255,8 +1780,24 @@ } } - protected int getNumberOfJobs(Connection conn, SchedulingContext ctxt) - throws JobPersistenceException { + /** + *

+ * Get the number of {@link org.quartz.Job} s that are + * stored in the JobStore. + *

+ */ + public int getNumberOfJobs() + throws JobPersistenceException { + return (Integer) executeWithoutLock( // no locks necessary for read... + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return getNumberOfJobs(conn); + } + }); + } + + protected int getNumberOfJobs(Connection conn) + throws JobPersistenceException { try { return getDelegate().selectNumJobs(conn); } catch (SQLException e) { @@ -1265,8 +1806,24 @@ } } - protected int getNumberOfTriggers(Connection conn, SchedulingContext ctxt) - throws JobPersistenceException { + /** + *

+ * Get the number of {@link org.quartz.Trigger} s that are + * stored in the JobsStore. + *

+ */ + public int getNumberOfTriggers() + throws JobPersistenceException { + return (Integer) executeWithoutLock( // no locks necessary for read... + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return getNumberOfTriggers(conn); + } + }); + } + + protected int getNumberOfTriggers(Connection conn) + throws JobPersistenceException { try { return getDelegate().selectNumTriggers(conn); } catch (SQLException e) { @@ -1275,8 +1832,24 @@ } } - protected int getNumberOfCalendars(Connection conn, SchedulingContext ctxt) - throws JobPersistenceException { + /** + *

+ * Get the number of {@link org.quartz.Calendar} s that are + * stored in the JobsStore. + *

+ */ + public int getNumberOfCalendars() + throws JobPersistenceException { + return (Integer) executeWithoutLock( // no locks necessary for read... + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return getNumberOfCalendars(conn); + } + }); + } + + protected int getNumberOfCalendars(Connection conn) + throws JobPersistenceException { try { return getDelegate().selectNumCalendars(conn); } catch (SQLException e) { @@ -1285,27 +1858,147 @@ } } - protected String[] getJobNames(Connection conn, SchedulingContext ctxt, - String groupName) throws JobPersistenceException { - String[] jobNames = null; + /** + *

+ * Get the names of all of the {@link org.quartz.Job} s that + * matcher the given groupMatcher. + *

+ * + *

+ * If there are no jobs in the given group name, the result should be an empty Set + *

+ */ + @SuppressWarnings("unchecked") + public Set getJobKeys(final GroupMatcher matcher) + throws JobPersistenceException { + return (Set)executeWithoutLock( // no locks necessary for read... + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return getJobNames(conn, matcher); + } + }); + } + + protected Set getJobNames(Connection conn, + GroupMatcher matcher) throws JobPersistenceException { + Set jobNames; try { - jobNames = getDelegate().selectJobsInGroup(conn, groupName); + jobNames = getDelegate().selectJobsInGroup(conn, matcher); } catch (SQLException e) { throw new JobPersistenceException("Couldn't obtain job names: " + e.getMessage(), e); } return jobNames; } + + + /** + * Determine whether a {@link Job} with the given identifier already + * exists within the scheduler. + * + * @param jobKey the identifier to check for + * @return true if a Job exists with the given identifier + * @throws JobPersistenceException + */ + public boolean checkExists(final JobKey jobKey) throws JobPersistenceException { + return (Boolean)executeWithoutLock( // no locks necessary for read... + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return checkExists(conn, jobKey); + } + }); + } + + protected boolean checkExists(Connection conn, JobKey jobKey) throws JobPersistenceException { + try { + return getDelegate().jobExists(conn, jobKey); + } catch (SQLException e) { + throw new JobPersistenceException("Couldn't check for existence of job: " + + e.getMessage(), e); + } + } + + /** + * Determine whether a {@link Trigger} with the given identifier already + * exists within the scheduler. + * + * @param triggerKey the identifier to check for + * @return true if a Trigger exists with the given identifier + * @throws JobPersistenceException + */ + public boolean checkExists(final TriggerKey triggerKey) throws JobPersistenceException { + return (Boolean)executeWithoutLock( // no locks necessary for read... + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return checkExists(conn, triggerKey); + } + }); + } + + protected boolean checkExists(Connection conn, TriggerKey triggerKey) throws JobPersistenceException { + try { + return getDelegate().triggerExists(conn, triggerKey); + } catch (SQLException e) { + throw new JobPersistenceException("Couldn't check for existence of job: " + + e.getMessage(), e); + } + } - protected String[] getTriggerNames(Connection conn, SchedulingContext ctxt, - String groupName) throws JobPersistenceException { + /** + * Clear (delete!) all scheduling data - all {@link Job}s, {@link Trigger}s + * {@link Calendar}s. + * + * @throws JobPersistenceException + */ + public void clearAllSchedulingData() throws JobPersistenceException { + executeInLock( + LOCK_TRIGGER_ACCESS, + new VoidTransactionCallback() { + public void executeVoid(Connection conn) throws JobPersistenceException { + clearAllSchedulingData(conn); + } + }); + } + + protected void clearAllSchedulingData(Connection conn) throws JobPersistenceException { + try { + getDelegate().clearData(conn); + } catch (SQLException e) { + throw new JobPersistenceException("Error clearing scheduling data: " + e.getMessage(), e); + } + } + + /** + *

+ * Get the names of all of the {@link org.quartz.Trigger} s + * that match the given group Matcher. + *

+ * + *

+ * If there are no triggers in the given group name, the result should be a + * an empty Set (not null). + *

+ */ + @SuppressWarnings("unchecked") + public Set getTriggerKeys(final GroupMatcher matcher) + throws JobPersistenceException { + return (Set)executeWithoutLock( // no locks necessary for read... + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return getTriggerNames(conn, matcher); + } + }); + } + + protected Set getTriggerNames(Connection conn, + GroupMatcher matcher) throws JobPersistenceException { - String[] trigNames = null; + Set trigNames; try { - trigNames = getDelegate().selectTriggersInGroup(conn, groupName); + trigNames = getDelegate().selectTriggersInGroup(conn, matcher); } catch (SQLException e) { throw new JobPersistenceException("Couldn't obtain trigger names: " + e.getMessage(), e); @@ -1314,11 +2007,34 @@ return trigNames; } - protected String[] getJobGroupNames(Connection conn, SchedulingContext ctxt) - throws JobPersistenceException { - String[] groupNames = null; + /** + *

+ * Get the names of all of the {@link org.quartz.Job} + * groups. + *

+ * + *

+ * If there are no known group names, the result should be a zero-length + * array (not null). + *

+ */ + @SuppressWarnings("unchecked") + public List getJobGroupNames() + throws JobPersistenceException { + return (List)executeWithoutLock( // no locks necessary for read... + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return getJobGroupNames(conn); + } + }); + } + + protected List getJobGroupNames(Connection conn) + throws JobPersistenceException { + List groupNames; + try { groupNames = getDelegate().selectJobGroups(conn); } catch (SQLException e) { @@ -1329,10 +2045,31 @@ return groupNames; } - protected String[] getTriggerGroupNames(Connection conn, - SchedulingContext ctxt) throws JobPersistenceException { + /** + *

+ * Get the names of all of the {@link org.quartz.Trigger} + * groups. + *

+ * + *

+ * If there are no known group names, the result should be a zero-length + * array (not null). + *

+ */ + @SuppressWarnings("unchecked") + public List getTriggerGroupNames() + throws JobPersistenceException { + return (List)executeWithoutLock( // no locks necessary for read... + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return getTriggerGroupNames(conn); + } + }); + } + + protected List getTriggerGroupNames(Connection conn) throws JobPersistenceException { - String[] groupNames = null; + List groupNames; try { groupNames = getDelegate().selectTriggerGroups(conn); @@ -1344,8 +2081,30 @@ return groupNames; } - protected String[] getCalendarNames(Connection conn, SchedulingContext ctxt) - throws JobPersistenceException { + /** + *

+ * Get the names of all of the {@link org.quartz.Calendar} s + * in the JobStore. + *

+ * + *

+ * If there are no Calendars in the given group name, the result should be + * a zero-length array (not null). + *

+ */ + @SuppressWarnings("unchecked") + public List getCalendarNames() + throws JobPersistenceException { + return (List)executeWithoutLock( // no locks necessary for read... + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return getCalendarNames(conn); + } + }); + } + + protected List getCalendarNames(Connection conn) + throws JobPersistenceException { try { return getDelegate().selectCalendars(conn); } catch (SQLException e) { @@ -1354,141 +2113,202 @@ } } - protected Trigger[] getTriggersForJob(Connection conn, - SchedulingContext ctxt, String jobName, String groupName) - throws JobPersistenceException { - Trigger[] array = null; + /** + *

+ * Get all of the Triggers that are associated to the given Job. + *

+ * + *

+ * If there are no matches, a zero-length array should be returned. + *

+ */ + @SuppressWarnings("unchecked") + public List getTriggersForJob(final JobKey jobKey) throws JobPersistenceException { + return (List)executeWithoutLock( // no locks necessary for read... + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return getTriggersForJob(conn, jobKey); + } + }); + } + + protected List getTriggersForJob(Connection conn, + JobKey key) + throws JobPersistenceException { + List list; try { - array = getDelegate() - .selectTriggersForJob(conn, jobName, groupName); + list = getDelegate() + .selectTriggersForJob(conn, key); } catch (Exception e) { throw new JobPersistenceException( "Couldn't obtain triggers for job: " + e.getMessage(), e); } - return array; + return list; } /** *

* Pause the {@link org.quartz.Trigger} with the given name. *

* - * @see #resumeTrigger(Connection, SchedulingContext, String, String) + * @see #resumeTrigger(TriggerKey) */ - public void pauseTrigger(Connection conn, SchedulingContext ctxt, - String triggerName, String groupName) - throws JobPersistenceException { + public void pauseTrigger(final TriggerKey triggerKey) throws JobPersistenceException { + executeInLock( + LOCK_TRIGGER_ACCESS, + new VoidTransactionCallback() { + public void executeVoid(Connection conn) throws JobPersistenceException { + pauseTrigger(conn, triggerKey); + } + }); + } + + /** + *

+ * Pause the {@link org.quartz.Trigger} with the given name. + *

+ * + * @see #resumeTrigger(Connection, TriggerKey) + */ + public void pauseTrigger(Connection conn, + TriggerKey triggerKey) + throws JobPersistenceException { try { String oldState = getDelegate().selectTriggerState(conn, - triggerName, groupName); + triggerKey); if (oldState.equals(STATE_WAITING) || oldState.equals(STATE_ACQUIRED)) { - getDelegate().updateTriggerState(conn, triggerName, - groupName, STATE_PAUSED); + getDelegate().updateTriggerState(conn, triggerKey, + STATE_PAUSED); + } else if (oldState.equals(STATE_BLOCKED)) { + getDelegate().updateTriggerState(conn, triggerKey, + STATE_PAUSED_BLOCKED); } - else if (oldState.equals(STATE_BLOCKED)) { - getDelegate().updateTriggerState(conn, triggerName, - groupName, STATE_PAUSED_BLOCKED); - } } catch (SQLException e) { throw new JobPersistenceException("Couldn't pause trigger '" - + groupName + "." + triggerName + "': " + e.getMessage(), e); + + triggerKey + "': " + e.getMessage(), e); } } - protected String getStatusForResumedTrigger(Connection conn, - SchedulingContext ctxt, TriggerStatus status) - throws JobPersistenceException { + /** + *

+ * Pause the {@link org.quartz.Job} with the given name - by + * pausing all of its current Triggers. + *

+ * + * @see #resumeJob(JobKey) + */ + public void pauseJob(final JobKey jobKey) throws JobPersistenceException { + executeInLock( + LOCK_TRIGGER_ACCESS, + new VoidTransactionCallback() { + public void executeVoid(Connection conn) throws JobPersistenceException { + List triggers = getTriggersForJob(conn, jobKey); + for (OperableTrigger trigger: triggers) { + pauseTrigger(conn, trigger.getKey()); + } + } + }); + } + + /** + *

+ * Pause all of the {@link org.quartz.Job}s matching the given + * groupMatcher - by pausing all of their Triggers. + *

+ * + * @see #resumeJobs(org.quartz.impl.matchers.GroupMatcher) + */ + @SuppressWarnings("unchecked") + public Set pauseJobs(final GroupMatcher matcher) + throws JobPersistenceException { + return (Set) executeInLock( + LOCK_TRIGGER_ACCESS, + new TransactionCallback() { + public Set execute(final Connection conn) throws JobPersistenceException { + Set groupNames = new HashSet(); + Set jobNames = getJobNames(conn, matcher); - try { - String newState = STATE_WAITING; + for (JobKey jobKey : jobNames) { + List triggers = getTriggersForJob(conn, jobKey); + for (OperableTrigger trigger : triggers) { + pauseTrigger(conn, trigger.getKey()); + } + groupNames.add(jobKey.getGroup()); + } - List lst = getDelegate() - .selectFiredTriggerRecordsByJob(conn, - status.getJobKey().getName(), - status.getJobKey().getGroup()); - - if (lst.size() > 0) { - FiredTriggerRecord rec = (FiredTriggerRecord) lst.get(0); - if (rec.isJobIsStateful()) // TODO: worry about - // failed/recovering/volatile job - // states? - newState = STATE_BLOCKED; + return groupNames; + } } - - return newState; - - } catch (SQLException e) { - throw new JobPersistenceException( - "Couldn't determine new state in order to resume trigger '" - + status.getKey().getGroup() + "." - + status.getKey().getName() + "': " - + e.getMessage(), e); - } - + ); } + + /** + * Determines if a Trigger for the given job should be blocked. + * State can only transition to STATE_PAUSED_BLOCKED/BLOCKED from + * PAUSED/STATE_WAITING respectively. + * + * @return STATE_PAUSED_BLOCKED, BLOCKED, or the currentState. + */ + protected String checkBlockedState( + Connection conn, JobKey jobKey, String currentState) + throws JobPersistenceException { - protected String getNewStatusForTrigger(Connection conn, - SchedulingContext ctxt, String jobName, String groupName) - throws JobPersistenceException { - + // State can only transition to BLOCKED from PAUSED or WAITING. + if ((!currentState.equals(STATE_WAITING)) && + (!currentState.equals(STATE_PAUSED))) { + return currentState; + } + try { - String newState = STATE_WAITING; + List lst = getDelegate().selectFiredTriggerRecordsByJob(conn, + jobKey.getName(), jobKey.getGroup()); - List lst = getDelegate().selectFiredTriggerRecordsByJob(conn, - jobName, groupName); - if (lst.size() > 0) { - FiredTriggerRecord rec = (FiredTriggerRecord) lst.get(0); - if (rec.isJobIsStateful()) // TODO: worry about - // failed/recovering/volatile job - // states? - newState = STATE_BLOCKED; + FiredTriggerRecord rec = lst.get(0); + if (rec.isJobDisallowsConcurrentExecution()) { // OLD_TODO: worry about failed/recovering/volatile job states? + return (STATE_PAUSED.equals(currentState)) ? STATE_PAUSED_BLOCKED : STATE_BLOCKED; + } } - return newState; - + return currentState; } catch (SQLException e) { throw new JobPersistenceException( - "Couldn't determine state for new trigger: " - + e.getMessage(), e); + "Couldn't determine if trigger should be in a blocked state '" + + jobKey + "': " + + e.getMessage(), e); } } - /* - * private List findTriggersToBeBlocked(Connection conn, SchedulingContext - * ctxt, String groupName) throws JobPersistenceException { + /** + *

+ * Resume (un-pause) the {@link org.quartz.Trigger} with the + * given name. + *

* - * try { List blockList = new LinkedList(); + *

+ * If the Trigger missed one or more fire-times, then the + * Trigger's misfire instruction will be applied. + *

* - * List affectingJobs = - * getDelegate().selectStatefulJobsOfTriggerGroup(conn, groupName); - * - * Iterator itr = affectingJobs.iterator(); while(itr.hasNext()) { Key - * jobKey = (Key) itr.next(); - * - * List lst = getDelegate().selectFiredTriggerRecordsByJob(conn, - * jobKey.getName(), jobKey.getGroup()); - * - * This logic is BROKEN... - * - * if(lst.size() > 0) { FiredTriggerRecord rec = - * (FiredTriggerRecord)lst.get(0); if(rec.isJobIsStateful()) // TODO: worry - * about failed/recovering/volatile job states? blockList.add( - * rec.getTriggerKey() ); } } - * - * - * return blockList; } catch (SQLException e) { throw new - * JobPersistenceException ("Couldn't determine states of resumed triggers - * in group '" + groupName + "': " + e.getMessage(), e); } } + * @see #pauseTrigger(TriggerKey) */ - + public void resumeTrigger(final TriggerKey triggerKey) throws JobPersistenceException { + executeInLock( + LOCK_TRIGGER_ACCESS, + new VoidTransactionCallback() { + public void executeVoid(Connection conn) throws JobPersistenceException { + resumeTrigger(conn, triggerKey); + } + }); + } + /** *

* Resume (un-pause) the {@link org.quartz.Trigger} with the @@ -1500,85 +2320,195 @@ * Trigger's misfire instruction will be applied. *

* - * @see #pauseTrigger(Connection, SchedulingContext, String, String) + * @see #pauseTrigger(Connection, TriggerKey) */ - public void resumeTrigger(Connection conn, SchedulingContext ctxt, - String triggerName, String groupName) - throws JobPersistenceException { + public void resumeTrigger(Connection conn, + TriggerKey key) + throws JobPersistenceException { try { TriggerStatus status = getDelegate().selectTriggerStatus(conn, - triggerName, groupName); + key); - if (status == null || status.getNextFireTime() == null) return; + if (status == null || status.getNextFireTime() == null) { + return; + } boolean blocked = false; - if(STATE_PAUSED_BLOCKED.equals(status.getStatus())) + if(STATE_PAUSED_BLOCKED.equals(status.getStatus())) { blocked = true; + } - String newState = getStatusForResumedTrigger(conn, ctxt, status); + String newState = checkBlockedState(conn, status.getJobKey(), STATE_WAITING); boolean misfired = false; - if (status.getNextFireTime().before(new Date())) { - misfired = updateMisfiredTrigger(conn, ctxt, triggerName, groupName, - newState, true); + if (schedulerRunning && status.getNextFireTime().before(new Date())) { + misfired = updateMisfiredTrigger(conn, key, + newState, true); } if(!misfired) { - if(blocked) + if(blocked) { getDelegate().updateTriggerStateFromOtherState(conn, - triggerName, groupName, newState, STATE_PAUSED_BLOCKED); - else + key, newState, STATE_PAUSED_BLOCKED); + } else { getDelegate().updateTriggerStateFromOtherState(conn, - triggerName, groupName, newState, STATE_PAUSED); + key, newState, STATE_PAUSED); + } } } catch (SQLException e) { throw new JobPersistenceException("Couldn't resume trigger '" - + groupName + "." + triggerName + "': " + e.getMessage(), e); + + key + "': " + e.getMessage(), e); } } /** *

- * Pause all of the {@link org.quartz.Trigger}s in the - * given group. + * Resume (un-pause) the {@link org.quartz.Job} with the + * given name. *

* - * @see #resumeTriggerGroup(Connection, SchedulingContext, String) + *

+ * If any of the Job'sTrigger s missed one + * or more fire-times, then the Trigger's misfire + * instruction will be applied. + *

+ * + * @see #pauseJob(JobKey) */ - public void pauseTriggerGroup(Connection conn, SchedulingContext ctxt, - String groupName) throws JobPersistenceException { + public void resumeJob(final JobKey jobKey) throws JobPersistenceException { + executeInLock( + LOCK_TRIGGER_ACCESS, + new VoidTransactionCallback() { + public void executeVoid(Connection conn) throws JobPersistenceException { + List triggers = getTriggersForJob(conn, jobKey); + for (OperableTrigger trigger: triggers) { + resumeTrigger(conn, trigger.getKey()); + } + } + }); + } + + /** + *

+ * Resume (un-pause) all of the {@link org.quartz.Job}s in + * the given group. + *

+ * + *

+ * If any of the Job s had Trigger s that + * missed one or more fire-times, then the Trigger's + * misfire instruction will be applied. + *

+ * + * @see #pauseJobs(org.quartz.impl.matchers.GroupMatcher) + */ + @SuppressWarnings("unchecked") + public Set resumeJobs(final GroupMatcher matcher) + throws JobPersistenceException { + return (Set) executeInLock( + LOCK_TRIGGER_ACCESS, + new TransactionCallback() { + public Set execute(Connection conn) throws JobPersistenceException { + Set jobKeys = getJobNames(conn, matcher); + Set groupNames = new HashSet(); + for (JobKey jobKey: jobKeys) { + List triggers = getTriggersForJob(conn, jobKey); + for (OperableTrigger trigger: triggers) { + resumeTrigger(conn, trigger.getKey()); + } + groupNames.add(jobKey.getGroup()); + } + return groupNames; + } + }); + } + + /** + *

+ * Pause all of the {@link org.quartz.Trigger}s matching the + * given groupMatcher. + *

+ * + * @see #resumeTriggerGroup(java.sql.Connection, org.quartz.impl.matchers.GroupMatcher) + */ + @SuppressWarnings("unchecked") + public Set pauseTriggers(final GroupMatcher matcher) + throws JobPersistenceException { + return (Set) executeInLock( + LOCK_TRIGGER_ACCESS, + new TransactionCallback() { + public Set execute(Connection conn) throws JobPersistenceException { + return pauseTriggerGroup(conn, matcher); + } + }); + } + + /** + *

+ * Pause all of the {@link org.quartz.Trigger}s matching the + * given groupMatcher. + *

+ * + * @see #resumeTriggerGroup(java.sql.Connection, org.quartz.impl.matchers.GroupMatcher) + */ + public Set pauseTriggerGroup(Connection conn, + GroupMatcher matcher) throws JobPersistenceException { + try { getDelegate().updateTriggerGroupStateFromOtherStates( - conn, groupName, STATE_PAUSED, STATE_ACQUIRED, + conn, matcher, STATE_PAUSED, STATE_ACQUIRED, STATE_WAITING, STATE_WAITING); getDelegate().updateTriggerGroupStateFromOtherState( - conn, groupName, STATE_PAUSED_BLOCKED, STATE_BLOCKED); + conn, matcher, STATE_PAUSED_BLOCKED, STATE_BLOCKED); + + List groups = getDelegate().selectTriggerGroups(conn, matcher); - if (!getDelegate().isTriggerGroupPaused(conn, groupName)) { - getDelegate().insertPausedTriggerGroup(conn, groupName); + // make sure to account for an exact group match for a group that doesn't yet exist + StringMatcher.StringOperatorName operator = matcher.getCompareWithOperator(); + if (operator.equals(StringOperatorName.EQUALS) && !groups.contains(matcher.getCompareToValue())) { + groups.add(matcher.getCompareToValue()); } + for (String group : groups) { + if (!getDelegate().isTriggerGroupPaused(conn, group)) { + getDelegate().insertPausedTriggerGroup(conn, group); + } + } + + return new HashSet(groups); + } catch (SQLException e) { throw new JobPersistenceException("Couldn't pause trigger group '" - + groupName + "': " + e.getMessage(), e); + + matcher + "': " + e.getMessage(), e); } } + @SuppressWarnings("unchecked") + public Set getPausedTriggerGroups() + throws JobPersistenceException { + return (Set)executeWithoutLock( // no locks necessary for read... + new TransactionCallback() { + public Object execute(Connection conn) throws JobPersistenceException { + return getPausedTriggerGroups(conn); + } + }); + } + /** *

* Pause all of the {@link org.quartz.Trigger}s in the * given group. *

* - * @see #resumeTriggerGroup(Connection, SchedulingContext, String) + * @see #resumeTriggers(org.quartz.impl.matchers.GroupMatcher) */ - public Set getPausedTriggerGroups(Connection conn, SchedulingContext ctxt) + public Set getPausedTriggerGroups(Connection conn) throws JobPersistenceException { try { @@ -1592,37 +2522,67 @@ /** *

* Resume (un-pause) all of the {@link org.quartz.Trigger}s - * in the given group. + * matching the given groupMatcher. *

* *

* If any Trigger missed one or more fire-times, then the * Trigger's misfire instruction will be applied. *

* - * @see #pauseTriggerGroup(Connection, SchedulingContext, String) + * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher) */ - public void resumeTriggerGroup(Connection conn, SchedulingContext ctxt, - String groupName) throws JobPersistenceException { + @SuppressWarnings("unchecked") + public Set resumeTriggers(final GroupMatcher matcher) + throws JobPersistenceException { + return (Set) executeInLock( + LOCK_TRIGGER_ACCESS, + new TransactionCallback() { + public Set execute(Connection conn) throws JobPersistenceException { + return resumeTriggerGroup(conn, matcher); + } + }); + } + + /** + *

+ * Resume (un-pause) all of the {@link org.quartz.Trigger}s + * matching the given groupMatcher. + *

+ * + *

+ * If any Trigger missed one or more fire-times, then the + * Trigger's misfire instruction will be applied. + *

+ * + * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher) + */ + public Set resumeTriggerGroup(Connection conn, + GroupMatcher matcher) throws JobPersistenceException { + try { - getDelegate().deletePausedTriggerGroup(conn, groupName); + getDelegate().deletePausedTriggerGroup(conn, matcher); + HashSet groups = new HashSet(); - String[] trigNames = getDelegate().selectTriggersInGroup(conn, - groupName); + Set keys = getDelegate().selectTriggersInGroup(conn, + matcher); - for (int i = 0; i < trigNames.length; i++) { - resumeTrigger(conn, ctxt, trigNames[i], groupName); + for (TriggerKey key: keys) { + resumeTrigger(conn, key); + groups.add(key.getGroup()); } - // TODO: find an efficient way to resume triggers (better than the + return groups; + + // FUTURE_TODO: find an efficient way to resume triggers (better than the // above)... logic below is broken because of // findTriggersToBeBlocked() /* * int res = * getDelegate().updateTriggerGroupStateFromOtherState(conn, - * groupName, STATE_WAITING, STATE_PAUSED); + * groupName, STATE_WAITING, PAUSED); * * if(res > 0) { * @@ -1634,24 +2594,24 @@ * getDelegate().selectMisfiredTriggersInGroupInState(conn, * groupName, STATE_WAITING, misfireTime); * - * List blockedTriggers = findTriggersToBeBlocked(conn, ctxt, + * List blockedTriggers = findTriggersToBeBlocked(conn, * groupName); * * Iterator itr = blockedTriggers.iterator(); while(itr.hasNext()) { * Key key = (Key)itr.next(); * getDelegate().updateTriggerState(conn, key.getName(), - * key.getGroup(), STATE_BLOCKED); } + * key.getGroup(), BLOCKED); } * * for(int i=0; i < misfires.length; i++) { String * newState = STATE_WAITING; * if(blockedTriggers.contains(misfires[i])) newState = - * STATE_BLOCKED; updateMisfiredTrigger(conn, ctxt, + * BLOCKED; updateMisfiredTrigger(conn, * misfires[i].getName(), misfires[i].getGroup(), newState, true); } } */ } catch (SQLException e) { throw new JobPersistenceException("Couldn't pause trigger group '" - + groupName + "': " + e.getMessage(), e); + + matcher + "': " + e.getMessage(), e); } } @@ -1666,16 +2626,40 @@ * instructions WILL be applied. *

* - * @see #resumeAll(SchedulingContext) - * @see #pauseTriggerGroup(SchedulingContext, String) + * @see #resumeAll() + * @see #pauseTriggerGroup(java.sql.Connection, org.quartz.impl.matchers.GroupMatcher) */ - public void pauseAll(Connection conn, SchedulingContext ctxt) - throws JobPersistenceException { + public void pauseAll() throws JobPersistenceException { + executeInLock( + LOCK_TRIGGER_ACCESS, + new VoidTransactionCallback() { + public void executeVoid(Connection conn) throws JobPersistenceException { + pauseAll(conn); + } + }); + } + + /** + *

+ * Pause all triggers - equivalent of calling pauseTriggerGroup(group) + * on every group. + *

+ * + *

+ * When resumeAll() is called (to un-pause), trigger misfire + * instructions WILL be applied. + *

+ * + * @see #resumeAll(Connection) + * @see #pauseTriggerGroup(java.sql.Connection, org.quartz.impl.matchers.GroupMatcher) + */ + public void pauseAll(Connection conn) + throws JobPersistenceException { - String[] names = getTriggerGroupNames(conn, ctxt); + List names = getTriggerGroupNames(conn); - for (int i = 0; i < names.length; i++) { - pauseTriggerGroup(conn, ctxt, names[i]); + for (String name: names) { + pauseTriggerGroup(conn, GroupMatcher.triggerGroupEquals(name)); } try { @@ -1691,6 +2675,30 @@ } /** + *

+ * Resume (un-pause) all triggers - equivalent of calling resumeTriggerGroup(group) + * on every group. + *

+ * + *

+ * If any Trigger missed one or more fire-times, then the + * Trigger's misfire instruction will be applied. + *

+ * + * @see #pauseAll() + */ + public void resumeAll() + throws JobPersistenceException { + executeInLock( + LOCK_TRIGGER_ACCESS, + new VoidTransactionCallback() { + public void executeVoid(Connection conn) throws JobPersistenceException { + resumeAll(conn); + } + }); + } + + /** * protected *

* Resume (un-pause) all triggers - equivalent of calling resumeTriggerGroup(group) @@ -1702,15 +2710,15 @@ * Trigger's misfire instruction will be applied. *

* - * @see #pauseAll(SchedulingContext) + * @see #pauseAll(Connection) */ - public void resumeAll(Connection conn, SchedulingContext ctxt) - throws JobPersistenceException { + public void resumeAll(Connection conn) + throws JobPersistenceException { - String[] names = getTriggerGroupNames(conn, ctxt); + List names = getTriggerGroupNames(conn); - for (int i = 0; i < names.length; i++) { - resumeTriggerGroup(conn, ctxt, names[i]); + for (String name: names) { + resumeTriggerGroup(conn, GroupMatcher.triggerGroupEquals(name)); } try { @@ -1719,7 +2727,6 @@ throw new JobPersistenceException( "Couldn't resume all trigger groups: " + e.getMessage(), e); } - } private static long ftrCtr = System.currentTimeMillis(); @@ -1728,116 +2735,252 @@ return getInstanceId() + ftrCtr++; } - // TODO: this really ought to return something like a FiredTriggerBundle, + /** + *

+ * Get a handle to the next N triggers to be fired, and mark them as 'reserved' + * by the calling scheduler. + *

+ * + * @see #releaseAcquiredTrigger(OperableTrigger) + */ + @SuppressWarnings("unchecked") + public List acquireNextTriggers(final long noLaterThan, final int maxCount, final long timeWindow) + throws JobPersistenceException { + + String lockName; + if(isAcquireTriggersWithinLock() || maxCount > 1) { + lockName = LOCK_TRIGGER_ACCESS; + } else { + lockName = null; + } + return executeInNonManagedTXLock(lockName, + new TransactionCallback>() { + public List execute(Connection conn) throws JobPersistenceException { + return acquireNextTrigger(conn, noLaterThan, maxCount, timeWindow); + } + }, + new TransactionValidator>() { + public Boolean validate(Connection conn, List result) throws JobPersistenceException { + try { + List acquired = getDelegate().selectInstancesFiredTriggerRecords(conn, getInstanceId()); + Set fireInstanceIds = new HashSet(); + for (FiredTriggerRecord ft : acquired) { + fireInstanceIds.add(ft.getFireInstanceId()); + } + for (OperableTrigger tr : result) { + if (fireInstanceIds.contains(tr.getFireInstanceId())) { + return true; + } + } + return false; + } catch (SQLException e) { + throw new JobPersistenceException("error validating trigger acquisition", e); + } + } + }); + } + + // FUTURE_TODO: this really ought to return something like a FiredTriggerBundle, // so that the fireInstanceId doesn't have to be on the trigger... - protected Trigger acquireNextTrigger(Connection conn, SchedulingContext ctxt, long noLaterThan) - throws JobPersistenceException { - Trigger nextTrigger = null; - - boolean acquiredOne = false; - + protected List acquireNextTrigger(Connection conn, long noLaterThan, int maxCount, long timeWindow) + throws JobPersistenceException { + if (timeWindow < 0) { + throw new IllegalArgumentException(); + } + + List acquiredTriggers = new ArrayList(); + Set acquiredJobKeysForNoConcurrentExec = new HashSet(); + final int MAX_DO_LOOP_RETRY = 3; + int currentLoopCount = 0; + long firstAcquiredTriggerFireTime = 0; + do { + currentLoopCount ++; try { - getDelegate().updateTriggerStateFromOtherStatesBeforeTime(conn, - STATE_MISFIRED, STATE_WAITING, STATE_WAITING, - getMisfireTime()); // only waiting + List keys = getDelegate().selectTriggerToAcquire(conn, noLaterThan + timeWindow, getMisfireTime(), maxCount); + + // No trigger is ready to fire yet. + if (keys == null || keys.size() == 0) + return acquiredTriggers; + + for(TriggerKey triggerKey: keys) { + // If our trigger is no longer available, try a new one. + OperableTrigger nextTrigger = retrieveTrigger(conn, triggerKey); + if(nextTrigger == null) { + continue; // next trigger + } + + // If trigger's job is set as @DisallowConcurrentExecution, and it has already been added to result, then + // put it back into the timeTriggers set and continue to search for next trigger. + JobKey jobKey = nextTrigger.getJobKey(); + JobDetail job = getDelegate().selectJobDetail(conn, jobKey, getClassLoadHelper()); + if (job.isConcurrentExectionDisallowed()) { + if (acquiredJobKeysForNoConcurrentExec.contains(jobKey)) { + continue; // next trigger + } else { + acquiredJobKeysForNoConcurrentExec.add(jobKey); + } + } + + // We now have a acquired trigger, let's add to return list. + // If our trigger was no longer in the expected state, try a new one. + int rowsUpdated = getDelegate().updateTriggerStateFromOtherState(conn, triggerKey, STATE_ACQUIRED, STATE_WAITING); + if (rowsUpdated <= 0) { + continue; // next trigger + } + nextTrigger.setFireInstanceId(getFiredTriggerRecordId()); + getDelegate().insertFiredTrigger(conn, nextTrigger, STATE_ACQUIRED, null); - long nextFireTime = getDelegate().selectNextFireTime(conn); + acquiredTriggers.add(nextTrigger); + if(firstAcquiredTriggerFireTime == 0) + firstAcquiredTriggerFireTime = nextTrigger.getNextFireTime().getTime(); + } - if (nextFireTime == 0 || nextFireTime > noLaterThan) - return null; - - Key triggerKey = null; - do { - triggerKey = getDelegate().selectTriggerForFireTime(conn, - nextFireTime); - if (null != triggerKey) { - - int res = getDelegate() - .updateTriggerStateFromOtherState(conn, - triggerKey.getName(), - triggerKey.getGroup(), STATE_ACQUIRED, - STATE_WAITING); - - if (res <= 0) continue; - - nextTrigger = retrieveTrigger(conn, ctxt, triggerKey - .getName(), triggerKey.getGroup()); - - if(nextTrigger == null) continue; - - nextTrigger - .setFireInstanceId(getFiredTriggerRecordId()); - getDelegate().insertFiredTrigger(conn, nextTrigger, - STATE_ACQUIRED, null); - - acquiredOne = true; - } - } while (triggerKey != null && !acquiredOne); + // if we didn't end up with any trigger to fire from that first + // batch, try again for another batch. We allow with a max retry count. + if(acquiredTriggers.size() == 0 && currentLoopCount < MAX_DO_LOOP_RETRY) { + continue; + } + + // We are done with the while loop. + break; } catch (Exception e) { throw new JobPersistenceException( - "Couldn't acquire next trigger: " + e.getMessage(), e); + "Couldn't acquire next trigger: " + e.getMessage(), e); } - - } while (!acquiredOne); - - return nextTrigger; + } while (true); + + // Return the acquired trigger list + return acquiredTriggers; } - + + /** + *

+ * Inform the JobStore that the scheduler no longer plans to + * fire the given Trigger, that it had previously acquired + * (reserved). + *

+ */ + public void releaseAcquiredTrigger(final OperableTrigger trigger) { + retryExecuteInNonManagedTXLock( + LOCK_TRIGGER_ACCESS, + new VoidTransactionCallback() { + public void executeVoid(Connection conn) throws JobPersistenceException { + releaseAcquiredTrigger(conn, trigger); + } + }); + } + protected void releaseAcquiredTrigger(Connection conn, - SchedulingContext ctxt, Trigger trigger) - throws JobPersistenceException { + OperableTrigger trigger) + throws JobPersistenceException { try { getDelegate().updateTriggerStateFromOtherState(conn, - trigger.getName(), trigger.getGroup(), STATE_WAITING, - STATE_ACQUIRED); + trigger.getKey(), STATE_WAITING, STATE_ACQUIRED); getDelegate().deleteFiredTrigger(conn, trigger.getFireInstanceId()); } catch (SQLException e) { throw new JobPersistenceException( "Couldn't release acquired trigger: " + e.getMessage(), e); } } + /** + *

+ * Inform the JobStore that the scheduler is now firing the + * given Trigger (executing its associated Job), + * that it had previously acquired (reserved). + *

+ * + * @return null if the trigger or its job or calendar no longer exist, or + * if the trigger was not successfully put into the 'executing' + * state. + */ + @SuppressWarnings("unchecked") + public List triggersFired(final List triggers) throws JobPersistenceException { + return executeInNonManagedTXLock(LOCK_TRIGGER_ACCESS, + new TransactionCallback>() { + public List execute(Connection conn) throws JobPersistenceException { + List results = new ArrayList(); + + TriggerFiredResult result; + for (OperableTrigger trigger : triggers) { + try { + TriggerFiredBundle bundle = triggerFired(conn, trigger); + result = new TriggerFiredResult(bundle); + } catch (JobPersistenceException jpe) { + result = new TriggerFiredResult(jpe); + } catch(RuntimeException re) { + result = new TriggerFiredResult(re); + } + results.add(result); + } + + return results; + } + }, + new TransactionValidator>() { + @Override + public Boolean validate(Connection conn, List result) throws JobPersistenceException { + try { + List acquired = getDelegate().selectInstancesFiredTriggerRecords(conn, getInstanceId()); + Set executingTriggers = new HashSet(); + for (FiredTriggerRecord ft : acquired) { + if (STATE_EXECUTING.equals(ft.getFireInstanceState())) { + executingTriggers.add(ft.getFireInstanceId()); + } + } + for (TriggerFiredResult tr : result) { + if (tr.getTriggerFiredBundle() != null && executingTriggers.contains(tr.getTriggerFiredBundle().getTrigger().getFireInstanceId())) { + return true; + } + } + return false; + } catch (SQLException e) { + throw new JobPersistenceException("error validating trigger acquisition", e); + } + } + }); + } + protected TriggerFiredBundle triggerFired(Connection conn, - SchedulingContext ctxt, Trigger trigger) - throws JobPersistenceException { - JobDetail job = null; + OperableTrigger trigger) + throws JobPersistenceException { + JobDetail job; Calendar cal = null; // Make sure trigger wasn't deleted, paused, or completed... try { // if trigger was deleted, state will be STATE_DELETED String state = getDelegate().selectTriggerState(conn, - trigger.getName(), trigger.getGroup()); - if (!state.equals(STATE_ACQUIRED)) return null; + trigger.getKey()); + if (!state.equals(STATE_ACQUIRED)) { + return null; + } } catch (SQLException e) { throw new JobPersistenceException("Couldn't select trigger state: " + e.getMessage(), e); } try { - job = retrieveJob(conn, ctxt, trigger.getJobName(), trigger - .getJobGroup()); + job = retrieveJob(conn, trigger.getJobKey()); if (job == null) { return null; } } catch (JobPersistenceException jpe) { try { getLog().error("Error retrieving job, setting trigger state to ERROR.", jpe); - getDelegate().updateTriggerState(conn, trigger.getName(), - trigger.getGroup(), STATE_ERROR); + getDelegate().updateTriggerState(conn, trigger.getKey(), + STATE_ERROR); } catch (SQLException sqle) { getLog().error("Unable to set trigger state to ERROR.", sqle); } throw jpe; } if (trigger.getCalendarName() != null) { - cal = retrieveCalendar(conn, ctxt, trigger.getCalendarName()); + cal = retrieveCalendar(conn, trigger.getCalendarName()); if (cal == null) { return null; } } try { - getDelegate().deleteFiredTrigger(conn, trigger.getFireInstanceId()); - getDelegate().insertFiredTrigger(conn, trigger, STATE_EXECUTING, - job); + getDelegate().updateFiredTrigger(conn, trigger, STATE_EXECUTING, job); } catch (SQLException e) { throw new JobPersistenceException("Couldn't insert fired trigger: " + e.getMessage(), e); @@ -1851,16 +2994,16 @@ String state = STATE_WAITING; boolean force = true; - if (job.isStateful()) { + if (job.isConcurrentExectionDisallowed()) { state = STATE_BLOCKED; force = false; try { - getDelegate().updateTriggerStatesForJobFromOtherState(conn, job.getName(), - job.getGroup(), STATE_BLOCKED, STATE_WAITING); - getDelegate().updateTriggerStatesForJobFromOtherState(conn, job.getName(), - job.getGroup(), STATE_BLOCKED, STATE_ACQUIRED); - getDelegate().updateTriggerStatesForJobFromOtherState(conn, job.getName(), - job.getGroup(), STATE_PAUSED_BLOCKED, STATE_PAUSED); + getDelegate().updateTriggerStatesForJobFromOtherState(conn, job.getKey(), + STATE_BLOCKED, STATE_WAITING); + getDelegate().updateTriggerStatesForJobFromOtherState(conn, job.getKey(), + STATE_BLOCKED, STATE_ACQUIRED); + getDelegate().updateTriggerStatesForJobFromOtherState(conn, job.getKey(), + STATE_PAUSED_BLOCKED, STATE_PAUSED); } catch (SQLException e) { throw new JobPersistenceException( "Couldn't update states of blocked triggers: " @@ -1869,67 +3012,92 @@ } if (trigger.getNextFireTime() == null) { - state = STATE_COMPLETE; - force = true; + state = STATE_COMPLETE; + force = true; } - storeTrigger(conn, ctxt, trigger, job, true, state, force, false); + storeTrigger(conn, trigger, job, true, state, force, false); job.getJobDataMap().clearDirtyFlag(); - return new TriggerFiredBundle(job, trigger, cal, trigger.getGroup() + return new TriggerFiredBundle(job, trigger, cal, trigger.getKey().getGroup() .equals(Scheduler.DEFAULT_RECOVERY_GROUP), new Date(), trigger .getPreviousFireTime(), prevFireTime, trigger.getNextFireTime()); } + /** + *

+ * Inform the JobStore that the scheduler has completed the + * firing of the given Trigger (and the execution its + * associated Job), and that the {@link org.quartz.JobDataMap} + * in the given JobDetail should be updated if the Job + * is stateful. + *

+ */ + public void triggeredJobComplete(final OperableTrigger trigger, + final JobDetail jobDetail, final CompletedExecutionInstruction triggerInstCode) { + retryExecuteInNonManagedTXLock( + LOCK_TRIGGER_ACCESS, + new VoidTransactionCallback() { + public void executeVoid(Connection conn) throws JobPersistenceException { + triggeredJobComplete(conn, trigger, jobDetail,triggerInstCode); + } + }); + } + protected void triggeredJobComplete(Connection conn, - SchedulingContext ctxt, Trigger trigger, JobDetail jobDetail, - int triggerInstCode) throws JobPersistenceException { + OperableTrigger trigger, JobDetail jobDetail, + CompletedExecutionInstruction triggerInstCode) throws JobPersistenceException { try { - if (triggerInstCode == Trigger.INSTRUCTION_DELETE_TRIGGER) { + if (triggerInstCode == CompletedExecutionInstruction.DELETE_TRIGGER) { if(trigger.getNextFireTime() == null) { // double check for possible reschedule within job // execution, which would cancel the need to delete... TriggerStatus stat = getDelegate().selectTriggerStatus( - conn, trigger.getName(), trigger.getGroup()); + conn, trigger.getKey()); if(stat != null && stat.getNextFireTime() == null) { - removeTrigger(conn, ctxt, trigger.getName(), trigger.getGroup()); + removeTrigger(conn, trigger.getKey()); } + } else{ + removeTrigger(conn, trigger.getKey()); + signalSchedulingChangeOnTxCompletion(0L); } - else{ - removeTrigger(conn, ctxt, trigger.getName(), trigger.getGroup()); - } - } else if (triggerInstCode == Trigger.INSTRUCTION_SET_TRIGGER_COMPLETE) { - getDelegate().updateTriggerState(conn, trigger.getName(), - trigger.getGroup(), STATE_COMPLETE); - } else if (triggerInstCode == Trigger.INSTRUCTION_SET_TRIGGER_ERROR) { - getLog().info("Trigger " + trigger.getFullName() + " set to ERROR state."); - getDelegate().updateTriggerState(conn, trigger.getName(), - trigger.getGroup(), STATE_ERROR); - } else if (triggerInstCode == Trigger.INSTRUCTION_SET_ALL_JOB_TRIGGERS_COMPLETE) { - getDelegate().updateTriggerStatesForJob(conn, - trigger.getJobName(), trigger.getJobGroup(), + } else if (triggerInstCode == CompletedExecutionInstruction.SET_TRIGGER_COMPLETE) { + getDelegate().updateTriggerState(conn, trigger.getKey(), STATE_COMPLETE); - } else if (triggerInstCode == Trigger.INSTRUCTION_SET_ALL_JOB_TRIGGERS_ERROR) { + signalSchedulingChangeOnTxCompletion(0L); + } else if (triggerInstCode == CompletedExecutionInstruction.SET_TRIGGER_ERROR) { + getLog().info("Trigger " + trigger.getKey() + " set to ERROR state."); + getDelegate().updateTriggerState(conn, trigger.getKey(), + STATE_ERROR); + signalSchedulingChangeOnTxCompletion(0L); + } else if (triggerInstCode == CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_COMPLETE) { + getDelegate().updateTriggerStatesForJob(conn, + trigger.getJobKey(), STATE_COMPLETE); + signalSchedulingChangeOnTxCompletion(0L); + } else if (triggerInstCode == CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_ERROR) { getLog().info("All triggers of Job " + - trigger.getFullJobName() + " set to ERROR state."); + trigger.getKey() + " set to ERROR state."); getDelegate().updateTriggerStatesForJob(conn, - trigger.getJobName(), trigger.getJobGroup(), - STATE_ERROR); + trigger.getJobKey(), STATE_ERROR); + signalSchedulingChangeOnTxCompletion(0L); } - if (jobDetail.isStateful()) { + if (jobDetail.isConcurrentExectionDisallowed()) { getDelegate().updateTriggerStatesForJobFromOtherState(conn, - jobDetail.getName(), jobDetail.getGroup(), - STATE_WAITING, STATE_BLOCKED); + jobDetail.getKey(), STATE_WAITING, + STATE_BLOCKED); getDelegate().updateTriggerStatesForJobFromOtherState(conn, - jobDetail.getName(), jobDetail.getGroup(), - STATE_PAUSED, STATE_PAUSED_BLOCKED); + jobDetail.getKey(), STATE_PAUSED, + STATE_PAUSED_BLOCKED); + signalSchedulingChangeOnTxCompletion(0L); + } + if (jobDetail.isPersistJobDataAfterExecution()) { try { if (jobDetail.getJobDataMap().isDirty()) { - getDelegate().updateJobData(conn, jobDetail); + getDelegate().updateJobData(conn, jobDetail); } } catch (IOException e) { throw new JobPersistenceException( @@ -1958,172 +3126,280 @@ *

*/ protected DriverDelegate getDelegate() throws NoSuchDelegateException { - if (null == delegate) { - try { - if(delegateClassName != null) - delegateClass = - getClassLoadHelper().loadClass(delegateClassName); - - Constructor ctor = null; - Object[] ctorParams = null; - if (canUseProperties()) { - Class[] ctorParamTypes = new Class[]{Log.class, - String.class, String.class, Boolean.class}; - ctor = delegateClass.getConstructor(ctorParamTypes); - ctorParams = new Object[]{getLog(), tablePrefix, - instanceId, new Boolean(canUseProperties())}; - } else { - Class[] ctorParamTypes = new Class[]{Log.class, - String.class, String.class}; - ctor = delegateClass.getConstructor(ctorParamTypes); - ctorParams = new Object[]{getLog(), tablePrefix, instanceId}; - } + synchronized(this) { + if(null == delegate) { + try { + if(delegateClassName != null) { + delegateClass = getClassLoadHelper().loadClass(delegateClassName, DriverDelegate.class); + } - delegate = (DriverDelegate) ctor.newInstance(ctorParams); - } catch (NoSuchMethodException e) { - throw new NoSuchDelegateException( - "Couldn't find delegate constructor: " + e.getMessage()); - } catch (InstantiationException e) { - throw new NoSuchDelegateException("Couldn't create delegate: " - + e.getMessage()); - } catch (IllegalAccessException e) { - throw new NoSuchDelegateException("Couldn't create delegate: " - + e.getMessage()); - } catch (InvocationTargetException e) { - throw new NoSuchDelegateException("Couldn't create delegate: " - + e.getMessage()); - } catch (ClassNotFoundException e) { - throw new NoSuchDelegateException("Couldn't load delegate class: " - + e.getMessage()); + delegate = delegateClass.newInstance(); + + delegate.initialize(getLog(), tablePrefix, instanceName, instanceId, getClassLoadHelper(), canUseProperties(), getDriverDelegateInitString()); + + } catch (InstantiationException e) { + throw new NoSuchDelegateException("Couldn't create delegate: " + + e.getMessage(), e); + } catch (IllegalAccessException e) { + throw new NoSuchDelegateException("Couldn't create delegate: " + + e.getMessage(), e); + } catch (ClassNotFoundException e) { + throw new NoSuchDelegateException("Couldn't load delegate class: " + + e.getMessage(), e); + } } + return delegate; } - - return delegate; } protected Semaphore getLockHandler() { return lockHandler; } + public void setLockHandler(Semaphore lockHandler) { + this.lockHandler = lockHandler; + } + //--------------------------------------------------------------------------- // Management methods //--------------------------------------------------------------------------- - protected abstract boolean doRecoverMisfires() - throws JobPersistenceException; + protected RecoverMisfiredJobsResult doRecoverMisfires() throws JobPersistenceException { + boolean transOwner = false; + Connection conn = getNonManagedTXConnection(); + try { + RecoverMisfiredJobsResult result = RecoverMisfiredJobsResult.NO_OP; + + // Before we make the potentially expensive call to acquire the + // trigger lock, peek ahead to see if it is likely we would find + // misfired triggers requiring recovery. + int misfireCount = (getDoubleCheckLockMisfireHandler()) ? + getDelegate().countMisfiredTriggersInState( + conn, STATE_WAITING, getMisfireTime()) : + Integer.MAX_VALUE; + + if (misfireCount == 0) { + getLog().debug( + "Found 0 triggers that missed their scheduled fire-time."); + } else { + transOwner = getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); + + result = recoverMisfiredJobs(conn, false); + } + + commitConnection(conn); + return result; + } catch (JobPersistenceException e) { + rollbackConnection(conn); + throw e; + } catch (SQLException e) { + rollbackConnection(conn); + throw new JobPersistenceException("Database error recovering from misfires.", e); + } catch (RuntimeException e) { + rollbackConnection(conn); + throw new JobPersistenceException("Unexpected runtime exception: " + + e.getMessage(), e); + } finally { + try { + releaseLock(LOCK_TRIGGER_ACCESS, transOwner); + } finally { + cleanupConnection(conn); + } + } + } - protected void signalSchedulingChange() { - signaler.signalSchedulingChange(); + protected ThreadLocal sigChangeForTxCompletion = new ThreadLocal(); + protected void signalSchedulingChangeOnTxCompletion(long candidateNewNextFireTime) { + Long sigTime = sigChangeForTxCompletion.get(); + if(sigTime == null && candidateNewNextFireTime >= 0L) + sigChangeForTxCompletion.set(candidateNewNextFireTime); + else { + if(sigTime == null || candidateNewNextFireTime < sigTime) + sigChangeForTxCompletion.set(candidateNewNextFireTime); + } } + + protected Long clearAndGetSignalSchedulingChangeOnTxCompletion() { + Long t = sigChangeForTxCompletion.get(); + sigChangeForTxCompletion.set(null); + return t; + } + protected void signalSchedulingChangeImmediately(long candidateNewNextFireTime) { + schedSignaler.signalSchedulingChange(candidateNewNextFireTime); + } + //--------------------------------------------------------------------------- // Cluster management methods //--------------------------------------------------------------------------- - protected abstract boolean doCheckin() throws JobPersistenceException; - protected boolean firstCheckIn = true; protected long lastCheckin = System.currentTimeMillis(); + + protected boolean doCheckin() throws JobPersistenceException { + boolean transOwner = false; + boolean transStateOwner = false; + boolean recovered = false; + Connection conn = getNonManagedTXConnection(); + try { + // Other than the first time, always checkin first to make sure there is + // work to be done before we acquire the lock (since that is expensive, + // and is almost never necessary). This must be done in a separate + // transaction to prevent a deadlock under recovery conditions. + List failedRecords = null; + if (!firstCheckIn) { + failedRecords = clusterCheckIn(conn); + commitConnection(conn); + } + + if (firstCheckIn || (failedRecords.size() > 0)) { + getLockHandler().obtainLock(conn, LOCK_STATE_ACCESS); + transStateOwner = true; + + // Now that we own the lock, make sure we still have work to do. + // The first time through, we also need to make sure we update/create our state record + failedRecords = (firstCheckIn) ? clusterCheckIn(conn) : findFailedInstances(conn); + + if (failedRecords.size() > 0) { + getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); + //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); + transOwner = true; + + clusterRecover(conn, failedRecords); + recovered = true; + } + } + + commitConnection(conn); + } catch (JobPersistenceException e) { + rollbackConnection(conn); + throw e; + } finally { + try { + releaseLock(LOCK_TRIGGER_ACCESS, transOwner); + } finally { + try { + releaseLock(LOCK_STATE_ACCESS, transStateOwner); + } finally { + cleanupConnection(conn); + } + } + } + + firstCheckIn = false; + + return recovered; + } + /** * Get a list of all scheduler instances in the cluster that may have failed. - * This includes this scheduler if it has no recoverer and is checking for the - * first time. + * This includes this scheduler if it is checking in for the first time. */ - protected List findFailedInstances(Connection conn) - throws JobPersistenceException { - - List failedInstances = new LinkedList(); - boolean selfFailed = false; - - long timeNow = System.currentTimeMillis(); - + protected List findFailedInstances(Connection conn) + throws JobPersistenceException { try { - List states = getDelegate().selectSchedulerStateRecords(conn, null); - // build map of states by Id... - HashMap statesById = new HashMap(); - Iterator itr = states.iterator(); - while (itr.hasNext()) { - SchedulerStateRecord rec = (SchedulerStateRecord) itr.next(); - statesById.put(rec.getSchedulerInstanceId(), rec); - } + List failedInstances = new LinkedList(); + boolean foundThisScheduler = false; + long timeNow = System.currentTimeMillis(); + + List states = getDelegate().selectSchedulerStateRecords(conn, null); - itr = states.iterator(); - while (itr.hasNext()) { - SchedulerStateRecord rec = (SchedulerStateRecord) itr.next(); + for(SchedulerStateRecord rec: states) { // find own record... if (rec.getSchedulerInstanceId().equals(getInstanceId())) { + foundThisScheduler = true; if (firstCheckIn) { - if (rec.getRecoverer() == null) { - failedInstances.add(rec); - } else { - // make sure the recoverer hasn't died itself! - SchedulerStateRecord recOrec = (SchedulerStateRecord)statesById.get(rec.getRecoverer()); - - long failedIfAfter = (recOrec == null) ? timeNow : calcFailedIfAfter(recOrec); - - // if it has failed, then let's become the recoverer - if( failedIfAfter < timeNow || recOrec == null) { - failedInstances.add(rec); - } - } + failedInstances.add(rec); } - // TODO: revisit when handle self-failed-out impled (see TODO in clusterCheckIn() below) - // else if (rec.getRecoverer() != null) { - // selfFailed = true; - // } } else { // find failed instances... - long failedIfAfter = calcFailedIfAfter(rec); - - if (rec.getRecoverer() == null) { - if (failedIfAfter < timeNow) { - failedInstances.add(rec); - } - } else { - // make sure the recoverer hasn't died itself! - SchedulerStateRecord recOrec = (SchedulerStateRecord)statesById.get(rec.getRecoverer()); - - failedIfAfter = (recOrec == null) ? timeNow : calcFailedIfAfter(recOrec); - - // if it has failed, then let's become the recoverer - if (failedIfAfter < timeNow || recOrec == null) { - failedInstances.add(rec); - } + if (calcFailedIfAfter(rec) < timeNow) { + failedInstances.add(rec); } } } + + // The first time through, also check for orphaned fired triggers. + if (firstCheckIn) { + failedInstances.addAll(findOrphanedFailedInstances(conn, states)); + } + + // If not the first time but we didn't find our own instance, then + // Someone must have done recovery for us. + if ((!foundThisScheduler) && (!firstCheckIn)) { + // FUTURE_TODO: revisit when handle self-failed-out impl'ed (see FUTURE_TODO in clusterCheckIn() below) + getLog().warn( + "This scheduler instance (" + getInstanceId() + ") is still " + + "active but was recovered by another instance in the cluster. " + + "This may cause inconsistent behavior."); + } + + return failedInstances; } catch (Exception e) { lastCheckin = System.currentTimeMillis(); throw new JobPersistenceException("Failure identifying failed instances when checking-in: " + e.getMessage(), e); } + } - return failedInstances; + /** + * Create dummy SchedulerStateRecord objects for fired triggers + * that have no scheduler state record. Checkin timestamp and interval are + * left as zero on these dummy SchedulerStateRecord objects. + * + * @param schedulerStateRecords List of all current SchedulerStateRecords + */ + private List findOrphanedFailedInstances( + Connection conn, + List schedulerStateRecords) + throws SQLException, NoSuchDelegateException { + List orphanedInstances = new ArrayList(); + + Set allFiredTriggerInstanceNames = getDelegate().selectFiredTriggerInstanceNames(conn); + if (!allFiredTriggerInstanceNames.isEmpty()) { + for (SchedulerStateRecord rec: schedulerStateRecords) { + + allFiredTriggerInstanceNames.remove(rec.getSchedulerInstanceId()); + } + + for (String inst: allFiredTriggerInstanceNames) { + + SchedulerStateRecord orphanedInstance = new SchedulerStateRecord(); + orphanedInstance.setSchedulerInstanceId(inst); + + orphanedInstances.add(orphanedInstance); + + getLog().warn( + "Found orphaned fired triggers for instance: " + orphanedInstance.getSchedulerInstanceId()); + } + } + + return orphanedInstances; } protected long calcFailedIfAfter(SchedulerStateRecord rec) { - return rec.getCheckinTimestamp() + - Math.max(rec.getCheckinInterval(), - (System.currentTimeMillis() - lastCheckin)) + - 7500L; + return rec.getCheckinTimestamp() + + Math.max(rec.getCheckinInterval(), + (System.currentTimeMillis() - lastCheckin)) + + 7500L; } - protected List clusterCheckIn(Connection conn) - throws JobPersistenceException { + protected List clusterCheckIn(Connection conn) + throws JobPersistenceException { - List failedInstances = findFailedInstances(conn); + List failedInstances = findFailedInstances(conn); try { - // TODO: handle self-failed-out + // FUTURE_TODO: handle self-failed-out // check in... lastCheckin = System.currentTimeMillis(); - if(getDelegate().updateSchedulerState(conn, getInstanceId(), lastCheckin, null) == 0) { + if(getDelegate().updateSchedulerState(conn, getInstanceId(), lastCheckin) == 0) { getDelegate().insertSchedulerState(conn, getInstanceId(), - lastCheckin, getClusterCheckinInterval(), null); + lastCheckin, getClusterCheckinInterval()); } } catch (Exception e) { @@ -2134,8 +3410,9 @@ return failedInstances; } - protected void clusterRecover(Connection conn, List failedInstances) - throws JobPersistenceException { + @SuppressWarnings("ConstantConditions") + protected void clusterRecover(Connection conn, List failedInstances) + throws JobPersistenceException { if (failedInstances.size() > 0) { @@ -2145,77 +3422,73 @@ "ClusterManager: detected " + failedInstances.size() + " failed or restarted instances."); try { - Iterator itr = failedInstances.iterator(); - while (itr.hasNext()) { - SchedulerStateRecord rec = (SchedulerStateRecord) itr - .next(); - + for (SchedulerStateRecord rec : failedInstances) { getLog().info( "ClusterManager: Scanning for instance \"" + rec.getSchedulerInstanceId() + "\"'s failed in-progress jobs."); - List firedTriggerRecs = getDelegate() + List firedTriggerRecs = getDelegate() .selectInstancesFiredTriggerRecords(conn, rec.getSchedulerInstanceId()); int acquiredCount = 0; int recoveredCount = 0; int otherCount = 0; - Iterator ftItr = firedTriggerRecs.iterator(); - while (ftItr.hasNext()) { - FiredTriggerRecord ftRec = (FiredTriggerRecord) ftItr - .next(); + Set triggerKeys = new HashSet(); - Key tKey = ftRec.getTriggerKey(); - Key jKey = ftRec.getJobKey(); + for (FiredTriggerRecord ftRec : firedTriggerRecs) { + TriggerKey tKey = ftRec.getTriggerKey(); + JobKey jKey = ftRec.getJobKey(); + + triggerKeys.add(tKey); + // release blocked triggers.. if (ftRec.getFireInstanceState().equals(STATE_BLOCKED)) { getDelegate() .updateTriggerStatesForJobFromOtherState( - conn, jKey.getName(), - jKey.getGroup(), STATE_WAITING, - STATE_BLOCKED); - } - if (ftRec.getFireInstanceState().equals(STATE_PAUSED_BLOCKED)) { + conn, jKey, + STATE_WAITING, STATE_BLOCKED); + } else if (ftRec.getFireInstanceState().equals(STATE_PAUSED_BLOCKED)) { getDelegate() .updateTriggerStatesForJobFromOtherState( - conn, jKey.getName(), - jKey.getGroup(), STATE_PAUSED, - STATE_PAUSED_BLOCKED); + conn, jKey, + STATE_PAUSED, STATE_PAUSED_BLOCKED); } // release acquired triggers.. if (ftRec.getFireInstanceState().equals(STATE_ACQUIRED)) { getDelegate().updateTriggerStateFromOtherState( - conn, tKey.getName(), tKey.getGroup(), - STATE_WAITING, STATE_ACQUIRED); + conn, tKey, STATE_WAITING, + STATE_ACQUIRED); acquiredCount++; - }// handle jobs marked for recovery that were not fully - // executed.. - else if (ftRec.isJobRequestsRecovery()) { - if (jobExists(conn, jKey.getName(), jKey.getGroup())) { - SimpleTrigger rcvryTrig = new SimpleTrigger( + } else if (ftRec.isJobRequestsRecovery()) { + // handle jobs marked for recovery that were not fully + // executed.. + if (jobExists(conn, jKey)) { + @SuppressWarnings("deprecation") + SimpleTriggerImpl rcvryTrig = new SimpleTriggerImpl( "recover_" + rec.getSchedulerInstanceId() + "_" + String.valueOf(recoverIds++), Scheduler.DEFAULT_RECOVERY_GROUP, - new Date(ftRec.getFireTimestamp())); + new Date(ftRec.getScheduleTimestamp())); rcvryTrig.setJobName(jKey.getName()); rcvryTrig.setJobGroup(jKey.getGroup()); - rcvryTrig - .setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW); + rcvryTrig.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY); + rcvryTrig.setPriority(ftRec.getPriority()); JobDataMap jd = getDelegate().selectTriggerJobDataMap(conn, tKey.getName(), tKey.getGroup()); - jd.put("QRTZ_FAILED_JOB_ORIG_TRIGGER_NAME", tKey.getName()); - jd.put("QRTZ_FAILED_JOB_ORIG_TRIGGER_GROUP", tKey.getGroup()); - jd.put("QRTZ_FAILED_JOB_ORIG_TRIGGER_FIRETIME_IN_MILLISECONDS_AS_STRING", String.valueOf(ftRec.getFireTimestamp())); + jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_NAME, tKey.getName()); + jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_GROUP, tKey.getGroup()); + jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_FIRETIME_IN_MILLISECONDS, String.valueOf(ftRec.getFireTimestamp())); + jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_SCHEDULED_FIRETIME_IN_MILLISECONDS, String.valueOf(ftRec.getScheduleTimestamp())); rcvryTrig.setJobDataMap(jd); rcvryTrig.computeFirstFireTime(null); - storeTrigger(conn, null, rcvryTrig, null, false, + storeTrigger(conn, rcvryTrig, null, false, STATE_WAITING, false, true); recoveredCount++; } else { @@ -2231,96 +3504,157 @@ } // free up stateful job's triggers - if (ftRec.isJobIsStateful()) { + if (ftRec.isJobDisallowsConcurrentExecution()) { getDelegate() - .updateTriggerStatesForJobFromOtherState( - conn, jKey.getName(), - jKey.getGroup(), STATE_WAITING, - STATE_BLOCKED); + .updateTriggerStatesForJobFromOtherState( + conn, jKey, + STATE_WAITING, STATE_BLOCKED); getDelegate() - .updateTriggerStatesForJobFromOtherState( - conn, jKey.getName(), - jKey.getGroup(), STATE_PAUSED, - STATE_PAUSED_BLOCKED); + .updateTriggerStatesForJobFromOtherState( + conn, jKey, + STATE_PAUSED, STATE_PAUSED_BLOCKED); } } getDelegate().deleteFiredTriggers(conn, rec.getSchedulerInstanceId()); + // Check if any of the fired triggers we just deleted were the last fired trigger + // records of a COMPLETE trigger. + int completeCount = 0; + for (TriggerKey triggerKey : triggerKeys) { + + if (getDelegate().selectTriggerState(conn, triggerKey). + equals(STATE_COMPLETE)) { + List firedTriggers = + getDelegate().selectFiredTriggerRecords(conn, triggerKey.getName(), triggerKey.getGroup()); + if (firedTriggers.isEmpty()) { + + if (removeTrigger(conn, triggerKey)) { + completeCount++; + } + } + } + } + logWarnIfNonZero(acquiredCount, "ClusterManager: ......Freed " + acquiredCount + " acquired trigger(s)."); + logWarnIfNonZero(completeCount, + "ClusterManager: ......Deleted " + completeCount + + " complete triggers(s)."); logWarnIfNonZero(recoveredCount, "ClusterManager: ......Scheduled " + recoveredCount + " recoverable job(s) for recovery."); logWarnIfNonZero(otherCount, "ClusterManager: ......Cleaned-up " + otherCount + " other failed job(s)."); - getDelegate().deleteSchedulerState(conn, - rec.getSchedulerInstanceId()); - - // update record to show that recovery was handled - if (rec.getSchedulerInstanceId().equals(getInstanceId())) { - getDelegate().insertSchedulerState(conn, - rec.getSchedulerInstanceId(), System.currentTimeMillis(), - rec.getCheckinInterval(), null); + if (!rec.getSchedulerInstanceId().equals(getInstanceId())) { + getDelegate().deleteSchedulerState(conn, + rec.getSchedulerInstanceId()); } - } - } catch (Exception e) { + } catch (Throwable e) { throw new JobPersistenceException("Failure recovering jobs: " + e.getMessage(), e); } } } protected void logWarnIfNonZero(int val, String warning) { - if (val > 0) getLog().info(warning); - else + if (val > 0) { + getLog().info(warning); + } else { getLog().debug(warning); + } } /** - * Closes the supplied connection - * - * @param conn (Optional) - * @throws JobPersistenceException thrown if a SQLException occurs when the - * connection is closed + *

+ * Cleanup the given database connection. This means restoring + * any modified auto commit or transaction isolation connection + * attributes, and then closing the underlying connection. + *

+ * + *

+ * This is separate from closeConnection() because the Spring + * integration relies on being able to overload closeConnection() and + * expects the same connection back that it originally returned + * from the datasource. + *

+ * + * @see #closeConnection(Connection) */ - protected void closeConnection(Connection conn) - throws JobPersistenceException { - + protected void cleanupConnection(Connection conn) { if (conn != null) { + if (conn instanceof Proxy) { + Proxy connProxy = (Proxy)conn; + + InvocationHandler invocationHandler = + Proxy.getInvocationHandler(connProxy); + if (invocationHandler instanceof AttributeRestoringConnectionInvocationHandler) { + AttributeRestoringConnectionInvocationHandler connHandler = + (AttributeRestoringConnectionInvocationHandler)invocationHandler; + + connHandler.restoreOriginalAtributes(); + closeConnection(connHandler.getWrappedConnection()); + return; + } + } + + // Wan't a Proxy, or was a Proxy, but wasn't ours. + closeConnection(conn); + } + } + + + /** + * Closes the supplied Connection. + *

+ * Ignores a null Connection. + * Any exception thrown trying to close the Connection is + * logged and ignored. + *

+ * + * @param conn The Connection to close (Optional). + */ + protected void closeConnection(Connection conn) { + if (conn != null) { try { conn.close(); } catch (SQLException e) { - throw new JobPersistenceException( - "Couldn't close jdbc connection. "+e.getMessage(), e); + getLog().error("Failed to close Connection", e); + } catch (Throwable e) { + getLog().error( + "Unexpected exception closing Connection." + + " This is often due to a Connection being returned after or during shutdown.", e); } } } /** - * Rollback the supplied connection + * Rollback the supplied connection. + * + *

+ * Logs any SQLException it gets trying to rollback, but will not propogate + * the exception lest it mask the exception that caused the caller to + * need to rollback in the first place. + *

* * @param conn (Optional) - * @throws JobPersistenceException thrown if a SQLException occurs when the - * connection is rolled back */ - protected void rollbackConnection(Connection conn) - throws JobPersistenceException { - + protected void rollbackConnection(Connection conn) { if (conn != null) { try { conn.rollback(); } catch (SQLException e) { - throw new JobPersistenceException( + getLog().error( "Couldn't rollback jdbc connection. "+e.getMessage(), e); } } } + /** * Commit the supplied connection * @@ -2340,7 +3674,153 @@ } } } + + /** + * Implement this interface to provide the code to execute within + * the a transaction template. If no return value is required, execute + * should just return null. + * + * @see JobStoreSupport#executeInNonManagedTXLock(String, TransactionCallback) + * @see JobStoreSupport#executeInLock(String, TransactionCallback) + * @see JobStoreSupport#executeWithoutLock(TransactionCallback) + */ + protected interface TransactionCallback { + T execute(Connection conn) throws JobPersistenceException; + } + protected interface TransactionValidator { + Boolean validate(Connection conn, T result) throws JobPersistenceException; + } + + /** + * Implement this interface to provide the code to execute within + * the a transaction template that has no return value. + * + * @see JobStoreSupport#executeInNonManagedTXLock(String, TransactionCallback) + */ + protected abstract class VoidTransactionCallback implements TransactionCallback { + public final Void execute(Connection conn) throws JobPersistenceException { + executeVoid(conn); + return null; + } + + abstract void executeVoid(Connection conn) throws JobPersistenceException; + } + + /** + * Execute the given callback in a transaction. Depending on the JobStore, + * the surrounding transaction may be assumed to be already present + * (managed). + * + *

+ * This method just forwards to executeInLock() with a null lockName. + *

+ * + * @see #executeInLock(String, TransactionCallback) + */ + public T executeWithoutLock( + TransactionCallback txCallback) throws JobPersistenceException { + return executeInLock(null, txCallback); + } + + /** + * Execute the given callback having acquired the given lock. + * Depending on the JobStore, the surrounding transaction may be + * assumed to be already present (managed). + * + * @param lockName The name of the lock to acquire, for example + * "TRIGGER_ACCESS". If null, then no lock is acquired, but the + * lockCallback is still executed in a transaction. + */ + protected abstract T executeInLock( + String lockName, + TransactionCallback txCallback) throws JobPersistenceException; + + protected T retryExecuteInNonManagedTXLock(String lockName, TransactionCallback txCallback) { + for (int retry = 1; !shutdown; retry++) { + try { + return executeInNonManagedTXLock(lockName, txCallback, null); + } catch (JobPersistenceException jpe) { + if(retry % 4 == 0) { + schedSignaler.notifySchedulerListenersError("An error occurred while " + txCallback, jpe); + } + } catch (RuntimeException e) { + getLog().error("retryExecuteInNonManagedTXLock: RuntimeException " + e.getMessage(), e); + } + try { + Thread.sleep(getDbRetryInterval()); // retry every N seconds (the db connection must be failed) + } catch (InterruptedException e) { + throw new IllegalStateException("Received interrupted exception", e); + } + } + throw new IllegalStateException("JobStore is shutdown - aborting retry"); + } + + /** + * Execute the given callback having optionally acquired the given lock. + * This uses the non-managed transaction connection. + * + * @param lockName The name of the lock to acquire, for example + * "TRIGGER_ACCESS". If null, then no lock is acquired, but the + * lockCallback is still executed in a non-managed transaction. + */ + protected T executeInNonManagedTXLock( + String lockName, + TransactionCallback txCallback, final TransactionValidator txValidator) throws JobPersistenceException { + boolean transOwner = false; + Connection conn = null; + try { + if (lockName != null) { + // If we aren't using db locks, then delay getting DB connection + // until after acquiring the lock since it isn't needed. + if (getLockHandler().requiresConnection()) { + conn = getNonManagedTXConnection(); + } + + transOwner = getLockHandler().obtainLock(conn, lockName); + } + + if (conn == null) { + conn = getNonManagedTXConnection(); + } + + final T result = txCallback.execute(conn); + try { + commitConnection(conn); + } catch (JobPersistenceException e) { + rollbackConnection(conn); + if (txValidator == null || !retryExecuteInNonManagedTXLock(lockName, new TransactionCallback() { + @Override + public Boolean execute(Connection conn) throws JobPersistenceException { + return txValidator.validate(conn, result); + } + })) { + throw e; + } + } + + Long sigTime = clearAndGetSignalSchedulingChangeOnTxCompletion(); + if(sigTime != null && sigTime >= 0) { + signalSchedulingChangeImmediately(sigTime); + } + + return result; + } catch (JobPersistenceException e) { + rollbackConnection(conn); + throw e; + } catch (RuntimeException e) { + rollbackConnection(conn); + throw new JobPersistenceException("Unexpected runtime exception: " + + e.getMessage(), e); + } finally { + try { + releaseLock(lockName, transOwner); + } finally { + cleanupConnection(conn); + } + } + } + ///////////////////////////////////////////////////////////////////////////// // // ClusterManager Thread @@ -2349,21 +3829,21 @@ class ClusterManager extends Thread { - private boolean shutdown = false; + private volatile boolean shutdown = false; - private JobStoreSupport js; - private int numFails = 0; - ClusterManager(JobStoreSupport js) { - this.js = js; + ClusterManager() { this.setPriority(Thread.NORM_PRIORITY + 2); this.setName("QuartzScheduler_" + instanceName + "-" + instanceId + "_ClusterManager"); + this.setDaemon(getMakeThreadsDaemons()); } public void initialize() { this.manage(); - this.start(); + + ThreadExecutor executor = getThreadExecutor(); + executor.execute(ClusterManager.this); } public void shutdown() { @@ -2375,38 +3855,46 @@ boolean res = false; try { - res = js.doCheckin(); + res = doCheckin(); numFails = 0; getLog().debug("ClusterManager: Check-in complete."); } catch (Exception e) { - if(numFails % 4 == 0) + if(numFails % 4 == 0) { getLog().error( "ClusterManager: Error managing cluster: " + e.getMessage(), e); + } numFails++; } return res; } + @Override public void run() { while (!shutdown) { if (!shutdown) { long timeToSleep = getClusterCheckinInterval(); long transpiredTime = (System.currentTimeMillis() - lastCheckin); timeToSleep = timeToSleep - transpiredTime; - if (timeToSleep <= 0) timeToSleep = 100L; + if (timeToSleep <= 0) { + timeToSleep = 100L; + } - if(numFails > 0) timeToSleep = Math.max(getDbRetryInterval(), timeToSleep); + if(numFails > 0) { + timeToSleep = Math.max(getDbRetryInterval(), timeToSleep); + } try { Thread.sleep(timeToSleep); } catch (Exception ignore) { } } - if (!shutdown && this.manage()) signalSchedulingChange(); + if (!shutdown && this.manage()) { + signalSchedulingChangeImmediately(0L); + } }//while !shutdown } @@ -2420,79 +3908,78 @@ class MisfireHandler extends Thread { - private boolean shutdown = false; + private volatile boolean shutdown = false; - private JobStoreSupport js; - private int numFails = 0; - MisfireHandler(JobStoreSupport js) { - this.js = js; + MisfireHandler() { this.setName("QuartzScheduler_" + instanceName + "-" + instanceId + "_MisfireHandler"); + this.setDaemon(getMakeThreadsDaemons()); } public void initialize() { - //this.manage(); - this.start(); + ThreadExecutor executor = getThreadExecutor(); + executor.execute(MisfireHandler.this); } public void shutdown() { shutdown = true; this.interrupt(); } - private boolean manage() { + private RecoverMisfiredJobsResult manage() { try { getLog().debug("MisfireHandler: scanning for misfires..."); - boolean res = js.doRecoverMisfires(); + RecoverMisfiredJobsResult res = doRecoverMisfires(); numFails = 0; return res; } catch (Exception e) { - if(numFails % 4 == 0) + if(numFails % 4 == 0) { getLog().error( "MisfireHandler: Error handling misfires: " + e.getMessage(), e); + } numFails++; } - return false; + return RecoverMisfiredJobsResult.NO_OP; } + @Override public void run() { while (!shutdown) { long sTime = System.currentTimeMillis(); - boolean moreToDo = this.manage(); + RecoverMisfiredJobsResult recoverMisfiredJobsResult = manage(); - if (lastRecoverCount > 0) signalSchedulingChange(); + if (recoverMisfiredJobsResult.getProcessedMisfiredTriggerCount() > 0) { + signalSchedulingChangeImmediately(recoverMisfiredJobsResult.getEarliestNewTime()); + } - long spanTime = System.currentTimeMillis() - sTime; + if (!shutdown) { + long timeToSleep = 50l; // At least a short pause to help balance threads + if (!recoverMisfiredJobsResult.hasMoreMisfiredTriggers()) { + timeToSleep = getMisfireThreshold() - (System.currentTimeMillis() - sTime); + if (timeToSleep <= 0) { + timeToSleep = 50l; + } - if (!shutdown && !moreToDo) { - long timeToSleep = getMisfireThreshold() - spanTime; - if (timeToSleep <= 0) timeToSleep = 50L; - - if(numFails > 0) timeToSleep = Math.max(getDbRetryInterval(), timeToSleep); + if(numFails > 0) { + timeToSleep = Math.max(getDbRetryInterval(), timeToSleep); + } + } - if (timeToSleep > 0) try { + try { Thread.sleep(timeToSleep); } catch (Exception ignore) { } - } - else if(moreToDo) { // short pause to help balance threads... - try { - Thread.sleep(50); - } catch (Exception ignore) { - } - } - - }//while !shutdown + }//while !shutdown + } } } - } // EOF Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/JobStoreTX.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/JobStoreTX.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/JobStoreTX.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/JobStoreTX.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,27 +15,15 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; -import org.quartz.Calendar; -import org.quartz.JobDetail; +import java.sql.Connection; + import org.quartz.JobPersistenceException; -import org.quartz.ObjectAlreadyExistsException; import org.quartz.SchedulerConfigException; -import org.quartz.SchedulerException; -import org.quartz.Trigger; -import org.quartz.core.SchedulingContext; import org.quartz.spi.ClassLoadHelper; import org.quartz.spi.SchedulerSignaler; -import org.quartz.spi.TriggerFiredBundle; -import java.sql.Connection; -import java.util.List; -import java.util.Set; - /** *

* JobStoreTX is meant to be used in a standalone environment. @@ -62,1363 +50,47 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - public void initialize(ClassLoadHelper loadHelper, - SchedulerSignaler signaler) throws SchedulerConfigException { + @Override + public void initialize(ClassLoadHelper classLoadHelper, + SchedulerSignaler schedSignaler) throws SchedulerConfigException { - super.initialize(loadHelper, signaler); + super.initialize(classLoadHelper, schedSignaler); getLog().info("JobStoreTX initialized."); } - //--------------------------------------------------------------------------- - // JobStoreSupport methods - //--------------------------------------------------------------------------- - /** - *

- * Recover any failed or misfired jobs and clean up the data store as - * appropriate. - *

+ * For JobStoreTX, the non-managed TX connection is just + * the normal connection because it is not CMT. * - * @throws JobPersistenceException - * if jobs could not be recovered + * @see JobStoreSupport#getConnection() */ - protected void recoverJobs() throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - recoverJobs(conn); - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - protected void cleanVolatileTriggerAndJobs() throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - cleanVolatileTriggerAndJobs(conn); - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - //--------------------------------------------------------------------------- - // job / trigger storage methods - //--------------------------------------------------------------------------- - - /** - *

- * Store the given {@link org.quartz.JobDetail} and {@link org.quartz.Trigger}. - *

- * - * @param newJob - * The JobDetail to be stored. - * @param newTrigger - * The Trigger to be stored. - * @throws ObjectAlreadyExistsException - * if a Job with the same name/group already - * exists. - */ - public void storeJobAndTrigger(SchedulingContext ctxt, JobDetail newJob, - Trigger newTrigger) throws ObjectAlreadyExistsException, - JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - if(isLockOnInsert()) { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - } - - if (newJob.isVolatile() && !newTrigger.isVolatile()) { - JobPersistenceException jpe = new JobPersistenceException( - "Cannot associate non-volatile " - + "trigger with a volatile job!"); - jpe.setErrorCode(SchedulerException.ERR_CLIENT_ERROR); - throw jpe; - } - - storeJob(conn, ctxt, newJob, false); - storeTrigger(conn, ctxt, newTrigger, newJob, false, - Constants.STATE_WAITING, false, false); - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Store the given {@link org.quartz.JobDetail}. - *

- * - * @param newJob - * The JobDetail to be stored. - * @param replaceExisting - * If true, any Job existing in the - * JobStore with the same name & group should be - * over-written. - * @throws ObjectAlreadyExistsException - * if a Job with the same name/group already - * exists, and replaceExisting is set to false. - */ - public void storeJob(SchedulingContext ctxt, JobDetail newJob, - boolean replaceExisting) throws ObjectAlreadyExistsException, - JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - if(isLockOnInsert() || replaceExisting) { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - } - - storeJob(conn, ctxt, newJob, replaceExisting); - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Remove (delete) the {@link org.quartz.Job} with the given - * name, and any {@link org.quartz.Trigger} s that reference - * it. - *

- * - *

- * If removal of the Job results in an empty group, the - * group should be removed from the JobStore's list of - * known group names. - *

- * - * @param jobName - * The name of the Job to be removed. - * @param groupName - * The group name of the Job to be removed. - * @return true if a Job with the given name & - * group was found and removed from the store. - */ - public boolean removeJob(SchedulingContext ctxt, String jobName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - boolean removed = removeJob(conn, ctxt, jobName, groupName, true); - commitConnection(conn); - return removed; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Retrieve the {@link org.quartz.JobDetail} for the given - * {@link org.quartz.Job}. - *

- * - * @param jobName - * The name of the Job to be retrieved. - * @param groupName - * The group name of the Job to be retrieved. - * @return The desired Job, or null if there is no match. - */ - public JobDetail retrieveJob(SchedulingContext ctxt, String jobName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - JobDetail job = retrieveJob(conn, ctxt, jobName, groupName); - commitConnection(conn); - return job; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - closeConnection(conn); - } - } - - /** - *

- * Store the given {@link org.quartz.Trigger}. - *

- * - * @param newTrigger - * The Trigger to be stored. - * @param replaceExisting - * If true, any Trigger existing in - * the JobStore with the same name & group should - * be over-written. - * @throws ObjectAlreadyExistsException - * if a Trigger with the same name/group already - * exists, and replaceExisting is set to false. - */ - public void storeTrigger(SchedulingContext ctxt, Trigger newTrigger, - boolean replaceExisting) throws ObjectAlreadyExistsException, - JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - if(isLockOnInsert() || replaceExisting) { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - } - - storeTrigger(conn, ctxt, newTrigger, null, replaceExisting, - STATE_WAITING, false, false); - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Remove (delete) the {@link org.quartz.Trigger} with the - * given name. - *

- * - *

- * If removal of the Trigger results in an empty group, the - * group should be removed from the JobStore's list of - * known group names. - *

- * - *

- * If removal of the Trigger results in an 'orphaned' Job - * that is not 'durable', then the Job should be deleted - * also. - *

- * - * @param triggerName - * The name of the Trigger to be removed. - * @param groupName - * The group name of the Trigger to be removed. - * @return true if a Trigger with the given - * name & group was found and removed from the store. - */ - public boolean removeTrigger(SchedulingContext ctxt, String triggerName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - boolean removed = removeTrigger(conn, ctxt, triggerName, groupName); - commitConnection(conn); - return removed; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - * @see org.quartz.spi.JobStore#replaceTrigger(org.quartz.core.SchedulingContext, java.lang.String, java.lang.String, org.quartz.Trigger) - */ - public boolean replaceTrigger(SchedulingContext ctxt, String triggerName, String groupName, Trigger newTrigger) throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - boolean removed = replaceTrigger(conn, ctxt, triggerName, groupName, newTrigger); - commitConnection(conn); - return removed; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - - - /** - *

- * Retrieve the given {@link org.quartz.Trigger}. - *

- * - * @param triggerName - * The name of the Trigger to be retrieved. - * @param groupName - * The group name of the Trigger to be retrieved. - * @return The desired Trigger, or null if there is no - * match. - */ - public Trigger retrieveTrigger(SchedulingContext ctxt, String triggerName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - Trigger trigger = retrieveTrigger(conn, ctxt, triggerName, - groupName); - commitConnection(conn); - return trigger; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - closeConnection(conn); - } - } - - /** - *

- * Store the given {@link org.quartz.Calendar}. - *

- * - * @param calName - * The name of the calendar. - * @param calendar - * The Calendar to be stored. - * @param replaceExisting - * If true, any Calendar existing - * in the JobStore with the same name & group - * should be over-written. - * @throws ObjectAlreadyExistsException - * if a Calendar with the same name already - * exists, and replaceExisting is set to false. - */ - public void storeCalendar(SchedulingContext ctxt, String calName, - Calendar calendar, boolean replaceExisting, boolean updateTriggers) - throws ObjectAlreadyExistsException, JobPersistenceException { - Connection conn = getConnection(); - boolean lockOwner = false; - try { - if(isLockOnInsert() || updateTriggers) { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - lockOwner = true; - } - - storeCalendar(conn, ctxt, calName, calendar, replaceExisting, updateTriggers); - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, lockOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Remove (delete) the {@link org.quartz.Calendar} with the - * given name. - *

- * - *

- * If removal of the Calendar would result in - * s pointing to non-existent calendars, then a - * JobPersistenceException will be thrown.

- * * - * @param calName The name of the Calendar to be removed. - * @return true if a Calendar with the given name - * was found and removed from the store. - */ - public boolean removeCalendar(SchedulingContext ctxt, String calName) - throws JobPersistenceException { - Connection conn = getConnection(); - boolean lockOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - lockOwner = true; - - boolean removed = removeCalendar(conn, ctxt, calName); - commitConnection(conn); - return removed; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, lockOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Retrieve the given {@link org.quartz.Trigger}. - *

- * - * @param calName - * The name of the Calendar to be retrieved. - * @return The desired Calendar, or null if there is no - * match. - */ - public Calendar retrieveCalendar(SchedulingContext ctxt, String calName) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - Calendar cal = retrieveCalendar(conn, ctxt, calName); - commitConnection(conn); - return cal; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - closeConnection(conn); - } - } - - //--------------------------------------------------------------------------- - // informational methods - //--------------------------------------------------------------------------- - - /** - *

- * Get the number of {@link org.quartz.Job} s that are - * stored in the JobStore. - *

- */ - public int getNumberOfJobs(SchedulingContext ctxt) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - int numJobs = getNumberOfJobs(conn, ctxt); - commitConnection(conn); - return numJobs; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - closeConnection(conn); - } - } - - /** - *

- * Get the number of {@link org.quartz.Trigger} s that are - * stored in the JobsStore. - *

- */ - public int getNumberOfTriggers(SchedulingContext ctxt) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - int numTriggers = getNumberOfTriggers(conn, ctxt); - commitConnection(conn); - return numTriggers; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - closeConnection(conn); - } - } - - /** - *

- * Get the number of {@link org.quartz.Calendar} s that are - * stored in the JobsStore. - *

- */ - public int getNumberOfCalendars(SchedulingContext ctxt) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - int numCals = getNumberOfCalendars(conn, ctxt); - commitConnection(conn); - return numCals; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - closeConnection(conn); - } - } - - - public Set getPausedTriggerGroups(SchedulingContext ctxt) + @Override + protected Connection getNonManagedTXConnection() throws JobPersistenceException { - - Connection conn = getConnection(); - try { - // no locks necessary for read... - Set groups = getPausedTriggerGroups(conn, ctxt); - commitConnection(conn); - return groups; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - closeConnection(conn); - } + return getConnection(); } /** - *

- * Get the names of all of the {@link org.quartz.Job} s that - * have the given group name. - *

+ * Execute the given callback having optionally aquired the given lock. + * For JobStoreTX, because it manages its own transactions + * and only has the one datasource, this is the same behavior as + * executeInNonManagedTXLock(). * - *

- * If there are no jobs in the given group name, the result should be a - * zero-length array (not null). - *

- */ - public String[] getJobNames(SchedulingContext ctxt, String groupName) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - String[] jobNames = getJobNames(conn, ctxt, groupName); - commitConnection(conn); - return jobNames; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - closeConnection(conn); - } - } - - /** - *

- * Get the names of all of the {@link org.quartz.Trigger} s - * that have the given group name. - *

+ * @param lockName The name of the lock to aquire, for example + * "TRIGGER_ACCESS". If null, then no lock is aquired, but the + * lockCallback is still executed in a transaction. * - *

- * If there are no triggers in the given group name, the result should be a - * zero-length array (not null). - *

+ * @see JobStoreSupport#executeInNonManagedTXLock(String, TransactionCallback) + * @see JobStoreCMT#executeInLock(String, TransactionCallback) + * @see JobStoreSupport#getNonManagedTXConnection() + * @see JobStoreSupport#getConnection() */ - public String[] getTriggerNames(SchedulingContext ctxt, String groupName) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - String[] triggerNames = getTriggerNames(conn, ctxt, groupName); - commitConnection(conn); - return triggerNames; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - closeConnection(conn); - } + @Override + protected Object executeInLock( + String lockName, + TransactionCallback txCallback) throws JobPersistenceException { + return executeInNonManagedTXLock(lockName, txCallback, null); } - - /** - *

- * Get the names of all of the {@link org.quartz.Job} - * groups. - *

- * - *

- * If there are no known group names, the result should be a zero-length - * array (not null). - *

- */ - public String[] getJobGroupNames(SchedulingContext ctxt) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - String[] groupNames = getJobGroupNames(conn, ctxt); - commitConnection(conn); - return groupNames; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - closeConnection(conn); - } - } - - /** - *

- * Get the names of all of the {@link org.quartz.Trigger} - * groups. - *

- * - *

- * If there are no known group names, the result should be a zero-length - * array (not null). - *

- */ - public String[] getTriggerGroupNames(SchedulingContext ctxt) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - String[] triggerGroups = getTriggerGroupNames(conn, ctxt); - commitConnection(conn); - return triggerGroups; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - closeConnection(conn); - } - } - - /** - *

- * Get the names of all of the {@link org.quartz.Calendar} s - * in the JobStore. - *

- * - *

- * If there are no Calendars in the given group name, the result should be - * a zero-length array (not null). - *

- */ - public String[] getCalendarNames(SchedulingContext ctxt) - throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - String[] calNames = getCalendarNames(conn, ctxt); - commitConnection(conn); - return calNames; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - closeConnection(conn); - } - } - - /** - *

- * Get all of the Triggers that are associated to the given Job. - *

- * - *

- * If there are no matches, a zero-length array should be returned. - *

- */ - public Trigger[] getTriggersForJob(SchedulingContext ctxt, String jobName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - return getTriggersForJob(conn, ctxt, jobName, groupName); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - closeConnection(conn); - } - } - - /** - *

- * Get the current state of the identified {@link Trigger}. - *

- * - * @see Trigger#STATE_NORMAL - * @see Trigger#STATE_PAUSED - * @see Trigger#STATE_COMPLETE - * @see Trigger#STATE_ERROR - * @see Trigger#STATE_NONE - */ - public int getTriggerState(SchedulingContext ctxt, String triggerName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - try { - // no locks necessary for read... - return getTriggerState(conn, ctxt, triggerName, groupName); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - closeConnection(conn); - } - } - - //--------------------------------------------------------------------------- - // trigger state manipulation methods - //--------------------------------------------------------------------------- - - /** - *

- * Pause the {@link org.quartz.Trigger} with the given name. - *

- * - * @see #resumeTrigger(SchedulingContext, String, String) - */ - public void pauseTrigger(SchedulingContext ctxt, String triggerName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - pauseTrigger(conn, ctxt, triggerName, groupName); - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Pause all of the {@link org.quartz.Trigger}s in the - * given group. - *

- * - * @see #resumeTriggerGroup(SchedulingContext, String) - */ - public void pauseTriggerGroup(SchedulingContext ctxt, String groupName) - throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - pauseTriggerGroup(conn, ctxt, groupName); - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Pause the {@link org.quartz.Job} with the given name - by - * pausing all of its current Triggers. - *

- * - * @see #resumeJob(SchedulingContext, String, String) - */ - public void pauseJob(SchedulingContext ctxt, String jobName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - Trigger[] triggers = getTriggersForJob(conn, ctxt, jobName, - groupName); - for (int j = 0; j < triggers.length; j++) { - pauseTrigger(conn, ctxt, triggers[j].getName(), triggers[j] - .getGroup()); - } - - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Pause all of the {@link org.quartz.Job}s in the given - * group - by pausing all of their Triggers. - *

- * - * @see #resumeJobGroup(SchedulingContext, String) - */ - public void pauseJobGroup(SchedulingContext ctxt, String groupName) - throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - String[] jobNames = getJobNames(conn, ctxt, groupName); - - for (int i = 0; i < jobNames.length; i++) { - Trigger[] triggers = getTriggersForJob(conn, ctxt, jobNames[i], - groupName); - for (int j = 0; j < triggers.length; j++) { - pauseTrigger(conn, ctxt, triggers[j].getName(), triggers[j] - .getGroup()); - } - } - - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Resume (un-pause) the {@link org.quartz.Trigger} with the - * given name. - *

- * - *

- * If the Trigger missed one or more fire-times, then the - * Trigger's misfire instruction will be applied. - *

- * - * @see #pauseTrigger(SchedulingContext, String, String) - */ - public void resumeTrigger(SchedulingContext ctxt, String triggerName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - resumeTrigger(conn, ctxt, triggerName, groupName); - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Resume (un-pause) all of the {@link org.quartz.Trigger}s - * in the given group. - *

- * - *

- * If any Trigger missed one or more fire-times, then the - * Trigger's misfire instruction will be applied. - *

- * - * @see #pauseTriggerGroup(SchedulingContext, String) - */ - public void resumeTriggerGroup(SchedulingContext ctxt, String groupName) - throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - resumeTriggerGroup(conn, ctxt, groupName); - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Resume (un-pause) the {@link org.quartz.Job} with the - * given name. - *

- * - *

- * If any of the Job'sTrigger s missed one - * or more fire-times, then the Trigger's misfire - * instruction will be applied. - *

- * - * @see #pauseJob(SchedulingContext, String, String) - */ - public void resumeJob(SchedulingContext ctxt, String jobName, - String groupName) throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - Trigger[] triggers = getTriggersForJob(conn, ctxt, jobName, - groupName); - for (int j = 0; j < triggers.length; j++) { - resumeTrigger(conn, ctxt, triggers[j].getName(), triggers[j] - .getGroup()); - } - - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Resume (un-pause) all of the {@link org.quartz.Job}s in - * the given group. - *

- * - *

- * If any of the Job s had Trigger s that - * missed one or more fire-times, then the Trigger's - * misfire instruction will be applied. - *

- * - * @see #pauseJobGroup(SchedulingContext, String) - */ - public void resumeJobGroup(SchedulingContext ctxt, String groupName) - throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - String[] jobNames = getJobNames(conn, ctxt, groupName); - - for (int i = 0; i < jobNames.length; i++) { - Trigger[] triggers = getTriggersForJob(conn, ctxt, jobNames[i], - groupName); - for (int j = 0; j < triggers.length; j++) { - resumeTrigger(conn, ctxt, triggers[j].getName(), - triggers[j].getGroup()); - } - } - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Pause all triggers - equivalent of calling pauseTriggerGroup(group) - * on every group. - *

- * - *

- * When resumeAll() is called (to un-pause), trigger misfire - * instructions WILL be applied. - *

- * - * @see #resumeAll(SchedulingContext) - * @see #pauseTriggerGroup(SchedulingContext, String) - */ - public void pauseAll(SchedulingContext ctxt) throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - pauseAll(conn, ctxt); - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Resume (un-pause) all triggers - equivalent of calling resumeTriggerGroup(group) - * on every group. - *

- * - *

- * If any Trigger missed one or more fire-times, then the - * Trigger's misfire instruction will be applied. - *

- * - * @see #pauseAll(SchedulingContext) - */ - public void resumeAll(SchedulingContext ctxt) - throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - resumeAll(conn, ctxt); - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - //--------------------------------------------------------------------------- - // trigger firing methods - //--------------------------------------------------------------------------- - - /** - *

- * Get a handle to the next trigger to be fired, and mark it as 'reserved' - * by the calling scheduler. - *

- * - * @see #releaseAcquiredTrigger(SchedulingContext, Trigger) - */ - public Trigger acquireNextTrigger(SchedulingContext ctxt, long noLaterThan) - throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - Trigger trigger = acquireNextTrigger(conn, ctxt, noLaterThan); - commitConnection(conn); - return trigger; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Inform the JobStore that the scheduler no longer plans to - * fire the given Trigger, that it had previously acquired - * (reserved). - *

- */ - public void releaseAcquiredTrigger(SchedulingContext ctxt, Trigger trigger) - throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - releaseAcquiredTrigger(conn, ctxt, trigger); - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Inform the JobStore that the scheduler is now firing the - * given Trigger (executing its associated Job), - * that it had previously acquired (reserved). - *

- * - * @return null if the trigger or it's job or calendar no longer exist, or - * if the trigger was not successfully put into the 'executing' - * state. - */ - public TriggerFiredBundle triggerFired(SchedulingContext ctxt, - Trigger trigger) throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - TriggerFiredBundle tfb = null; - JobPersistenceException err = null; - try { - tfb = triggerFired(conn, ctxt, trigger); - } catch (JobPersistenceException jpe) { - if (jpe.getErrorCode() != SchedulerException.ERR_PERSISTENCE_JOB_DOES_NOT_EXIST) - throw jpe; - err = jpe; - } - - commitConnection(conn); - if (err != null) throw err; - return tfb; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - /** - *

- * Inform the JobStore that the scheduler has completed the - * firing of the given Trigger (and the execution its - * associated Job), and that the {@link org.quartz.JobDataMap} - * in the given JobDetail should be updated if the Job - * is stateful. - *

- */ - public void triggeredJobComplete(SchedulingContext ctxt, Trigger trigger, - JobDetail jobDetail, int triggerInstCode) - throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - triggeredJobComplete(conn, ctxt, trigger, jobDetail, - triggerInstCode); - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - protected boolean doRecoverMisfires() throws JobPersistenceException { - Connection conn = getConnection(); - boolean transOwner = false; - boolean moreToDo = false; - try { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - transOwner = true; - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - - try { - moreToDo = recoverMisfiredJobs(conn, false); - } catch (Exception e) { - throw new JobPersistenceException(e.getMessage(), e); - } - - commitConnection(conn); - - return moreToDo; - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - closeConnection(conn); - } - } - } - - protected boolean doCheckin() throws JobPersistenceException { - Connection conn = getConnection(); - - boolean transOwner = false; - boolean transStateOwner = false; - boolean recovered = false; - - try { - // Other than the first time, always checkin first to make sure there is - // work to be done before we aquire / the lock (since that is expensive, - // and is almost never necessary) - List failedRecords = (firstCheckIn) ? null : clusterCheckIn(conn); - - if (firstCheckIn || (failedRecords.size() > 0)) { - getLockHandler().obtainLock(conn, LOCK_STATE_ACCESS); - transStateOwner = true; - - // Now that we own the lock, make sure we still have work to do. - // The first time through, we also need to make sure we update/create our state record - failedRecords = (firstCheckIn) ? clusterCheckIn(conn) : findFailedInstances(conn); - - if (failedRecords.size() > 0) { - getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); - //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); - transOwner = true; - - clusterRecover(conn, failedRecords); - recovered = true; - } - } - commitConnection(conn); - } catch (JobPersistenceException e) { - rollbackConnection(conn); - throw e; - } finally { - try { - releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); - } finally { - try { - releaseLock(conn, LOCK_STATE_ACCESS, transStateOwner); - } finally { - closeConnection(conn); - } - } - } - - firstCheckIn = false; - - return recovered; - } } - // EOF Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/LockException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/LockException.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/LockException.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/LockException.java 15 Dec 2014 10:09:51 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; import org.quartz.JobPersistenceException; @@ -34,6 +31,8 @@ */ public class LockException extends JobPersistenceException { + private static final long serialVersionUID = 3993800462589137228L; + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -46,7 +45,7 @@ super(msg); } - public LockException(String msg, Exception cause) { + public LockException(String msg, Throwable cause) { super(msg, cause); } } Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/MSSQLDelegate.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/MSSQLDelegate.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/MSSQLDelegate.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/MSSQLDelegate.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; import java.io.IOException; @@ -26,7 +23,8 @@ import java.sql.ResultSet; import java.sql.SQLException; -import org.apache.commons.logging.Log; +import org.quartz.spi.ClassLoadHelper; +import org.slf4j.Logger; /** *

@@ -36,24 +34,7 @@ * @author Jeffrey Wescott */ public class MSSQLDelegate extends StdJDBCDelegate { - /** - *

- * Create new MSSQLDelegate instance. - *

- * - * @param logger - * the logger to use during execution - * @param tablePrefix - * the prefix of all table names - */ - public MSSQLDelegate(Log log, String tablePrefix, String instanceId) { - super(log, tablePrefix, instanceId); - } - public MSSQLDelegate(Log log, String tablePrefix, String instanceId, Boolean useProperties) { - super(log, tablePrefix, instanceId, useProperties); - } - //--------------------------------------------------------------------------- // protected methods that can be overridden by subclasses //--------------------------------------------------------------------------- @@ -75,22 +56,30 @@ * @throws IOException * if deserialization causes an error */ + @Override protected Object getObjectFromBlob(ResultSet rs, String colName) - throws ClassNotFoundException, IOException, SQLException { + throws ClassNotFoundException, IOException, SQLException { InputStream binaryInput = rs.getBinaryStream(colName); - if(binaryInput == null) + if(binaryInput == null || binaryInput.available() == 0) { return null; - + } + + Object obj = null; + ObjectInputStream in = new ObjectInputStream(binaryInput); - Object obj = in.readObject(); - in.close(); + try { + obj = in.readObject(); + } finally { + in.close(); + } return obj; } - protected Object getJobDetailFromBlob(ResultSet rs, String colName) - throws ClassNotFoundException, IOException, SQLException { + @Override + protected Object getJobDataFromBlob(ResultSet rs, String colName) + throws ClassNotFoundException, IOException, SQLException { if (canUseProperties()) { InputStream binaryInput = rs.getBinaryStream(colName); return binaryInput; Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/NoSuchDelegateException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/NoSuchDelegateException.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/NoSuchDelegateException.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/NoSuchDelegateException.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; import org.quartz.JobPersistenceException; @@ -31,6 +28,9 @@ * @author Jeffrey Wescott */ public class NoSuchDelegateException extends JobPersistenceException { + + private static final long serialVersionUID = -4255865028975822979L; + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -42,6 +42,10 @@ public NoSuchDelegateException(String msg) { super(msg); } + + public NoSuchDelegateException(String msg, Throwable cause) { + super(msg, cause); + } } // EOF Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/PointbaseDelegate.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/PointbaseDelegate.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/PointbaseDelegate.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/PointbaseDelegate.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; import java.io.ByteArrayInputStream; @@ -31,12 +28,11 @@ import java.sql.ResultSet; import java.sql.SQLException; -import org.apache.commons.logging.Log; import org.quartz.Calendar; -import org.quartz.CronTrigger; import org.quartz.JobDetail; -import org.quartz.SimpleTrigger; -import org.quartz.Trigger; +import org.quartz.spi.ClassLoadHelper; +import org.quartz.spi.OperableTrigger; +import org.slf4j.Logger; /** *

@@ -47,37 +43,6 @@ */ public class PointbaseDelegate extends StdJDBCDelegate { - //private static Category log = - // Category.getInstance(PointbaseJDBCDelegate.class); - /** - *

- * Create new PointbaseJDBCDelegate instance. - *

- * - * @param logger - * the logger to use during execution - * @param tablePrefix - * the prefix of all table names - */ - public PointbaseDelegate(Log logger, String tablePrefix, String instanceId) { - super(logger, tablePrefix, instanceId); - } - - /** - *

- * Create new PointbaseJDBCDelegate instance. - *

- * - * @param logger - * the logger to use during execution - * @param tablePrefix - * the prefix of all table names - */ - public PointbaseDelegate(Log logger, String tablePrefix, String instanceId, - Boolean useProperties) { - super(logger, tablePrefix, instanceId, useProperties); - } - //--------------------------------------------------------------------------- // jobs //--------------------------------------------------------------------------- @@ -95,8 +60,9 @@ * @throws IOException * if there were problems serializing the JobDataMap */ + @Override public int insertJobDetail(Connection conn, JobDetail job) - throws IOException, SQLException { + throws IOException, SQLException { //log.debug( "Inserting JobDetail " + job ); ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap()); int len = baos.toByteArray().length; @@ -108,32 +74,21 @@ try { ps = conn.prepareStatement(rtp(INSERT_JOB_DETAIL)); - ps.setString(1, job.getName()); - ps.setString(2, job.getGroup()); + ps.setString(1, job.getKey().getName()); + ps.setString(2, job.getKey().getGroup()); ps.setString(3, job.getDescription()); ps.setString(4, job.getJobClass().getName()); - ps.setBoolean(5, job.isDurable()); - ps.setBoolean(6, job.isVolatile()); - ps.setBoolean(7, job.isStateful()); - ps.setBoolean(8, job.requestsRecovery()); + setBoolean(ps, 5, job.isDurable()); + setBoolean(ps, 6, job.isConcurrentExectionDisallowed()); + setBoolean(ps, 7, job.isPersistJobDataAfterExecution()); + setBoolean(ps, 8, job.requestsRecovery()); ps.setBinaryStream(9, bais, len); insertResult = ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } - if (insertResult > 0) { - String[] jobListeners = job.getJobListenerNames(); - for (int i = 0; jobListeners != null && i < jobListeners.length; i++) - insertJobListener(conn, job, jobListeners[i]); - } - return insertResult; } @@ -150,8 +105,9 @@ * @throws IOException * if there were problems serializing the JobDataMap */ + @Override public int updateJobDetail(Connection conn, JobDetail job) - throws IOException, SQLException { + throws IOException, SQLException { //log.debug( "Updating job detail " + job ); ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap()); int len = baos.toByteArray().length; @@ -165,36 +121,24 @@ ps = conn.prepareStatement(rtp(UPDATE_JOB_DETAIL)); ps.setString(1, job.getDescription()); ps.setString(2, job.getJobClass().getName()); - ps.setBoolean(3, job.isDurable()); - ps.setBoolean(4, job.isVolatile()); - ps.setBoolean(5, job.isStateful()); - ps.setBoolean(6, job.requestsRecovery()); + setBoolean(ps, 3, job.isDurable()); + setBoolean(ps, 4, job.isConcurrentExectionDisallowed()); + setBoolean(ps, 5, job.isPersistJobDataAfterExecution()); + setBoolean(ps, 6, job.requestsRecovery()); ps.setBinaryStream(7, bais, len); - ps.setString(8, job.getName()); - ps.setString(9, job.getGroup()); + ps.setString(8, job.getKey().getName()); + ps.setString(9, job.getKey().getGroup()); insertResult = ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } - if (insertResult > 0) { - deleteJobListeners(conn, job.getName(), job.getGroup()); - - String[] jobListeners = job.getJobListenerNames(); - for (int i = 0; jobListeners != null && i < jobListeners.length; i++) - insertJobListener(conn, job, jobListeners[i]); - } - return insertResult; } - public int insertTrigger(Connection conn, Trigger trigger, String state, + @Override + public int insertTrigger(Connection conn, OperableTrigger trigger, String state, JobDetail jobDetail) throws SQLException, IOException { ByteArrayOutputStream baos = serializeJobData(trigger.getJobDataMap()); @@ -207,58 +151,55 @@ try { ps = conn.prepareStatement(rtp(INSERT_TRIGGER)); - ps.setString(1, trigger.getName()); - ps.setString(2, trigger.getGroup()); - ps.setString(3, trigger.getJobName()); - ps.setString(4, trigger.getJobGroup()); - ps.setBoolean(5, trigger.isVolatile()); - ps.setString(6, trigger.getDescription()); - ps.setBigDecimal(7, new BigDecimal(String.valueOf(trigger + ps.setString(1, trigger.getKey().getName()); + ps.setString(2, trigger.getKey().getGroup()); + ps.setString(3, trigger.getJobKey().getName()); + ps.setString(4, trigger.getJobKey().getGroup()); + ps.setString(5, trigger.getDescription()); + ps.setBigDecimal(6, new BigDecimal(String.valueOf(trigger .getNextFireTime().getTime()))); long prevFireTime = -1; if (trigger.getPreviousFireTime() != null) { prevFireTime = trigger.getPreviousFireTime().getTime(); } - ps.setBigDecimal(8, new BigDecimal(String.valueOf(prevFireTime))); - ps.setString(9, state); - if (trigger instanceof SimpleTrigger) { - ps.setString(10, TTYPE_SIMPLE); - } else if (trigger instanceof CronTrigger) { - ps.setString(10, TTYPE_CRON); - } else { // (trigger instanceof BlobTrigger) - ps.setString(10, TTYPE_BLOB); - } - ps.setBigDecimal(11, new BigDecimal(String.valueOf(trigger + ps.setBigDecimal(7, new BigDecimal(String.valueOf(prevFireTime))); + ps.setString(8, state); + + TriggerPersistenceDelegate tDel = findTriggerPersistenceDelegate(trigger); + + String type = TTYPE_BLOB; + if(tDel != null) + type = tDel.getHandledTriggerTypeDiscriminator(); + ps.setString(9, type); + + ps.setBigDecimal(10, new BigDecimal(String.valueOf(trigger .getStartTime().getTime()))); long endTime = 0; if (trigger.getEndTime() != null) { endTime = trigger.getEndTime().getTime(); } - ps.setBigDecimal(12, new BigDecimal(String.valueOf(endTime))); - ps.setString(13, trigger.getCalendarName()); - ps.setInt(14, trigger.getMisfireInstruction()); - ps.setBinaryStream(15, bais, len); + ps.setBigDecimal(11, new BigDecimal(String.valueOf(endTime))); + ps.setString(12, trigger.getCalendarName()); + ps.setInt(13, trigger.getMisfireInstruction()); + ps.setBinaryStream(14, bais, len); + ps.setInt(15, trigger.getPriority()); insertResult = ps.executeUpdate(); + + if(tDel == null) + insertBlobTrigger(conn, trigger); + else + tDel.insertExtendedTriggerProperties(conn, trigger, state, jobDetail); + } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } - if (insertResult > 0) { - String[] trigListeners = trigger.getTriggerListenerNames(); - for (int i = 0; trigListeners != null && i < trigListeners.length; i++) - insertTriggerListener(conn, trigger, trigListeners[i]); - } - return insertResult; } - public int updateTrigger(Connection conn, Trigger trigger, String state, + @Override + public int updateTrigger(Connection conn, OperableTrigger trigger, String state, JobDetail jobDetail) throws SQLException, IOException { ByteArrayOutputStream baos = serializeJobData(trigger.getJobDataMap()); @@ -273,62 +214,55 @@ try { ps = conn.prepareStatement(rtp(UPDATE_TRIGGER)); - ps.setString(1, trigger.getJobName()); - ps.setString(2, trigger.getJobGroup()); - ps.setBoolean(3, trigger.isVolatile()); - ps.setString(4, trigger.getDescription()); + ps.setString(1, trigger.getJobKey().getName()); + ps.setString(2, trigger.getJobKey().getGroup()); + ps.setString(3, trigger.getDescription()); long nextFireTime = -1; if (trigger.getNextFireTime() != null) { nextFireTime = trigger.getNextFireTime().getTime(); } - ps.setBigDecimal(5, new BigDecimal(String.valueOf(nextFireTime))); + ps.setBigDecimal(4, new BigDecimal(String.valueOf(nextFireTime))); long prevFireTime = -1; if (trigger.getPreviousFireTime() != null) { prevFireTime = trigger.getPreviousFireTime().getTime(); } - ps.setBigDecimal(6, new BigDecimal(String.valueOf(prevFireTime))); - ps.setString(7, state); - if (trigger instanceof SimpleTrigger) { - // updateSimpleTrigger(conn, (SimpleTrigger)trigger); - ps.setString(8, TTYPE_SIMPLE); - } else if (trigger instanceof CronTrigger) { - // updateCronTrigger(conn, (CronTrigger)trigger); - ps.setString(8, TTYPE_CRON); - } else { - // updateBlobTrigger(conn, trigger); - ps.setString(8, TTYPE_BLOB); - } - ps.setBigDecimal(9, new BigDecimal(String.valueOf(trigger + ps.setBigDecimal(5, new BigDecimal(String.valueOf(prevFireTime))); + ps.setString(6, state); + + TriggerPersistenceDelegate tDel = findTriggerPersistenceDelegate(trigger); + + String type = TTYPE_BLOB; + if(tDel != null) + type = tDel.getHandledTriggerTypeDiscriminator(); + + ps.setString(7, type); + + ps.setBigDecimal(8, new BigDecimal(String.valueOf(trigger .getStartTime().getTime()))); long endTime = 0; if (trigger.getEndTime() != null) { endTime = trigger.getEndTime().getTime(); } - ps.setBigDecimal(10, new BigDecimal(String.valueOf(endTime))); - ps.setString(11, trigger.getCalendarName()); - ps.setInt(12, trigger.getMisfireInstruction()); + ps.setBigDecimal(9, new BigDecimal(String.valueOf(endTime))); + ps.setString(10, trigger.getCalendarName()); + ps.setInt(11, trigger.getMisfireInstruction()); + + ps.setInt(12, trigger.getPriority()); ps.setBinaryStream(13, bais, len); - ps.setString(14, trigger.getName()); - ps.setString(15, trigger.getGroup()); + ps.setString(14, trigger.getKey().getName()); + ps.setString(15, trigger.getKey().getGroup()); insertResult = ps.executeUpdate(); + + if(tDel == null) + updateBlobTrigger(conn, trigger); + else + tDel.updateExtendedTriggerProperties(conn, trigger, state, jobDetail); + } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } - if (insertResult > 0) { - deleteTriggerListeners(conn, trigger.getName(), trigger.getGroup()); - - String[] trigListeners = trigger.getTriggerListenerNames(); - for (int i = 0; trigListeners != null && i < trigListeners.length; i++) - insertTriggerListener(conn, trigger, trigListeners[i]); - } - return insertResult; } @@ -343,8 +277,9 @@ * the job to update * @return the number of rows updated */ + @Override public int updateJobData(Connection conn, JobDetail job) - throws IOException, SQLException { + throws IOException, SQLException { //log.debug( "Updating Job Data for Job " + job ); ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap()); int len = baos.toByteArray().length; @@ -354,17 +289,12 @@ try { ps = conn.prepareStatement(rtp(UPDATE_JOB_DATA)); ps.setBinaryStream(1, bais, len); - ps.setString(2, job.getName()); - ps.setString(3, job.getGroup()); + ps.setString(2, job.getKey().getName()); + ps.setString(3, job.getKey().getGroup()); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } @@ -391,6 +321,7 @@ * @throws IOException * if there were problems serializing the calendar */ + @Override public int insertCalendar(Connection conn, String calendarName, Calendar calendar) throws IOException, SQLException { //log.debug( "Inserting Calendar " + calendarName + " : " + calendar @@ -408,12 +339,7 @@ return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } @@ -432,6 +358,7 @@ * @throws IOException * if there were problems serializing the calendar */ + @Override public int updateCalendar(Connection conn, String calendarName, Calendar calendar) throws IOException, SQLException { //log.debug( "Updating calendar " + calendarName + " : " + calendar ); @@ -448,12 +375,7 @@ return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } @@ -478,19 +400,23 @@ * @throws IOException * if deserialization causes an error */ + @Override protected Object getObjectFromBlob(ResultSet rs, String colName) - throws ClassNotFoundException, IOException, SQLException { + throws ClassNotFoundException, IOException, SQLException { //log.debug( "Getting blob from column: " + colName ); Object obj = null; byte binaryData[] = rs.getBytes(colName); InputStream binaryInput = new ByteArrayInputStream(binaryData); - if (null != binaryInput) { + if (null != binaryInput && binaryInput.available() != 0) { ObjectInputStream in = new ObjectInputStream(binaryInput); - obj = in.readObject(); - in.close(); + try { + obj = in.readObject(); + } finally { + in.close(); + } } return obj; @@ -513,13 +439,15 @@ * @throws IOException * if deserialization causes an error */ - protected Object getJobDetailFromBlob(ResultSet rs, String colName) - throws ClassNotFoundException, IOException, SQLException { + @Override + protected Object getJobDataFromBlob(ResultSet rs, String colName) + throws ClassNotFoundException, IOException, SQLException { //log.debug( "Getting Job details from blob in col " + colName ); if (canUseProperties()) { byte data[] = rs.getBytes(colName); - if(data == null) + if(data == null) { return null; + } InputStream binaryInput = new ByteArrayInputStream(data); return binaryInput; } Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/PostgreSQLDelegate.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/PostgreSQLDelegate.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/PostgreSQLDelegate.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/PostgreSQLDelegate.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; import java.io.ByteArrayInputStream; @@ -27,7 +24,8 @@ import java.sql.ResultSet; import java.sql.SQLException; -import org.apache.commons.logging.Log; +import org.quartz.spi.ClassLoadHelper; +import org.slf4j.Logger; /** *

@@ -37,37 +35,7 @@ * @author Jeffrey Wescott */ public class PostgreSQLDelegate extends StdJDBCDelegate { - /** - *

- * Create new PostgreSQLDelegate instance. - *

- * - * @param logger - * the logger to use during execution - * @param tablePrefix - * the prefix of all table names - */ - public PostgreSQLDelegate(Log log, String tablePrefix, String instanceId) { - super(log, tablePrefix, instanceId); - } - /** - *

- * Create new PostgreSQLDelegate instance. - *

- * - * @param logger - * the logger to use during execution - * @param tablePrefix - * the prefix of all table names - * @param useProperties - * use java.util.Properties for storage - */ - public PostgreSQLDelegate(Log log, String tablePrefix, String instanceId, - Boolean useProperties) { - super(log, tablePrefix, instanceId, useProperties); - } - //--------------------------------------------------------------------------- // protected methods that can be overridden by subclasses //--------------------------------------------------------------------------- @@ -89,31 +57,38 @@ * @throws IOException * if deserialization causes an error */ + @Override protected Object getObjectFromBlob(ResultSet rs, String colName) - throws ClassNotFoundException, IOException, SQLException { + throws ClassNotFoundException, IOException, SQLException { InputStream binaryInput = null; byte[] bytes = rs.getBytes(colName); Object obj = null; - if(bytes != null) { + if(bytes != null && bytes.length != 0) { binaryInput = new ByteArrayInputStream(bytes); ObjectInputStream in = new ObjectInputStream(binaryInput); - obj = in.readObject(); - in.close(); + try { + obj = in.readObject(); + } finally { + in.close(); + } + } return obj; } - protected Object getJobDetailFromBlob(ResultSet rs, String colName) - throws ClassNotFoundException, IOException, SQLException { + @Override + protected Object getJobDataFromBlob(ResultSet rs, String colName) + throws ClassNotFoundException, IOException, SQLException { if (canUseProperties()) { InputStream binaryInput = null; byte[] bytes = rs.getBytes(colName); - if(bytes == null || bytes.length == 0) + if(bytes == null || bytes.length == 0) { return null; + } binaryInput = new ByteArrayInputStream(bytes); return binaryInput; } Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/SchedulerStateRecord.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/SchedulerStateRecord.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/SchedulerStateRecord.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/SchedulerStateRecord.java 15 Dec 2014 10:09:49 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; /** @@ -29,6 +26,8 @@ */ public class SchedulerStateRecord implements java.io.Serializable { + private static final long serialVersionUID = -715704959016191445L; + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -43,8 +42,6 @@ private long checkinInterval; - private String recoverer; - /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -67,12 +64,6 @@ /** */ - public String getRecoverer() { - return recoverer; - } - - /** - */ public String getSchedulerInstanceId() { return schedulerInstanceId; } @@ -91,12 +82,6 @@ /** */ - public void setRecoverer(String string) { - recoverer = string; - } - - /** - */ public void setSchedulerInstanceId(String string) { schedulerInstanceId = string; } Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/Semaphore.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/Semaphore.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/Semaphore.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/Semaphore.java 15 Dec 2014 10:09:49 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; import java.sql.Connection; @@ -42,6 +39,9 @@ * Grants a lock on the identified resource to the calling thread (blocking * until it is available). * + * @param conn Database connection used to establish lock. Can be null if + * {@link #requiresConnection()} returns false. + * * @return true if the lock was obtained. */ boolean obtainLock(Connection conn, String lockName) throws LockException; @@ -50,12 +50,14 @@ * Release the lock on the identified resource if it is held by the calling * thread. */ - void releaseLock(Connection conn, String lockName) throws LockException; + void releaseLock(String lockName) throws LockException; /** - * Determine whether the calling thread owns a lock on the identified - * resource. + * Whether this Semaphore implementation requires a database connection for + * its lock management operations. + * + * @see #obtainLock(Connection, String) + * @see #releaseLock(String) */ - boolean isLockOwner(Connection conn, String lockName) throws LockException; - + boolean requiresConnection(); } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/SimplePropertiesTriggerPersistenceDelegateSupport.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/SimplePropertiesTriggerProperties.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/SimpleSemaphore.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/SimpleSemaphore.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/SimpleSemaphore.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/SimpleSemaphore.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,21 +15,18 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; import java.sql.Connection; import java.util.HashSet; -import java.util.List; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - * An interface for providing thread/resource locking in order to protect - * resources from being altered by multiple threads at the same time. + * Internal in-memory lock handler for providing thread/resource locking in + * order to protect resources from being altered by multiple threads at the + * same time. * * @author jhouse */ @@ -43,10 +40,12 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - ThreadLocal lockOwners = new ThreadLocal(); + ThreadLocal> lockOwners = new ThreadLocal>(); - HashSet locks = new HashSet(); + HashSet locks = new HashSet(); + private final Logger log = LoggerFactory.getLogger(getClass()); + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -55,15 +54,14 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - Log getLog() { - return LogFactory.getLog(getClass()); - //return LogFactory.getLog("LOCK:"+Thread.currentThread().getName()); + protected Logger getLog() { + return log; } - private HashSet getThreadLocks() { - HashSet threadLocks = (HashSet) lockOwners.get(); + private HashSet getThreadLocks() { + HashSet threadLocks = lockOwners.get(); if (threadLocks == null) { - threadLocks = new HashSet(); + threadLocks = new HashSet(); lockOwners.set(threadLocks); } return threadLocks; @@ -79,42 +77,44 @@ lockName = lockName.intern(); - Log log = getLog(); - - if(log.isDebugEnabled()) + if(log.isDebugEnabled()) { log.debug( "Lock '" + lockName + "' is desired by: " + Thread.currentThread().getName()); + } - if (!isLockOwner(conn, lockName)) { - if(log.isDebugEnabled()) + if (!isLockOwner(lockName)) { + if(log.isDebugEnabled()) { log.debug( "Lock '" + lockName + "' is being obtained: " + Thread.currentThread().getName()); + } while (locks.contains(lockName)) { try { this.wait(); } catch (InterruptedException ie) { - if(log.isDebugEnabled()) + if(log.isDebugEnabled()) { log.debug( "Lock '" + lockName + "' was not obtained by: " + Thread.currentThread().getName()); + } } } - if(log.isDebugEnabled()) + if(log.isDebugEnabled()) { log.debug( "Lock '" + lockName + "' given to: " + Thread.currentThread().getName()); + } getThreadLocks().add(lockName); locks.add(lockName); - } else - if(log.isDebugEnabled()) - log.debug( - "Lock '" + lockName + "' already owned by: " - + Thread.currentThread().getName() - + " -- but not owner!", - new Exception("stack-trace of wrongful returner")); + } else if(log.isDebugEnabled()) { + log.debug( + "Lock '" + lockName + "' already owned by: " + + Thread.currentThread().getName() + + " -- but not owner!", + new Exception("stack-trace of wrongful returner")); + } return true; } @@ -123,40 +123,43 @@ * Release the lock on the identified resource if it is held by the calling * thread. */ - public synchronized void releaseLock(Connection conn, String lockName) { + public synchronized void releaseLock(String lockName) { lockName = lockName.intern(); - if (isLockOwner(conn, lockName)) { - if(getLog().isDebugEnabled()) + if (isLockOwner(lockName)) { + if(getLog().isDebugEnabled()) { getLog().debug( "Lock '" + lockName + "' retuned by: " + Thread.currentThread().getName()); + } getThreadLocks().remove(lockName); locks.remove(lockName); - this.notify(); - } else - if(getLog().isDebugEnabled()) - getLog().debug( - "Lock '" + lockName + "' attempt to retun by: " - + Thread.currentThread().getName() - + " -- but not owner!", - new Exception("stack-trace of wrongful returner")); + this.notifyAll(); + } else if (getLog().isDebugEnabled()) { + getLog().debug( + "Lock '" + lockName + "' attempt to retun by: " + + Thread.currentThread().getName() + + " -- but not owner!", + new Exception("stack-trace of wrongful returner")); + } } /** * Determine whether the calling thread owns a lock on the identified * resource. */ - public synchronized boolean isLockOwner(Connection conn, String lockName) { + public synchronized boolean isLockOwner(String lockName) { lockName = lockName.intern(); return getThreadLocks().contains(lockName); } - public void init(Connection conn, List listOfLocks) { - // nothing to do... + /** + * This Semaphore implementation does not use the database. + */ + public boolean requiresConnection() { + return false; } - } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/SimpleTriggerPersistenceDelegate.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/StdJDBCConstants.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/StdJDBCConstants.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/StdJDBCConstants.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/StdJDBCConstants.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,12 +15,10 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ - package org.quartz.impl.jdbcjobstore; +import org.quartz.Trigger; + /** *

* This interface extends {@link @@ -43,539 +41,630 @@ */ // table prefix substitution string - public static final String TABLE_PREFIX_SUBST = "{0}"; + String TABLE_PREFIX_SUBST = "{0}"; + // table prefix substitution string + String SCHED_NAME_SUBST = "{1}"; + // QUERIES - public static final String UPDATE_TRIGGER_STATES_FROM_OTHER_STATES = "UPDATE " + String UPDATE_TRIGGER_STATES_FROM_OTHER_STATES = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " SET " + COL_TRIGGER_STATE + " = ?" + " WHERE " + + COL_SCHEDULER_NAME + + " = " + SCHED_NAME_SUBST + " AND (" + COL_TRIGGER_STATE + " = ? OR " - + COL_TRIGGER_STATE + " = ?"; + + COL_TRIGGER_STATE + " = ?)"; - public static final String UPDATE_TRIGGER_STATE_FROM_OTHER_STATES_BEFORE_TIME = "UPDATE " - + TABLE_PREFIX_SUBST - + TABLE_TRIGGERS - + " SET " - + COL_TRIGGER_STATE - + " = ?" - + " WHERE (" - + COL_TRIGGER_STATE - + " = ? OR " - + COL_TRIGGER_STATE + " = ?) AND " + COL_NEXT_FIRE_TIME + " < ?"; - - public static final String SELECT_MISFIRED_TRIGGERS = "SELECT * FROM " - + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " - + COL_NEXT_FIRE_TIME + " < ? ORDER BY START_TIME ASC"; - - public static final String SELECT_TRIGGERS_IN_STATE = "SELECT " + String SELECT_MISFIRED_TRIGGERS = "SELECT * FROM " + + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND NOT (" + + COL_MISFIRE_INSTRUCTION + " = " + Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY + ") AND " + + COL_NEXT_FIRE_TIME + " < ? " + + "ORDER BY " + COL_NEXT_FIRE_TIME + " ASC, " + COL_PRIORITY + " DESC"; + + String SELECT_TRIGGERS_IN_STATE = "SELECT " + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + " FROM " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + " AND " + COL_TRIGGER_STATE + " = ?"; - public static final String SELECT_MISFIRED_TRIGGERS_IN_STATE = "SELECT " - + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + " FROM " - + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " - + COL_NEXT_FIRE_TIME + " < ? AND " + COL_TRIGGER_STATE + " = ?"; + String SELECT_MISFIRED_TRIGGERS_IN_STATE = "SELECT " + + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + " FROM " + + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + " AND NOT (" + + COL_MISFIRE_INSTRUCTION + " = " + Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY + ") AND " + + COL_NEXT_FIRE_TIME + " < ? AND " + COL_TRIGGER_STATE + " = ? " + + "ORDER BY " + COL_NEXT_FIRE_TIME + " ASC, " + COL_PRIORITY + " DESC"; - public static final String SELECT_MISFIRED_TRIGGERS_IN_GROUP_IN_STATE = "SELECT " - + COL_TRIGGER_NAME - + " FROM " - + TABLE_PREFIX_SUBST - + TABLE_TRIGGERS - + " WHERE " - + COL_NEXT_FIRE_TIME - + " < ? AND " - + COL_TRIGGER_GROUP - + " = ? AND " + COL_TRIGGER_STATE + " = ?"; + String COUNT_MISFIRED_TRIGGERS_IN_STATE = "SELECT COUNT(" + + COL_TRIGGER_NAME + ") FROM " + + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + " AND NOT (" + + COL_MISFIRE_INSTRUCTION + " = " + Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY + ") AND " + + COL_NEXT_FIRE_TIME + " < ? " + + "AND " + COL_TRIGGER_STATE + " = ?"; + + String SELECT_HAS_MISFIRED_TRIGGERS_IN_STATE = "SELECT " + + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + " FROM " + + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + " AND NOT (" + + COL_MISFIRE_INSTRUCTION + " = " + Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY + ") AND " + + COL_NEXT_FIRE_TIME + " < ? " + + "AND " + COL_TRIGGER_STATE + " = ? " + + "ORDER BY " + COL_NEXT_FIRE_TIME + " ASC, " + COL_PRIORITY + " DESC"; - public static final String SELECT_VOLATILE_TRIGGERS = "SELECT " - + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + " FROM " - + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " + COL_IS_VOLATILE - + " = ?"; + String SELECT_MISFIRED_TRIGGERS_IN_GROUP_IN_STATE = "SELECT " + + COL_TRIGGER_NAME + + " FROM " + + TABLE_PREFIX_SUBST + + TABLE_TRIGGERS + + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + " AND NOT (" + + COL_MISFIRE_INSTRUCTION + " = " + Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY + ") AND " + + COL_NEXT_FIRE_TIME + + " < ? AND " + + COL_TRIGGER_GROUP + + " = ? AND " + COL_TRIGGER_STATE + " = ? " + + "ORDER BY " + COL_NEXT_FIRE_TIME + " ASC, " + COL_PRIORITY + " DESC"; - public static final String DELETE_FIRED_TRIGGERS = "DELETE FROM " - + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS; - public static final String INSERT_JOB_DETAIL = "INSERT INTO " - + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + " (" + COL_JOB_NAME + String DELETE_FIRED_TRIGGERS = "DELETE FROM " + + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; + + String INSERT_JOB_DETAIL = "INSERT INTO " + + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + " (" + + COL_SCHEDULER_NAME + ", " + COL_JOB_NAME + ", " + COL_JOB_GROUP + ", " + COL_DESCRIPTION + ", " - + COL_JOB_CLASS + ", " + COL_IS_DURABLE + ", " + COL_IS_VOLATILE - + ", " + COL_IS_STATEFUL + ", " + COL_REQUESTS_RECOVERY + ", " - + COL_JOB_DATAMAP + ") " + " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + COL_JOB_CLASS + ", " + COL_IS_DURABLE + ", " + + COL_IS_NONCONCURRENT + ", " + COL_IS_UPDATE_DATA + ", " + + COL_REQUESTS_RECOVERY + ", " + + COL_JOB_DATAMAP + ") " + " VALUES(" + SCHED_NAME_SUBST + ", ?, ?, ?, ?, ?, ?, ?, ?, ?)"; - public static final String UPDATE_JOB_DETAIL = "UPDATE " + String UPDATE_JOB_DETAIL = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + " SET " + COL_DESCRIPTION + " = ?, " + COL_JOB_CLASS + " = ?, " - + COL_IS_DURABLE + " = ?, " + COL_IS_VOLATILE + " = ?, " - + COL_IS_STATEFUL + " = ?, " + COL_REQUESTS_RECOVERY + " = ?, " - + COL_JOB_DATAMAP + " = ? " + " WHERE " + COL_JOB_NAME + + COL_IS_DURABLE + " = ?, " + + COL_IS_NONCONCURRENT + " = ?, " + COL_IS_UPDATE_DATA + " = ?, " + + COL_REQUESTS_RECOVERY + " = ?, " + + COL_JOB_DATAMAP + " = ? " + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_JOB_NAME + " = ? AND " + COL_JOB_GROUP + " = ?"; - public static final String SELECT_TRIGGERS_FOR_JOB = "SELECT " + String SELECT_TRIGGERS_FOR_JOB = "SELECT " + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + " FROM " - + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " + COL_JOB_NAME + + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_JOB_NAME + " = ? AND " + COL_JOB_GROUP + " = ?"; - public static final String SELECT_TRIGGERS_FOR_CALENDAR = "SELECT " + String SELECT_TRIGGERS_FOR_CALENDAR = "SELECT " + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + " FROM " - + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " + COL_CALENDAR_NAME + + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_CALENDAR_NAME + " = ?"; - public static final String SELECT_STATEFUL_JOBS_OF_TRIGGER_GROUP = "SELECT DISTINCT J." - + COL_JOB_NAME - + ", J." - + COL_JOB_GROUP - + " FROM " - + TABLE_PREFIX_SUBST - + TABLE_TRIGGERS - + " T, " - + TABLE_PREFIX_SUBST - + TABLE_JOB_DETAILS - + " J WHERE T." - + COL_TRIGGER_GROUP - + " = ? AND T." - + COL_JOB_NAME - + " = J." - + COL_JOB_NAME - + " AND T." - + COL_JOB_GROUP - + " = J." - + COL_JOB_GROUP - + " AND J." - + COL_IS_STATEFUL + " = ?"; + String DELETE_JOB_DETAIL = "DELETE FROM " + + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_JOB_NAME + + " = ? AND " + COL_JOB_GROUP + " = ?"; - public static final String DELETE_JOB_LISTENERS = "DELETE FROM " - + TABLE_PREFIX_SUBST + TABLE_JOB_LISTENERS + " WHERE " - + COL_JOB_NAME + " = ? AND " + COL_JOB_GROUP + " = ?"; - - public static final String DELETE_JOB_DETAIL = "DELETE FROM " - + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + " WHERE " + COL_JOB_NAME + String SELECT_JOB_NONCONCURRENT = "SELECT " + + COL_IS_NONCONCURRENT + " FROM " + TABLE_PREFIX_SUBST + + TABLE_JOB_DETAILS + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_JOB_NAME + " = ? AND " + COL_JOB_GROUP + " = ?"; - public static final String SELECT_JOB_STATEFUL = "SELECT " - + COL_IS_STATEFUL + " FROM " + TABLE_PREFIX_SUBST - + TABLE_JOB_DETAILS + " WHERE " + COL_JOB_NAME + " = ? AND " - + COL_JOB_GROUP + " = ?"; - - public static final String SELECT_JOB_EXISTENCE = "SELECT " + COL_JOB_NAME + String SELECT_JOB_EXISTENCE = "SELECT " + COL_JOB_NAME + " FROM " + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + " WHERE " - + COL_JOB_NAME + " = ? AND " + COL_JOB_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_JOB_NAME + + " = ? AND " + COL_JOB_GROUP + " = ?"; - public static final String UPDATE_JOB_DATA = "UPDATE " + TABLE_PREFIX_SUBST + String UPDATE_JOB_DATA = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + " SET " + COL_JOB_DATAMAP + " = ? " - + " WHERE " + COL_JOB_NAME + " = ? AND " + COL_JOB_GROUP + " = ?"; + + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_JOB_NAME + + " = ? AND " + COL_JOB_GROUP + " = ?"; - public static final String INSERT_JOB_LISTENER = "INSERT INTO " - + TABLE_PREFIX_SUBST + TABLE_JOB_LISTENERS + " (" + COL_JOB_NAME - + ", " + COL_JOB_GROUP + ", " + COL_JOB_LISTENER - + ") VALUES(?, ?, ?)"; - - public static final String SELECT_JOB_LISTENERS = "SELECT " - + COL_JOB_LISTENER + " FROM " + TABLE_PREFIX_SUBST - + TABLE_JOB_LISTENERS + " WHERE " + COL_JOB_NAME + " = ? AND " - + COL_JOB_GROUP + " = ?"; - - public static final String SELECT_JOB_DETAIL = "SELECT *" + " FROM " - + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + " WHERE " + COL_JOB_NAME + String SELECT_JOB_DETAIL = "SELECT *" + " FROM " + + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_JOB_NAME + " = ? AND " + COL_JOB_GROUP + " = ?"; + - public static final String SELECT_NUM_JOBS = "SELECT COUNT(" + COL_JOB_NAME - + ") " + " FROM " + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS; + String SELECT_NUM_JOBS = "SELECT COUNT(" + COL_JOB_NAME + + ") " + " FROM " + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; - public static final String SELECT_JOB_GROUPS = "SELECT DISTINCT(" + String SELECT_JOB_GROUPS = "SELECT DISTINCT(" + COL_JOB_GROUP + ") FROM " + TABLE_PREFIX_SUBST - + TABLE_JOB_DETAILS; + + TABLE_JOB_DETAILS + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; - public static final String SELECT_JOBS_IN_GROUP = "SELECT " + COL_JOB_NAME + String SELECT_JOBS_IN_GROUP_LIKE = "SELECT " + COL_JOB_NAME + ", " + COL_JOB_GROUP + " FROM " + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + " WHERE " - + COL_JOB_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_JOB_GROUP + " LIKE ?"; - public static final String SELECT_VOLATILE_JOBS = "SELECT " + COL_JOB_NAME - + ", " + COL_JOB_GROUP + " FROM " + TABLE_PREFIX_SUBST - + TABLE_JOB_DETAILS + " WHERE " + COL_IS_VOLATILE + " = ?"; + String SELECT_JOBS_IN_GROUP = "SELECT " + COL_JOB_NAME + ", " + COL_JOB_GROUP + + " FROM " + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_JOB_GROUP + " = ?"; - public static final String INSERT_TRIGGER = "INSERT INTO " - + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " (" + COL_TRIGGER_NAME + String INSERT_TRIGGER = "INSERT INTO " + + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " (" + COL_SCHEDULER_NAME + ", " + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + ", " + COL_JOB_NAME + ", " - + COL_JOB_GROUP + ", " + COL_IS_VOLATILE + ", " + COL_DESCRIPTION + + COL_JOB_GROUP + ", " + COL_DESCRIPTION + ", " + COL_NEXT_FIRE_TIME + ", " + COL_PREV_FIRE_TIME + ", " + COL_TRIGGER_STATE + ", " + COL_TRIGGER_TYPE + ", " + COL_START_TIME + ", " + COL_END_TIME + ", " + COL_CALENDAR_NAME - + ", " + COL_MISFIRE_INSTRUCTION + ", " + COL_JOB_DATAMAP + ") " - + " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + ", " + COL_MISFIRE_INSTRUCTION + ", " + COL_JOB_DATAMAP + ", " + COL_PRIORITY + ") " + + " VALUES(" + SCHED_NAME_SUBST + ", ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; - public static final String INSERT_SIMPLE_TRIGGER = "INSERT INTO " + String INSERT_SIMPLE_TRIGGER = "INSERT INTO " + TABLE_PREFIX_SUBST + TABLE_SIMPLE_TRIGGERS + " (" + + COL_SCHEDULER_NAME + ", " + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + ", " + COL_REPEAT_COUNT + ", " + COL_REPEAT_INTERVAL + ", " - + COL_TIMES_TRIGGERED + ") " + " VALUES(?, ?, ?, ?, ?)"; + + COL_TIMES_TRIGGERED + ") " + " VALUES(" + SCHED_NAME_SUBST + ", ?, ?, ?, ?, ?)"; - public static final String INSERT_CRON_TRIGGER = "INSERT INTO " + String INSERT_CRON_TRIGGER = "INSERT INTO " + TABLE_PREFIX_SUBST + TABLE_CRON_TRIGGERS + " (" + + COL_SCHEDULER_NAME + ", " + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + ", " + COL_CRON_EXPRESSION + ", " + COL_TIME_ZONE_ID + ") " - + " VALUES(?, ?, ?, ?)"; + + " VALUES(" + SCHED_NAME_SUBST + ", ?, ?, ?, ?)"; - public static final String INSERT_BLOB_TRIGGER = "INSERT INTO " + String INSERT_BLOB_TRIGGER = "INSERT INTO " + TABLE_PREFIX_SUBST + TABLE_BLOB_TRIGGERS + " (" + + COL_SCHEDULER_NAME + ", " + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + ", " + COL_BLOB - + ") " + " VALUES(?, ?, ?)"; + + ") " + " VALUES(" + SCHED_NAME_SUBST + ", ?, ?, ?)"; - public static final String UPDATE_TRIGGER_SKIP_DATA = "UPDATE " + TABLE_PREFIX_SUBST + String UPDATE_TRIGGER_SKIP_DATA = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " SET " + COL_JOB_NAME + " = ?, " - + COL_JOB_GROUP + " = ?, " + COL_IS_VOLATILE + " = ?, " + + COL_JOB_GROUP + " = ?, " + COL_DESCRIPTION + " = ?, " + COL_NEXT_FIRE_TIME + " = ?, " + COL_PREV_FIRE_TIME + " = ?, " + COL_TRIGGER_STATE + " = ?, " + COL_TRIGGER_TYPE + " = ?, " + COL_START_TIME + " = ?, " + COL_END_TIME + " = ?, " + COL_CALENDAR_NAME + " = ?, " - + COL_MISFIRE_INSTRUCTION + " = ? WHERE " + COL_TRIGGER_NAME + + COL_MISFIRE_INSTRUCTION + " = ?, " + COL_PRIORITY + + " = ? WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String UPDATE_TRIGGER = "UPDATE " + TABLE_PREFIX_SUBST + String UPDATE_TRIGGER = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " SET " + COL_JOB_NAME + " = ?, " - + COL_JOB_GROUP + " = ?, " + COL_IS_VOLATILE + " = ?, " + + COL_JOB_GROUP + " = ?, " + COL_DESCRIPTION + " = ?, " + COL_NEXT_FIRE_TIME + " = ?, " + COL_PREV_FIRE_TIME + " = ?, " + COL_TRIGGER_STATE + " = ?, " + COL_TRIGGER_TYPE + " = ?, " + COL_START_TIME + " = ?, " + COL_END_TIME + " = ?, " + COL_CALENDAR_NAME + " = ?, " - + COL_MISFIRE_INSTRUCTION + " = ?, " + COL_JOB_DATAMAP + " = ? WHERE " - + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; + + COL_MISFIRE_INSTRUCTION + " = ?, " + COL_PRIORITY + " = ?, " + + COL_JOB_DATAMAP + " = ? WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String UPDATE_SIMPLE_TRIGGER = "UPDATE " + String UPDATE_SIMPLE_TRIGGER = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_SIMPLE_TRIGGERS + " SET " + COL_REPEAT_COUNT + " = ?, " + COL_REPEAT_INTERVAL + " = ?, " - + COL_TIMES_TRIGGERED + " = ? WHERE " + COL_TRIGGER_NAME + + COL_TIMES_TRIGGERED + " = ? WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String UPDATE_CRON_TRIGGER = "UPDATE " + String UPDATE_CRON_TRIGGER = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_CRON_TRIGGERS + " SET " - + COL_CRON_EXPRESSION + " = ? WHERE " + COL_TRIGGER_NAME + + COL_CRON_EXPRESSION + " = ?, " + COL_TIME_ZONE_ID + + " = ? WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String UPDATE_BLOB_TRIGGER = "UPDATE " + String UPDATE_BLOB_TRIGGER = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_BLOB_TRIGGERS + " SET " + COL_BLOB - + " = ? WHERE " + COL_TRIGGER_NAME + " = ? AND " + + " = ? WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String SELECT_TRIGGER_EXISTENCE = "SELECT " + String SELECT_TRIGGER_EXISTENCE = "SELECT " + COL_TRIGGER_NAME + " FROM " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS - + " WHERE " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String UPDATE_TRIGGER_STATE = "UPDATE " + String UPDATE_TRIGGER_STATE = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " SET " + COL_TRIGGER_STATE - + " = ?" + " WHERE " + COL_TRIGGER_NAME + " = ? AND " + + " = ?" + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String UPDATE_TRIGGER_STATE_FROM_STATE = "UPDATE " + String UPDATE_TRIGGER_STATE_FROM_STATE = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " SET " + COL_TRIGGER_STATE - + " = ?" + " WHERE " + COL_TRIGGER_NAME + " = ? AND " + + " = ?" + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ? AND " + COL_TRIGGER_STATE + " = ?"; - public static final String UPDATE_TRIGGER_GROUP_STATE = "UPDATE " - + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " SET " + COL_TRIGGER_STATE - + " = ?"; - - public static final String UPDATE_TRIGGER_GROUP_STATE_FROM_STATE = "UPDATE " + String UPDATE_TRIGGER_GROUP_STATE_FROM_STATE = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " SET " + COL_TRIGGER_STATE + " = ?" + " WHERE " - + COL_TRIGGER_GROUP - + " = ? AND " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_GROUP + + " LIKE ? AND " + COL_TRIGGER_STATE + " = ?"; - public static final String UPDATE_TRIGGER_STATE_FROM_STATES = "UPDATE " + String UPDATE_TRIGGER_STATE_FROM_STATES = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " SET " + COL_TRIGGER_STATE - + " = ?" + " WHERE " + COL_TRIGGER_NAME + " = ? AND " + + " = ?" + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ? AND (" + COL_TRIGGER_STATE + " = ? OR " + COL_TRIGGER_STATE + " = ? OR " + COL_TRIGGER_STATE + " = ?)"; - public static final String UPDATE_TRIGGER_GROUP_STATE_FROM_STATES = "UPDATE " + String UPDATE_TRIGGER_GROUP_STATE_FROM_STATES = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " SET " + COL_TRIGGER_STATE + " = ?" + " WHERE " - + COL_TRIGGER_GROUP - + " = ? AND (" + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_GROUP + + " LIKE ? AND (" + COL_TRIGGER_STATE + " = ? OR " + COL_TRIGGER_STATE + " = ? OR " + COL_TRIGGER_STATE + " = ?)"; - public static final String UPDATE_JOB_TRIGGER_STATES = "UPDATE " + String UPDATE_JOB_TRIGGER_STATES = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " SET " + COL_TRIGGER_STATE - + " = ? WHERE " + COL_JOB_NAME + " = ? AND " + COL_JOB_GROUP + + " = ? WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_JOB_NAME + " = ? AND " + COL_JOB_GROUP + " = ?"; - public static final String UPDATE_JOB_TRIGGER_STATES_FROM_OTHER_STATE = "UPDATE " + String UPDATE_JOB_TRIGGER_STATES_FROM_OTHER_STATE = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " SET " + COL_TRIGGER_STATE + " = ? WHERE " - + COL_JOB_NAME + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_JOB_NAME + " = ? AND " + COL_JOB_GROUP + " = ? AND " + COL_TRIGGER_STATE + " = ?"; - public static final String DELETE_TRIGGER_LISTENERS = "DELETE FROM " - + TABLE_PREFIX_SUBST + TABLE_TRIGGER_LISTENERS + " WHERE " - + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - - public static final String INSERT_TRIGGER_LISTENER = "INSERT INTO " - + TABLE_PREFIX_SUBST + TABLE_TRIGGER_LISTENERS + " (" - + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + ", " - + COL_TRIGGER_LISTENER + ") VALUES(?, ?, ?)"; - - public static final String SELECT_TRIGGER_LISTENERS = "SELECT " - + COL_TRIGGER_LISTENER + " FROM " + TABLE_PREFIX_SUBST - + TABLE_TRIGGER_LISTENERS + " WHERE " + COL_TRIGGER_NAME - + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - - public static final String DELETE_SIMPLE_TRIGGER = "DELETE FROM " + String DELETE_SIMPLE_TRIGGER = "DELETE FROM " + TABLE_PREFIX_SUBST + TABLE_SIMPLE_TRIGGERS + " WHERE " - + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String DELETE_CRON_TRIGGER = "DELETE FROM " + String DELETE_CRON_TRIGGER = "DELETE FROM " + TABLE_PREFIX_SUBST + TABLE_CRON_TRIGGERS + " WHERE " - + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String DELETE_BLOB_TRIGGER = "DELETE FROM " + String DELETE_BLOB_TRIGGER = "DELETE FROM " + TABLE_PREFIX_SUBST + TABLE_BLOB_TRIGGERS + " WHERE " - + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String DELETE_TRIGGER = "DELETE FROM " + String DELETE_TRIGGER = "DELETE FROM " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " - + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String SELECT_NUM_TRIGGERS_FOR_JOB = "SELECT COUNT(" + String SELECT_NUM_TRIGGERS_FOR_JOB = "SELECT COUNT(" + COL_TRIGGER_NAME + ") FROM " + TABLE_PREFIX_SUBST - + TABLE_TRIGGERS + " WHERE " + COL_JOB_NAME + " = ? AND " + + TABLE_TRIGGERS + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_JOB_NAME + " = ? AND " + COL_JOB_GROUP + " = ?"; - public static final String SELECT_JOB_FOR_TRIGGER = "SELECT J." + String SELECT_JOB_FOR_TRIGGER = "SELECT J." + COL_JOB_NAME + ", J." + COL_JOB_GROUP + ", J." + COL_IS_DURABLE + ", J." + COL_JOB_CLASS + ", J." + COL_REQUESTS_RECOVERY + " FROM " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " T, " + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS - + " J WHERE T." + COL_TRIGGER_NAME + " = ? AND T." + + " J WHERE T." + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND J." + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND T." + COL_TRIGGER_NAME + " = ? AND T." + COL_TRIGGER_GROUP + " = ? AND T." + COL_JOB_NAME + " = J." + COL_JOB_NAME + " AND T." + COL_JOB_GROUP + " = J." + COL_JOB_GROUP; - public static final String SELECT_TRIGGER = "SELECT *" + " FROM " + String SELECT_TRIGGER = "SELECT * FROM " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " - + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String SELECT_TRIGGER_DATA = "SELECT " + + String SELECT_TRIGGER_DATA = "SELECT " + COL_JOB_DATAMAP + " FROM " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " - + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String SELECT_TRIGGER_STATE = "SELECT " + String SELECT_TRIGGER_STATE = "SELECT " + COL_TRIGGER_STATE + " FROM " + TABLE_PREFIX_SUBST - + TABLE_TRIGGERS + " WHERE " + COL_TRIGGER_NAME + " = ? AND " + + TABLE_TRIGGERS + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String SELECT_TRIGGER_STATUS = "SELECT " + String SELECT_TRIGGER_STATUS = "SELECT " + COL_TRIGGER_STATE + ", " + COL_NEXT_FIRE_TIME + ", " + COL_JOB_NAME + ", " + COL_JOB_GROUP + " FROM " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " - + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String SELECT_SIMPLE_TRIGGER = "SELECT *" + " FROM " + String SELECT_SIMPLE_TRIGGER = "SELECT *" + " FROM " + TABLE_PREFIX_SUBST + TABLE_SIMPLE_TRIGGERS + " WHERE " - + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String SELECT_CRON_TRIGGER = "SELECT *" + " FROM " + String SELECT_CRON_TRIGGER = "SELECT *" + " FROM " + TABLE_PREFIX_SUBST + TABLE_CRON_TRIGGERS + " WHERE " - + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String SELECT_BLOB_TRIGGER = "SELECT *" + " FROM " + String SELECT_BLOB_TRIGGER = "SELECT *" + " FROM " + TABLE_PREFIX_SUBST + TABLE_BLOB_TRIGGERS + " WHERE " - + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String SELECT_NUM_TRIGGERS = "SELECT COUNT(" + String SELECT_NUM_TRIGGERS = "SELECT COUNT(" + COL_TRIGGER_NAME + ") " + " FROM " + TABLE_PREFIX_SUBST - + TABLE_TRIGGERS; + + TABLE_TRIGGERS + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; - public static final String SELECT_NUM_TRIGGERS_IN_GROUP = "SELECT COUNT(" + String SELECT_NUM_TRIGGERS_IN_GROUP = "SELECT COUNT(" + COL_TRIGGER_NAME + ") " + " FROM " + TABLE_PREFIX_SUBST - + TABLE_TRIGGERS + " WHERE " + COL_TRIGGER_GROUP + " = ?"; + + TABLE_TRIGGERS + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String SELECT_TRIGGER_GROUPS = "SELECT DISTINCT(" + String SELECT_TRIGGER_GROUPS = "SELECT DISTINCT(" + COL_TRIGGER_GROUP + ") FROM " + TABLE_PREFIX_SUBST - + TABLE_TRIGGERS; + + TABLE_TRIGGERS + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; - public static final String SELECT_TRIGGERS_IN_GROUP = "SELECT " - + COL_TRIGGER_NAME + " FROM " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS - + " WHERE " + COL_TRIGGER_GROUP + " = ?"; + String SELECT_TRIGGER_GROUPS_FILTERED = "SELECT DISTINCT(" + + COL_TRIGGER_GROUP + ") FROM " + TABLE_PREFIX_SUBST + + TABLE_TRIGGERS + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + " AND " + COL_TRIGGER_GROUP + " LIKE ?"; - public static final String INSERT_CALENDAR = "INSERT INTO " - + TABLE_PREFIX_SUBST + TABLE_CALENDARS + " (" + COL_CALENDAR_NAME - + ", " + COL_CALENDAR + ") " + " VALUES(?, ?)"; + String SELECT_TRIGGERS_IN_GROUP_LIKE = "SELECT " + + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + " FROM " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_GROUP + " LIKE ?"; - public static final String UPDATE_CALENDAR = "UPDATE " + TABLE_PREFIX_SUBST + String SELECT_TRIGGERS_IN_GROUP = "SELECT " + + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + " FROM " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_GROUP + " = ?"; + + String INSERT_CALENDAR = "INSERT INTO " + + TABLE_PREFIX_SUBST + TABLE_CALENDARS + " (" + COL_SCHEDULER_NAME + ", " + COL_CALENDAR_NAME + + ", " + COL_CALENDAR + ") " + " VALUES(" + SCHED_NAME_SUBST + ", ?, ?)"; + + String UPDATE_CALENDAR = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_CALENDARS + " SET " + COL_CALENDAR + " = ? " + " WHERE " - + COL_CALENDAR_NAME + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_CALENDAR_NAME + " = ?"; - public static final String SELECT_CALENDAR_EXISTENCE = "SELECT " + String SELECT_CALENDAR_EXISTENCE = "SELECT " + COL_CALENDAR_NAME + " FROM " + TABLE_PREFIX_SUBST - + TABLE_CALENDARS + " WHERE " + COL_CALENDAR_NAME + " = ?"; + + TABLE_CALENDARS + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_CALENDAR_NAME + " = ?"; - public static final String SELECT_CALENDAR = "SELECT *" + " FROM " + String SELECT_CALENDAR = "SELECT *" + " FROM " + TABLE_PREFIX_SUBST + TABLE_CALENDARS + " WHERE " - + COL_CALENDAR_NAME + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_CALENDAR_NAME + " = ?"; - public static final String SELECT_REFERENCED_CALENDAR = "SELECT " + String SELECT_REFERENCED_CALENDAR = "SELECT " + COL_CALENDAR_NAME + " FROM " + TABLE_PREFIX_SUBST - + TABLE_TRIGGERS + " WHERE " + COL_CALENDAR_NAME + " = ?"; + + TABLE_TRIGGERS + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_CALENDAR_NAME + " = ?"; - public static final String DELETE_CALENDAR = "DELETE FROM " + String DELETE_CALENDAR = "DELETE FROM " + TABLE_PREFIX_SUBST + TABLE_CALENDARS + " WHERE " - + COL_CALENDAR_NAME + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_CALENDAR_NAME + " = ?"; - public static final String SELECT_NUM_CALENDARS = "SELECT COUNT(" + String SELECT_NUM_CALENDARS = "SELECT COUNT(" + COL_CALENDAR_NAME + ") " + " FROM " + TABLE_PREFIX_SUBST - + TABLE_CALENDARS; + + TABLE_CALENDARS + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; - public static final String SELECT_CALENDARS = "SELECT " + COL_CALENDAR_NAME - + " FROM " + TABLE_PREFIX_SUBST + TABLE_CALENDARS; + String SELECT_CALENDARS = "SELECT " + COL_CALENDAR_NAME + + " FROM " + TABLE_PREFIX_SUBST + TABLE_CALENDARS + + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; - public static final String SELECT_NEXT_FIRE_TIME = "SELECT MIN(" + String SELECT_NEXT_FIRE_TIME = "SELECT MIN(" + COL_NEXT_FIRE_TIME + ") AS " + ALIAS_COL_NEXT_FIRE_TIME + " FROM " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " - + COL_TRIGGER_STATE + " = ? AND " + COL_NEXT_FIRE_TIME + " >= 0"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_STATE + " = ? AND " + COL_NEXT_FIRE_TIME + " >= 0"; - public static final String SELECT_TRIGGER_FOR_FIRE_TIME = "SELECT " + String SELECT_TRIGGER_FOR_FIRE_TIME = "SELECT " + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + " FROM " + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " - + COL_TRIGGER_STATE + " = ? AND " + COL_NEXT_FIRE_TIME + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_STATE + " = ? AND " + COL_NEXT_FIRE_TIME + " = ?"; - public static final String INSERT_FIRED_TRIGGER = "INSERT INTO " - + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + " (" + COL_ENTRY_ID + String SELECT_NEXT_TRIGGER_TO_ACQUIRE = "SELECT " + + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + ", " + + COL_NEXT_FIRE_TIME + ", " + COL_PRIORITY + " FROM " + + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_STATE + " = ? AND " + COL_NEXT_FIRE_TIME + " <= ? " + + "AND (" + COL_MISFIRE_INSTRUCTION + " = -1 OR (" +COL_MISFIRE_INSTRUCTION+ " != -1 AND "+ COL_NEXT_FIRE_TIME + " >= ?)) " + + "ORDER BY "+ COL_NEXT_FIRE_TIME + " ASC, " + COL_PRIORITY + " DESC"; + + + String INSERT_FIRED_TRIGGER = "INSERT INTO " + + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + " (" + COL_SCHEDULER_NAME + ", " + COL_ENTRY_ID + ", " + COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + ", " - + COL_IS_VOLATILE + ", " + COL_INSTANCE_NAME + ", " - + COL_FIRED_TIME + ", " + COL_ENTRY_STATE + ", " + COL_JOB_NAME - + ", " + COL_JOB_GROUP + ", " + COL_IS_STATEFUL + ", " - + COL_REQUESTS_RECOVERY - + ") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + COL_INSTANCE_NAME + ", " + + COL_FIRED_TIME + ", " + COL_SCHED_TIME + ", " + COL_ENTRY_STATE + ", " + COL_JOB_NAME + + ", " + COL_JOB_GROUP + ", " + COL_IS_NONCONCURRENT + ", " + + COL_REQUESTS_RECOVERY + ", " + COL_PRIORITY + + ") VALUES(" + SCHED_NAME_SUBST + ", ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; - public static final String UPDATE_INSTANCES_FIRED_TRIGGER_STATE = "UPDATE " - + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + " SET " - + COL_ENTRY_STATE + " = ? AND " + COL_FIRED_TIME + " = ? WHERE " - + COL_INSTANCE_NAME + " = ?"; + String UPDATE_FIRED_TRIGGER = "UPDATE " + + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + " SET " + + COL_INSTANCE_NAME + " = ?, " + + COL_FIRED_TIME + " = ?, " + COL_SCHED_TIME + " = ?, " + COL_ENTRY_STATE + " = ?, " + COL_JOB_NAME + + " = ?, " + COL_JOB_GROUP + " = ?, " + COL_IS_NONCONCURRENT + " = ?, " + + COL_REQUESTS_RECOVERY + " = ? WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_ENTRY_ID + " = ?"; - public static final String SELECT_INSTANCES_FIRED_TRIGGERS = "SELECT * FROM " + String SELECT_INSTANCES_FIRED_TRIGGERS = "SELECT * FROM " + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + " WHERE " - + COL_INSTANCE_NAME + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_INSTANCE_NAME + " = ?"; - public static final String SELECT_INSTANCES_RECOVERABLE_FIRED_TRIGGERS = "SELECT * FROM " + String SELECT_INSTANCES_RECOVERABLE_FIRED_TRIGGERS = "SELECT * FROM " + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + " WHERE " - + COL_INSTANCE_NAME + " = ? AND " + COL_REQUESTS_RECOVERY + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_INSTANCE_NAME + " = ? AND " + COL_REQUESTS_RECOVERY + " = ?"; - public static final String SELECT_JOB_EXECUTION_COUNT = "SELECT COUNT(" + String SELECT_JOB_EXECUTION_COUNT = "SELECT COUNT(" + COL_TRIGGER_NAME + ") FROM " + TABLE_PREFIX_SUBST - + TABLE_FIRED_TRIGGERS + " WHERE " + COL_JOB_NAME + " = ? AND " + + TABLE_FIRED_TRIGGERS + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_JOB_NAME + " = ? AND " + COL_JOB_GROUP + " = ?"; - public static final String SELECT_FIRED_TRIGGERS = "SELECT * FROM " - + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS; + String SELECT_FIRED_TRIGGERS = "SELECT * FROM " + + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; - public static final String SELECT_FIRED_TRIGGER = "SELECT * FROM " + String SELECT_FIRED_TRIGGER = "SELECT * FROM " + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + " WHERE " - + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_NAME + " = ? AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String SELECT_FIRED_TRIGGER_GROUP = "SELECT * FROM " + String SELECT_FIRED_TRIGGER_GROUP = "SELECT * FROM " + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + " WHERE " - + COL_TRIGGER_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String SELECT_FIRED_TRIGGERS_OF_JOB = "SELECT * FROM " + String SELECT_FIRED_TRIGGERS_OF_JOB = "SELECT * FROM " + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + " WHERE " - + COL_JOB_NAME + " = ? AND " + COL_JOB_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_JOB_NAME + " = ? AND " + COL_JOB_GROUP + " = ?"; - public static final String SELECT_FIRED_TRIGGERS_OF_JOB_GROUP = "SELECT * FROM " + String SELECT_FIRED_TRIGGERS_OF_JOB_GROUP = "SELECT * FROM " + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + " WHERE " - + COL_JOB_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_JOB_GROUP + " = ?"; - public static final String DELETE_FIRED_TRIGGER = "DELETE FROM " + String DELETE_FIRED_TRIGGER = "DELETE FROM " + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + " WHERE " - + COL_ENTRY_ID + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_ENTRY_ID + " = ?"; - public static final String DELETE_INSTANCES_FIRED_TRIGGERS = "DELETE FROM " + String DELETE_INSTANCES_FIRED_TRIGGERS = "DELETE FROM " + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + " WHERE " - + COL_INSTANCE_NAME + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_INSTANCE_NAME + " = ?"; - public static final String DELETE_VOLATILE_FIRED_TRIGGERS = "DELETE FROM " - + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + " WHERE " - + COL_IS_VOLATILE + " = ?"; - - public static final String DELETE_NO_RECOVERY_FIRED_TRIGGERS = "DELETE FROM " + String DELETE_NO_RECOVERY_FIRED_TRIGGERS = "DELETE FROM " + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + " WHERE " - + COL_INSTANCE_NAME + " = ?" + COL_REQUESTS_RECOVERY + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_INSTANCE_NAME + " = ?" + COL_REQUESTS_RECOVERY + " = ?"; - public static final String INSERT_SCHEDULER_STATE = "INSERT INTO " + String DELETE_ALL_SIMPLE_TRIGGERS = "DELETE FROM " + TABLE_PREFIX_SUBST + "SIMPLE_TRIGGERS " + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; + String DELETE_ALL_SIMPROP_TRIGGERS = "DELETE FROM " + TABLE_PREFIX_SUBST + "SIMPROP_TRIGGERS " + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; + String DELETE_ALL_CRON_TRIGGERS = "DELETE FROM " + TABLE_PREFIX_SUBST + "CRON_TRIGGERS" + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; + String DELETE_ALL_BLOB_TRIGGERS = "DELETE FROM " + TABLE_PREFIX_SUBST + "BLOB_TRIGGERS" + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; + String DELETE_ALL_TRIGGERS = "DELETE FROM " + TABLE_PREFIX_SUBST + "TRIGGERS" + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; + String DELETE_ALL_JOB_DETAILS = "DELETE FROM " + TABLE_PREFIX_SUBST + "JOB_DETAILS" + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; + String DELETE_ALL_CALENDARS = "DELETE FROM " + TABLE_PREFIX_SUBST + "CALENDARS" + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; + String DELETE_ALL_PAUSED_TRIGGER_GRPS = "DELETE FROM " + TABLE_PREFIX_SUBST + "PAUSED_TRIGGER_GRPS" + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; + + String SELECT_FIRED_TRIGGER_INSTANCE_NAMES = + "SELECT DISTINCT " + COL_INSTANCE_NAME + " FROM " + + TABLE_PREFIX_SUBST + + TABLE_FIRED_TRIGGERS + + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; + + String INSERT_SCHEDULER_STATE = "INSERT INTO " + TABLE_PREFIX_SUBST + TABLE_SCHEDULER_STATE + " (" + + COL_SCHEDULER_NAME + ", " + COL_INSTANCE_NAME + ", " + COL_LAST_CHECKIN_TIME + ", " - + COL_CHECKIN_INTERVAL + ", " + COL_RECOVERER - + ") VALUES(?, ?, ?, ?)"; + + COL_CHECKIN_INTERVAL + ") VALUES(" + SCHED_NAME_SUBST + ", ?, ?, ?)"; - public static final String SELECT_SCHEDULER_STATE = "SELECT * FROM " + String SELECT_SCHEDULER_STATE = "SELECT * FROM " + TABLE_PREFIX_SUBST + TABLE_SCHEDULER_STATE + " WHERE " - + COL_INSTANCE_NAME + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_INSTANCE_NAME + " = ?"; - public static final String SELECT_SCHEDULER_STATES = "SELECT * FROM " - + TABLE_PREFIX_SUBST + TABLE_SCHEDULER_STATE; + String SELECT_SCHEDULER_STATES = "SELECT * FROM " + + TABLE_PREFIX_SUBST + TABLE_SCHEDULER_STATE + + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; - public static final String DELETE_SCHEDULER_STATE = "DELETE FROM " + String DELETE_SCHEDULER_STATE = "DELETE FROM " + TABLE_PREFIX_SUBST + TABLE_SCHEDULER_STATE + " WHERE " - + COL_INSTANCE_NAME + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_INSTANCE_NAME + " = ?"; - public static final String UPDATE_SCHEDULER_STATE = "UPDATE " + String UPDATE_SCHEDULER_STATE = "UPDATE " + TABLE_PREFIX_SUBST + TABLE_SCHEDULER_STATE + " SET " - + COL_LAST_CHECKIN_TIME + " = ?, " + COL_RECOVERER + " = ? WHERE " - + COL_INSTANCE_NAME + " = ?"; + + COL_LAST_CHECKIN_TIME + " = ? WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_INSTANCE_NAME + " = ?"; - public static final String INSERT_PAUSED_TRIGGER_GROUP = "INSERT INTO " + String INSERT_PAUSED_TRIGGER_GROUP = "INSERT INTO " + TABLE_PREFIX_SUBST + TABLE_PAUSED_TRIGGERS + " (" - + COL_TRIGGER_GROUP + ") VALUES(?)"; + + COL_SCHEDULER_NAME + ", " + + COL_TRIGGER_GROUP + ") VALUES(" + SCHED_NAME_SUBST + ", ?)"; - public static final String SELECT_PAUSED_TRIGGER_GROUP = "SELECT " + String SELECT_PAUSED_TRIGGER_GROUP = "SELECT " + COL_TRIGGER_GROUP + " FROM " + TABLE_PREFIX_SUBST - + TABLE_PAUSED_TRIGGERS + " WHERE " + COL_TRIGGER_GROUP + " = ?"; + + TABLE_PAUSED_TRIGGERS + " WHERE " + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_GROUP + " = ?"; - public static final String SELECT_PAUSED_TRIGGER_GROUPS = "SELECT " + String SELECT_PAUSED_TRIGGER_GROUPS = "SELECT " + COL_TRIGGER_GROUP + " FROM " + TABLE_PREFIX_SUBST - + TABLE_PAUSED_TRIGGERS; + + TABLE_PAUSED_TRIGGERS + + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; - public static final String DELETE_PAUSED_TRIGGER_GROUP = "DELETE FROM " + String DELETE_PAUSED_TRIGGER_GROUP = "DELETE FROM " + TABLE_PREFIX_SUBST + TABLE_PAUSED_TRIGGERS + " WHERE " - + COL_TRIGGER_GROUP + " = ?"; + + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_TRIGGER_GROUP + " LIKE ?"; - public static final String DELETE_PAUSED_TRIGGER_GROUPS = "DELETE FROM " - + TABLE_PREFIX_SUBST + TABLE_PAUSED_TRIGGERS; + String DELETE_PAUSED_TRIGGER_GROUPS = "DELETE FROM " + + TABLE_PREFIX_SUBST + TABLE_PAUSED_TRIGGERS + + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST; // CREATE TABLE qrtz_scheduler_state(INSTANCE_NAME VARCHAR2(80) NOT NULL, // LAST_CHECKIN_TIME NUMBER(13) NOT NULL, CHECKIN_INTERVAL NUMBER(13) NOT - // NULL, RECOVERER VARCHAR2(80) NOT NULL, PRIMARY KEY (INSTANCE_NAME)); + // NULL, PRIMARY KEY (INSTANCE_NAME)); } Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/StdJDBCDelegate.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/StdJDBCDelegate.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/StdJDBCDelegate.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/StdJDBCDelegate.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,15 +15,17 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; +import static org.quartz.JobKey.jobKey; +import static org.quartz.TriggerBuilder.newTrigger; +import static org.quartz.TriggerKey.triggerKey; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.NotSerializableException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.math.BigDecimal; @@ -32,29 +34,36 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; +import java.sql.Statement; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Iterator; -import java.util.HashMap; -import java.util.Set; import java.util.Properties; -import java.util.TimeZone; +import java.util.Set; -import org.apache.commons.logging.Log; import org.quartz.Calendar; -import org.quartz.CronTrigger; +import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobDetail; +import org.quartz.JobKey; +import org.quartz.JobPersistenceException; import org.quartz.Scheduler; import org.quartz.SimpleTrigger; import org.quartz.Trigger; +import org.quartz.TriggerBuilder; +import org.quartz.TriggerKey; +import org.quartz.impl.JobDetailImpl; +import org.quartz.impl.jdbcjobstore.TriggerPersistenceDelegate.TriggerPropertyBundle; +import org.quartz.impl.matchers.GroupMatcher; +import org.quartz.impl.matchers.StringMatcher; +import org.quartz.impl.triggers.SimpleTriggerImpl; import org.quartz.spi.ClassLoadHelper; -import org.quartz.utils.Key; -import org.quartz.utils.TriggerStatus; +import org.quartz.spi.OperableTrigger; +import org.slf4j.Logger; /** *

@@ -65,6 +74,7 @@ * * @author Jeffrey Wescott * @author James House + * @author Eric Mueller */ public class StdJDBCDelegate implements DriverDelegate, StdJDBCConstants { @@ -76,14 +86,21 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - protected Log logger = null; + protected Logger logger = null; protected String tablePrefix = DEFAULT_TABLE_PREFIX; protected String instanceId; + protected String schedName; + protected boolean useProperties; + + protected ClassLoadHelper classLoadHelper; + protected List triggerPersistenceDelegates = new LinkedList(); + + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -96,48 +113,96 @@ *

* Create new StdJDBCDelegate instance. *

- * - * @param logger - * the logger to use during execution - * @param tablePrefix - * the prefix of all table names */ - public StdJDBCDelegate(Log logger, String tablePrefix, String instanceId) { - this.logger = logger; - this.tablePrefix = tablePrefix; - this.instanceId = instanceId; + public StdJDBCDelegate() { } - /** - *

- * Create new StdJDBCDelegate instance. - *

- * - * @param logger - * the logger to use during execution - * @param tablePrefix - * the prefix of all table names - */ - public StdJDBCDelegate(Log logger, String tablePrefix, String instanceId, - Boolean useProperties) { - this.logger = logger; - this.tablePrefix = tablePrefix; - this.instanceId = instanceId; - this.useProperties = useProperties.booleanValue(); - } - /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Interface. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + + /** + * @param initString of the format: settingName=settingValue|otherSettingName=otherSettingValue|... + * @throws NoSuchDelegateException + */ + public void initialize(Logger logger, String tablePrefix, String schedName, String instanceId, ClassLoadHelper classLoadHelper, boolean useProperties, String initString) throws NoSuchDelegateException { + this.logger = logger; + this.tablePrefix = tablePrefix; + this.schedName = schedName; + this.instanceId = instanceId; + this.useProperties = useProperties; + this.classLoadHelper = classLoadHelper; + addDefaultTriggerPersistenceDelegates(); + + if(initString == null) + return; + + String[] settings = initString.split("\\|"); + + for(String setting: settings) { + String[] parts = setting.split("="); + String name = parts[0]; + if(parts.length == 1 || parts[1] == null || parts[1].equals("")) + continue; + + if(name.equals("triggerPersistenceDelegateClasses")) { + + String[] trigDelegates = parts[1].split(","); + + for(String trigDelClassName: trigDelegates) { + try { + Class trigDelClass = classLoadHelper.loadClass(trigDelClassName); + addTriggerPersistenceDelegate((TriggerPersistenceDelegate) trigDelClass.newInstance()); + } catch (Exception e) { + throw new NoSuchDelegateException("Error instantiating TriggerPersistenceDelegate of type: " + trigDelClassName, e); + } + } + } + else + throw new NoSuchDelegateException("Unknown setting: '" + name + "'"); + } + } + + protected void addDefaultTriggerPersistenceDelegates() { + addTriggerPersistenceDelegate(new SimpleTriggerPersistenceDelegate()); + addTriggerPersistenceDelegate(new CronTriggerPersistenceDelegate()); + addTriggerPersistenceDelegate(new CalendarIntervalTriggerPersistenceDelegate()); + addTriggerPersistenceDelegate(new DailyTimeIntervalTriggerPersistenceDelegate()); + } + protected boolean canUseProperties() { return useProperties; } + + public void addTriggerPersistenceDelegate(TriggerPersistenceDelegate delegate) { + logger.debug("Adding TriggerPersistenceDelegate of type: " + delegate.getClass().getCanonicalName()); + delegate.initialize(tablePrefix, schedName); + this.triggerPersistenceDelegates.add(delegate); + } + + public TriggerPersistenceDelegate findTriggerPersistenceDelegate(OperableTrigger trigger) { + for(TriggerPersistenceDelegate delegate: triggerPersistenceDelegates) { + if(delegate.canHandleTriggerType(trigger)) + return delegate; + } + + return null; + } + public TriggerPersistenceDelegate findTriggerPersistenceDelegate(String discriminator) { + for(TriggerPersistenceDelegate delegate: triggerPersistenceDelegates) { + if(delegate.getHandledTriggerTypeDiscriminator().equals(discriminator)) + return delegate; + } + + return null; + } + //--------------------------------------------------------------------------- // startup / recovery //--------------------------------------------------------------------------- @@ -159,7 +224,7 @@ */ public int updateTriggerStatesFromOtherStates(Connection conn, String newState, String oldState1, String oldState2) - throws SQLException { + throws SQLException { PreparedStatement ps = null; try { @@ -170,12 +235,7 @@ ps.setString(3, oldState2); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } @@ -189,8 +249,8 @@ * @return an array of {@link * org.quartz.utils.Key} objects */ - public Key[] selectMisfiredTriggers(Connection conn, long ts) - throws SQLException { + public List selectMisfiredTriggers(Connection conn, long ts) + throws SQLException { PreparedStatement ps = null; ResultSet rs = null; @@ -199,29 +259,16 @@ ps.setBigDecimal(1, new BigDecimal(String.valueOf(ts))); rs = ps.executeQuery(); - ArrayList list = new ArrayList(); + LinkedList list = new LinkedList(); while (rs.next()) { String triggerName = rs.getString(COL_TRIGGER_NAME); String groupName = rs.getString(COL_TRIGGER_GROUP); - list.add(new Key(triggerName, groupName)); + list.add(triggerKey(triggerName, groupName)); } - Object[] oArr = list.toArray(); - Key[] kArr = new Key[oArr.length]; - System.arraycopy(oArr, 0, kArr, 0, oArr.length); - return kArr; + return list; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -236,8 +283,8 @@ * the state the triggers must be in * @return an array of trigger Key s */ - public Key[] selectTriggersInState(Connection conn, String state) - throws SQLException { + public List selectTriggersInState(Connection conn, String state) + throws SQLException { PreparedStatement ps = null; ResultSet rs = null; @@ -246,30 +293,19 @@ ps.setString(1, state); rs = ps.executeQuery(); - ArrayList list = new ArrayList(); + LinkedList list = new LinkedList(); while (rs.next()) { - list.add(new Key(rs.getString(1), rs.getString(2))); + list.add(triggerKey(rs.getString(1), rs.getString(2))); } - Key[] sArr = (Key[]) list.toArray(new Key[list.size()]); - return sArr; + return list; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } - public Key[] selectMisfiredTriggersInState(Connection conn, String state, + public List selectMisfiredTriggersInState(Connection conn, String state, long ts) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; @@ -280,29 +316,90 @@ ps.setString(2, state); rs = ps.executeQuery(); - ArrayList list = new ArrayList(); + LinkedList list = new LinkedList(); while (rs.next()) { String triggerName = rs.getString(COL_TRIGGER_NAME); String groupName = rs.getString(COL_TRIGGER_GROUP); - list.add(new Key(triggerName, groupName)); + list.add(triggerKey(triggerName, groupName)); } - Object[] oArr = list.toArray(); - Key[] kArr = new Key[oArr.length]; - System.arraycopy(oArr, 0, kArr, 0, oArr.length); - return kArr; + return list; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { + closeResultSet(rs); + closeStatement(ps); + } + } + + /** + *

+ * Get the names of all of the triggers in the given state that have + * misfired - according to the given timestamp. No more than count will + * be returned. + *

+ * + * @param conn The DB Connection + * @param count The most misfired triggers to return, negative for all + * @param resultList Output parameter. A List of + * {@link org.quartz.utils.Key} objects. Must not be null. + * + * @return Whether there are more misfired triggers left to find beyond + * the given count. + */ + public boolean hasMisfiredTriggersInState(Connection conn, String state1, + long ts, int count, List resultList) throws SQLException { + PreparedStatement ps = null; + ResultSet rs = null; + + try { + ps = conn.prepareStatement(rtp(SELECT_HAS_MISFIRED_TRIGGERS_IN_STATE)); + ps.setBigDecimal(1, new BigDecimal(String.valueOf(ts))); + ps.setString(2, state1); + rs = ps.executeQuery(); + + boolean hasReachedLimit = false; + while (rs.next() && (hasReachedLimit == false)) { + if (resultList.size() == count) { + hasReachedLimit = true; + } else { + String triggerName = rs.getString(COL_TRIGGER_NAME); + String groupName = rs.getString(COL_TRIGGER_GROUP); + resultList.add(triggerKey(triggerName, groupName)); } } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } + + return hasReachedLimit; + } finally { + closeResultSet(rs); + closeStatement(ps); + } + } + + /** + *

+ * Get the number of triggers in the given states that have + * misfired - according to the given timestamp. + *

+ * + * @param conn the DB Connection + */ + public int countMisfiredTriggersInState( + Connection conn, String state1, long ts) throws SQLException { + PreparedStatement ps = null; + ResultSet rs = null; + + try { + ps = conn.prepareStatement(rtp(COUNT_MISFIRED_TRIGGERS_IN_STATE)); + ps.setBigDecimal(1, new BigDecimal(String.valueOf(ts))); + ps.setString(2, state1); + rs = ps.executeQuery(); + + if (rs.next()) { + return rs.getInt(1); } + + throw new SQLException("No misfired trigger count returned."); + } finally { + closeResultSet(rs); + closeStatement(ps); } } @@ -317,7 +414,7 @@ * @return an array of {@link * org.quartz.utils.Key} objects */ - public Key[] selectMisfiredTriggersInGroupInState(Connection conn, + public List selectMisfiredTriggersInGroupInState(Connection conn, String groupName, String state, long ts) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; @@ -330,28 +427,15 @@ ps.setString(3, state); rs = ps.executeQuery(); - ArrayList list = new ArrayList(); + LinkedList list = new LinkedList(); while (rs.next()) { String triggerName = rs.getString(COL_TRIGGER_NAME); - list.add(new Key(triggerName, groupName)); + list.add(triggerKey(triggerName, groupName)); } - Object[] oArr = list.toArray(); - Key[] kArr = new Key[oArr.length]; - System.arraycopy(oArr, 0, kArr, 0, oArr.length); - return kArr; + return list; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -376,59 +460,50 @@ * the DB Connection * @return an array of {@link org.quartz.Trigger} objects */ - public Trigger[] selectTriggersForRecoveringJobs(Connection conn) - throws SQLException, IOException, ClassNotFoundException { + public List selectTriggersForRecoveringJobs(Connection conn) + throws SQLException, IOException, ClassNotFoundException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn .prepareStatement(rtp(SELECT_INSTANCES_RECOVERABLE_FIRED_TRIGGERS)); ps.setString(1, instanceId); - ps.setBoolean(2, true); + setBoolean(ps, 2, true); rs = ps.executeQuery(); long dumId = System.currentTimeMillis(); - ArrayList list = new ArrayList(); + LinkedList list = new LinkedList(); while (rs.next()) { String jobName = rs.getString(COL_JOB_NAME); String jobGroup = rs.getString(COL_JOB_GROUP); String trigName = rs.getString(COL_TRIGGER_NAME); String trigGroup = rs.getString(COL_TRIGGER_GROUP); long firedTime = rs.getLong(COL_FIRED_TIME); - SimpleTrigger rcvryTrig = new SimpleTrigger("recover_" + long scheduledTime = rs.getLong(COL_SCHED_TIME); + int priority = rs.getInt(COL_PRIORITY); + @SuppressWarnings("deprecation") + SimpleTriggerImpl rcvryTrig = new SimpleTriggerImpl("recover_" + instanceId + "_" + String.valueOf(dumId++), - Scheduler.DEFAULT_RECOVERY_GROUP, new Date(firedTime)); + Scheduler.DEFAULT_RECOVERY_GROUP, new Date(scheduledTime)); rcvryTrig.setJobName(jobName); rcvryTrig.setJobGroup(jobGroup); - rcvryTrig - .setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW); + rcvryTrig.setPriority(priority); + rcvryTrig.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY); JobDataMap jd = selectTriggerJobDataMap(conn, trigName, trigGroup); - jd.put("QRTZ_FAILED_JOB_ORIG_TRIGGER_NAME", trigName); - jd.put("QRTZ_FAILED_JOB_ORIG_TRIGGER_GROUP", trigGroup); - jd.put("QRTZ_FAILED_JOB_ORIG_TRIGGER_FIRETIME_IN_MILLISECONDS_AS_STRING", String.valueOf(firedTime)); + jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_NAME, trigName); + jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_GROUP, trigGroup); + jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_FIRETIME_IN_MILLISECONDS, String.valueOf(firedTime)); + jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_SCHEDULED_FIRETIME_IN_MILLISECONDS, String.valueOf(scheduledTime)); rcvryTrig.setJobDataMap(jd); list.add(rcvryTrig); } - Object[] oArr = list.toArray(); - Trigger[] tArr = new Trigger[oArr.length]; - System.arraycopy(oArr, 0, tArr, 0, oArr.length); - return tArr; + return list; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -449,34 +524,66 @@ return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } - public int deleteFiredTriggers(Connection conn, String instanceId) - throws SQLException { + public int deleteFiredTriggers(Connection conn, String theInstanceId) + throws SQLException { PreparedStatement ps = null; try { ps = conn.prepareStatement(rtp(DELETE_INSTANCES_FIRED_TRIGGERS)); - ps.setString(1, instanceId); + ps.setString(1, theInstanceId); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } + + /** + * Clear (delete!) all scheduling data - all {@link Job}s, {@link Trigger}s + * {@link Calendar}s. + * + * @throws JobPersistenceException + */ + public void clearData(Connection conn) + throws SQLException { + + PreparedStatement ps = null; + + try { + ps = conn.prepareStatement(rtp(DELETE_ALL_SIMPLE_TRIGGERS)); + ps.executeUpdate(); + ps.close(); + ps = conn.prepareStatement(rtp(DELETE_ALL_SIMPROP_TRIGGERS)); + ps.executeUpdate(); + ps.close(); + ps = conn.prepareStatement(rtp(DELETE_ALL_CRON_TRIGGERS)); + ps.executeUpdate(); + ps.close(); + ps = conn.prepareStatement(rtp(DELETE_ALL_BLOB_TRIGGERS)); + ps.executeUpdate(); + ps.close(); + ps = conn.prepareStatement(rtp(DELETE_ALL_TRIGGERS)); + ps.executeUpdate(); + ps.close(); + ps = conn.prepareStatement(rtp(DELETE_ALL_JOB_DETAILS)); + ps.executeUpdate(); + ps.close(); + ps = conn.prepareStatement(rtp(DELETE_ALL_CALENDARS)); + ps.executeUpdate(); + ps.close(); + ps = conn.prepareStatement(rtp(DELETE_ALL_PAUSED_TRIGGER_GRPS)); + ps.executeUpdate(); + } finally { + closeStatement(ps); + } + } + + //--------------------------------------------------------------------------- // jobs //--------------------------------------------------------------------------- @@ -495,7 +602,7 @@ * if there were problems serializing the JobDataMap */ public int insertJobDetail(Connection conn, JobDetail job) - throws IOException, SQLException { + throws IOException, SQLException { ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap()); PreparedStatement ps = null; @@ -504,32 +611,21 @@ try { ps = conn.prepareStatement(rtp(INSERT_JOB_DETAIL)); - ps.setString(1, job.getName()); - ps.setString(2, job.getGroup()); + ps.setString(1, job.getKey().getName()); + ps.setString(2, job.getKey().getGroup()); ps.setString(3, job.getDescription()); ps.setString(4, job.getJobClass().getName()); - ps.setBoolean(5, job.isDurable()); - ps.setBoolean(6, job.isVolatile()); - ps.setBoolean(7, job.isStateful()); - ps.setBoolean(8, job.requestsRecovery()); - ps.setBytes(9, baos.toByteArray()); + setBoolean(ps, 5, job.isDurable()); + setBoolean(ps, 6, job.isConcurrentExectionDisallowed()); + setBoolean(ps, 7, job.isPersistJobDataAfterExecution()); + setBoolean(ps, 8, job.requestsRecovery()); + setBytes(ps, 9, baos); insertResult = ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } - if (insertResult > 0) { - String[] jobListeners = job.getJobListenerNames(); - for (int i = 0; jobListeners != null && i < jobListeners.length; i++) - insertJobListener(conn, job, jobListeners[i]); - } - return insertResult; } @@ -547,7 +643,7 @@ * if there were problems serializing the JobDataMap */ public int updateJobDetail(Connection conn, JobDetail job) - throws IOException, SQLException { + throws IOException, SQLException { ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap()); PreparedStatement ps = null; @@ -558,32 +654,19 @@ ps = conn.prepareStatement(rtp(UPDATE_JOB_DETAIL)); ps.setString(1, job.getDescription()); ps.setString(2, job.getJobClass().getName()); - ps.setBoolean(3, job.isDurable()); - ps.setBoolean(4, job.isVolatile()); - ps.setBoolean(5, job.isStateful()); - ps.setBoolean(6, job.requestsRecovery()); - ps.setBytes(7, baos.toByteArray()); - ps.setString(8, job.getName()); - ps.setString(9, job.getGroup()); + setBoolean(ps, 3, job.isDurable()); + setBoolean(ps, 4, job.isConcurrentExectionDisallowed()); + setBoolean(ps, 5, job.isPersistJobDataAfterExecution()); + setBoolean(ps, 6, job.requestsRecovery()); + setBytes(ps, 7, baos); + ps.setString(8, job.getKey().getName()); + ps.setString(9, job.getKey().getGroup()); insertResult = ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } - if (insertResult > 0) { - deleteJobListeners(conn, job.getName(), job.getGroup()); - - String[] jobListeners = job.getJobListenerNames(); - for (int i = 0; jobListeners != null && i < jobListeners.length; i++) - insertJobListener(conn, job, jobListeners[i]); - } - return insertResult; } @@ -594,112 +677,55 @@ * * @param conn * the DB Connection - * @param jobName - * the name of the job - * @param groupName - * the group containing the job * @return an array of {@link * org.quartz.utils.Key} objects */ - public Key[] selectTriggerNamesForJob(Connection conn, String jobName, - String groupName) throws SQLException { + public List selectTriggerKeysForJob(Connection conn, JobKey jobKey) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_FOR_JOB)); - ps.setString(1, jobName); - ps.setString(2, groupName); + ps.setString(1, jobKey.getName()); + ps.setString(2, jobKey.getGroup()); rs = ps.executeQuery(); - ArrayList list = new ArrayList(10); + LinkedList list = new LinkedList(); while (rs.next()) { String trigName = rs.getString(COL_TRIGGER_NAME); String trigGroup = rs.getString(COL_TRIGGER_GROUP); - list.add(new Key(trigName, trigGroup)); + list.add(triggerKey(trigName, trigGroup)); } - Object[] oArr = list.toArray(); - Key[] kArr = new Key[oArr.length]; - System.arraycopy(oArr, 0, kArr, 0, oArr.length); - return kArr; + return list; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } /** *

- * Delete all job listeners for the given job. - *

- * - * @param conn - * the DB Connection - * @param jobName - * the name of the job - * @param groupName - * the group containing the job - * @return the number of rows deleted - */ - public int deleteJobListeners(Connection conn, String jobName, - String groupName) throws SQLException { - PreparedStatement ps = null; - - try { - ps = conn.prepareStatement(rtp(DELETE_JOB_LISTENERS)); - ps.setString(1, jobName); - ps.setString(2, groupName); - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - /** - *

* Delete the job detail record for the given job. *

* * @param conn * the DB Connection - * @param jobName - * the name of the job - * @param groupName - * the group containing the job * @return the number of rows deleted */ - public int deleteJobDetail(Connection conn, String jobName, String groupName) - throws SQLException { + public int deleteJobDetail(Connection conn, JobKey jobKey) + throws SQLException { PreparedStatement ps = null; try { - logger.debug("Deleting job: " + groupName + "." + jobName); + if (logger.isDebugEnabled()) { + logger.debug("Deleting job: " + jobKey); + } ps = conn.prepareStatement(rtp(DELETE_JOB_DETAIL)); - ps.setString(1, jobName); - ps.setString(2, groupName); + ps.setString(1, jobKey.getName()); + ps.setString(2, jobKey.getGroup()); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } @@ -710,37 +736,22 @@ * * @param conn * the DB Connection - * @param jobName - * the name of the job - * @param groupName - * the group containing the job * @return true if the job exists and is stateful, false otherwise */ - public boolean isJobStateful(Connection conn, String jobName, - String groupName) throws SQLException { + public boolean isJobNonConcurrent(Connection conn, JobKey jobKey) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { - ps = conn.prepareStatement(rtp(SELECT_JOB_STATEFUL)); - ps.setString(1, jobName); - ps.setString(2, groupName); + ps = conn.prepareStatement(rtp(SELECT_JOB_NONCONCURRENT)); + ps.setString(1, jobKey.getName()); + ps.setString(2, jobKey.getGroup()); rs = ps.executeQuery(); if (!rs.next()) { return false; } - return rs.getBoolean(COL_IS_STATEFUL); + return getBoolean(rs, COL_IS_NONCONCURRENT); } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -751,40 +762,26 @@ * * @param conn * the DB Connection - * @param jobName - * the name of the job - * @param groupName - * the group containing the job * @return true if the job exists, false otherwise */ - public boolean jobExists(Connection conn, String jobName, String groupName) - throws SQLException { + public boolean jobExists(Connection conn, JobKey jobKey) + throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_JOB_EXISTENCE)); - ps.setString(1, jobName); - ps.setString(2, groupName); + ps.setString(1, jobKey.getName()); + ps.setString(2, jobKey.getGroup()); rs = ps.executeQuery(); if (rs.next()) { return true; } else { return false; } } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -801,159 +798,67 @@ * @return the number of rows updated */ public int updateJobData(Connection conn, JobDetail job) - throws IOException, SQLException { + throws IOException, SQLException { ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap()); PreparedStatement ps = null; try { ps = conn.prepareStatement(rtp(UPDATE_JOB_DATA)); - ps.setBytes(1, baos.toByteArray()); - ps.setString(2, job.getName()); - ps.setString(3, job.getGroup()); + setBytes(ps, 1, baos); + ps.setString(2, job.getKey().getName()); + ps.setString(3, job.getKey().getGroup()); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } /** *

- * Associate a listener with a job. - *

- * - * @param conn - * the DB Connection - * @param job - * the job to associate with the listener - * @param listener - * the listener to insert - * @return the number of rows inserted - */ - public int insertJobListener(Connection conn, JobDetail job, String listener) - throws SQLException { - PreparedStatement ps = null; - - try { - ps = conn.prepareStatement(rtp(INSERT_JOB_LISTENER)); - ps.setString(1, job.getName()); - ps.setString(2, job.getGroup()); - ps.setString(3, listener); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - /** - *

- * Get all of the listeners for a given job. - *

- * - * @param conn - * the DB Connection - * @param jobName - * the job name whose listeners are wanted - * @param groupName - * the group containing the job - * @return array of String listener names - */ - public String[] selectJobListeners(Connection conn, String jobName, - String groupName) throws SQLException { - PreparedStatement ps = null; - ResultSet rs = null; - - try { - ArrayList list = new ArrayList(); - ps = conn.prepareStatement(rtp(SELECT_JOB_LISTENERS)); - ps.setString(1, jobName); - ps.setString(2, groupName); - rs = ps.executeQuery(); - - while (rs.next()) { - list.add(rs.getString(1)); - } - - Object[] oArr = list.toArray(); - String[] sArr = new String[oArr.length]; - System.arraycopy(oArr, 0, sArr, 0, oArr.length); - return sArr; - } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - /** - *

* Select the JobDetail object for a given job name / group name. *

* * @param conn * the DB Connection - * @param jobName - * the job name whose listeners are wanted - * @param groupName - * the group containing the job * @return the populated JobDetail object * @throws ClassNotFoundException * if a class found during deserialization cannot be found or if * the job class could not be found * @throws IOException * if deserialization causes an error */ - public JobDetail selectJobDetail(Connection conn, String jobName, - String groupName, ClassLoadHelper loadHelper) - throws ClassNotFoundException, IOException, SQLException { + public JobDetail selectJobDetail(Connection conn, JobKey jobKey, + ClassLoadHelper loadHelper) + throws ClassNotFoundException, IOException, SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_JOB_DETAIL)); - ps.setString(1, jobName); - ps.setString(2, groupName); + ps.setString(1, jobKey.getName()); + ps.setString(2, jobKey.getGroup()); rs = ps.executeQuery(); - JobDetail job = null; + JobDetailImpl job = null; if (rs.next()) { - job = new JobDetail(); + job = new JobDetailImpl(); job.setName(rs.getString(COL_JOB_NAME)); job.setGroup(rs.getString(COL_JOB_GROUP)); job.setDescription(rs.getString(COL_DESCRIPTION)); - job.setJobClass(loadHelper.loadClass(rs - .getString(COL_JOB_CLASS))); - job.setDurability(rs.getBoolean(COL_IS_DURABLE)); - job.setVolatility(rs.getBoolean(COL_IS_VOLATILE)); - job.setRequestsRecovery(rs.getBoolean(COL_REQUESTS_RECOVERY)); + job.setJobClass( loadHelper.loadClass(rs.getString(COL_JOB_CLASS), Job.class)); + job.setDurability(getBoolean(rs, COL_IS_DURABLE)); + job.setRequestsRecovery(getBoolean(rs, COL_REQUESTS_RECOVERY)); - Map map = null; - if (canUseProperties()) map = getMapFromProperties(rs); - else - map = (Map) getObjectFromBlob(rs, COL_JOB_DATAMAP); + Map map = null; + if (canUseProperties()) { + map = getMapFromProperties(rs); + } else { + map = (Map) getObjectFromBlob(rs, COL_JOB_DATAMAP); + } if (null != map) { job.setJobDataMap(new JobDataMap(map)); @@ -962,32 +867,29 @@ return job; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } /** * build Map from java.util.Properties encoding. */ - private Map getMapFromProperties(ResultSet rs) - throws ClassNotFoundException, IOException, SQLException { - Map map; - InputStream is = (InputStream) getJobDetailFromBlob(rs, COL_JOB_DATAMAP); - if(is == null) + private Map getMapFromProperties(ResultSet rs) + throws ClassNotFoundException, IOException, SQLException { + Map map; + InputStream is = (InputStream) getJobDataFromBlob(rs, COL_JOB_DATAMAP); + if(is == null) { return null; + } Properties properties = new Properties(); - if (is != null) properties.load(is); + if (is != null) { + try { + properties.load(is); + } finally { + is.close(); + } + } map = convertFromProperty(properties); return map; } @@ -1016,18 +918,8 @@ return count; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -1040,36 +932,23 @@ * the DB Connection * @return an array of String group names */ - public String[] selectJobGroups(Connection conn) throws SQLException { + public List selectJobGroups(Connection conn) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_JOB_GROUPS)); rs = ps.executeQuery(); - ArrayList list = new ArrayList(); + LinkedList list = new LinkedList(); while (rs.next()) { list.add(rs.getString(1)); } - Object[] oArr = list.toArray(); - String[] sArr = new String[oArr.length]; - System.arraycopy(oArr, 0, sArr, 0, oArr.length); - return sArr; + return list; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -1080,45 +959,70 @@ * * @param conn * the DB Connection - * @param groupName - * the group containing the jobs + * @param matcher + * the groupMatcher to evaluate the jobs against * @return an array of String job names */ - public String[] selectJobsInGroup(Connection conn, String groupName) - throws SQLException { + public Set selectJobsInGroup(Connection conn, GroupMatcher matcher) + throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { - ps = conn.prepareStatement(rtp(SELECT_JOBS_IN_GROUP)); - ps.setString(1, groupName); + if(isMatcherEquals(matcher)) { + ps = conn.prepareStatement(rtp(SELECT_JOBS_IN_GROUP)); + ps.setString(1, toSqlEqualsClause(matcher)); + } + else { + ps = conn.prepareStatement(rtp(SELECT_JOBS_IN_GROUP_LIKE)); + ps.setString(1, toSqlLikeClause(matcher)); + } rs = ps.executeQuery(); - ArrayList list = new ArrayList(); + LinkedList list = new LinkedList(); while (rs.next()) { - list.add(rs.getString(1)); + list.add(jobKey(rs.getString(1), rs.getString(2))); } - Object[] oArr = list.toArray(); - String[] sArr = new String[oArr.length]; - System.arraycopy(oArr, 0, sArr, 0, oArr.length); - return sArr; + return new HashSet(list); } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } + protected boolean isMatcherEquals(final GroupMatcher matcher) { + return matcher.getCompareWithOperator().equals(StringMatcher.StringOperatorName.EQUALS); + } + + protected String toSqlEqualsClause(final GroupMatcher matcher) { + return matcher.getCompareToValue(); + } + + protected String toSqlLikeClause(final GroupMatcher matcher) { + String groupName; + switch(matcher.getCompareWithOperator()) { + case EQUALS: + groupName = matcher.getCompareToValue(); + break; + case CONTAINS: + groupName = "%" + matcher.getCompareToValue() + "%"; + break; + case ENDS_WITH: + groupName = "%" + matcher.getCompareToValue(); + break; + case STARTS_WITH: + groupName = matcher.getCompareToValue() + "%"; + break; + case ANYTHING: + groupName = "%"; + break; + default: + throw new UnsupportedOperationException("Don't know how to translate " + matcher.getCompareWithOperator() + " into SQL"); + } + return groupName; + } + //--------------------------------------------------------------------------- // triggers //--------------------------------------------------------------------------- @@ -1136,143 +1040,72 @@ * the state that the trigger should be stored in * @return the number of rows inserted */ - public int insertTrigger(Connection conn, Trigger trigger, String state, + public int insertTrigger(Connection conn, OperableTrigger trigger, String state, JobDetail jobDetail) throws SQLException, IOException { ByteArrayOutputStream baos = null; - if(trigger.getJobDataMap().size() > 0) + if(trigger.getJobDataMap().size() > 0) { baos = serializeJobData(trigger.getJobDataMap()); + } PreparedStatement ps = null; int insertResult = 0; try { ps = conn.prepareStatement(rtp(INSERT_TRIGGER)); - ps.setString(1, trigger.getName()); - ps.setString(2, trigger.getGroup()); - ps.setString(3, trigger.getJobName()); - ps.setString(4, trigger.getJobGroup()); - ps.setBoolean(5, trigger.isVolatile()); - ps.setString(6, trigger.getDescription()); - ps.setBigDecimal(7, new BigDecimal(String.valueOf(trigger - .getNextFireTime().getTime()))); + ps.setString(1, trigger.getKey().getName()); + ps.setString(2, trigger.getKey().getGroup()); + ps.setString(3, trigger.getJobKey().getName()); + ps.setString(4, trigger.getJobKey().getGroup()); + ps.setString(5, trigger.getDescription()); + if(trigger.getNextFireTime() != null) + ps.setBigDecimal(6, new BigDecimal(String.valueOf(trigger + .getNextFireTime().getTime()))); + else + ps.setBigDecimal(6, null); long prevFireTime = -1; if (trigger.getPreviousFireTime() != null) { prevFireTime = trigger.getPreviousFireTime().getTime(); } - ps.setBigDecimal(8, new BigDecimal(String.valueOf(prevFireTime))); - ps.setString(9, state); - if (trigger instanceof SimpleTrigger) { - ps.setString(10, TTYPE_SIMPLE); - } else if (trigger instanceof CronTrigger) { - ps.setString(10, TTYPE_CRON); - } else { // (trigger instanceof BlobTrigger) - ps.setString(10, TTYPE_BLOB); - } - ps.setBigDecimal(11, new BigDecimal(String.valueOf(trigger + ps.setBigDecimal(7, new BigDecimal(String.valueOf(prevFireTime))); + ps.setString(8, state); + + TriggerPersistenceDelegate tDel = findTriggerPersistenceDelegate(trigger); + + String type = TTYPE_BLOB; + if(tDel != null) + type = tDel.getHandledTriggerTypeDiscriminator(); + ps.setString(9, type); + + ps.setBigDecimal(10, new BigDecimal(String.valueOf(trigger .getStartTime().getTime()))); long endTime = 0; if (trigger.getEndTime() != null) { endTime = trigger.getEndTime().getTime(); } - ps.setBigDecimal(12, new BigDecimal(String.valueOf(endTime))); - ps.setString(13, trigger.getCalendarName()); - ps.setInt(14, trigger.getMisfireInstruction()); - if(baos != null) - ps.setBytes(15, baos.toByteArray()); - else - ps.setBytes(15, null); + ps.setBigDecimal(11, new BigDecimal(String.valueOf(endTime))); + ps.setString(12, trigger.getCalendarName()); + ps.setInt(13, trigger.getMisfireInstruction()); + setBytes(ps, 14, baos); + ps.setInt(15, trigger.getPriority()); insertResult = ps.executeUpdate(); + + if(tDel == null) + insertBlobTrigger(conn, trigger); + else + tDel.insertExtendedTriggerProperties(conn, trigger, state, jobDetail); + } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } - if (insertResult > 0) { - String[] trigListeners = trigger.getTriggerListenerNames(); - for (int i = 0; trigListeners != null && i < trigListeners.length; i++) - insertTriggerListener(conn, trigger, trigListeners[i]); - } - return insertResult; } /** *

- * Insert the simple trigger data. - *

- * - * @param conn - * the DB Connection - * @param trigger - * the trigger to insert - * @return the number of rows inserted - */ - public int insertSimpleTrigger(Connection conn, SimpleTrigger trigger) - throws SQLException { - PreparedStatement ps = null; - - try { - ps = conn.prepareStatement(rtp(INSERT_SIMPLE_TRIGGER)); - ps.setString(1, trigger.getName()); - ps.setString(2, trigger.getGroup()); - ps.setInt(3, trigger.getRepeatCount()); - ps.setBigDecimal(4, new BigDecimal(String.valueOf(trigger - .getRepeatInterval()))); - ps.setInt(5, trigger.getTimesTriggered()); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - /** - *

- * Insert the cron trigger data. - *

- * - * @param conn - * the DB Connection - * @param trigger - * the trigger to insert - * @return the number of rows inserted - */ - public int insertCronTrigger(Connection conn, CronTrigger trigger) - throws SQLException { - PreparedStatement ps = null; - - try { - ps = conn.prepareStatement(rtp(INSERT_CRON_TRIGGER)); - ps.setString(1, trigger.getName()); - ps.setString(2, trigger.getGroup()); - ps.setString(3, trigger.getCronExpression()); - ps.setString(4, trigger.getTimeZone().getID()); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - /** - *

* Insert the blob trigger data. *

* @@ -1282,8 +1115,8 @@ * the trigger to insert * @return the number of rows inserted */ - public int insertBlobTrigger(Connection conn, Trigger trigger) - throws SQLException, IOException { + public int insertBlobTrigger(Connection conn, OperableTrigger trigger) + throws SQLException, IOException { PreparedStatement ps = null; ByteArrayOutputStream os = null; @@ -1298,18 +1131,13 @@ ByteArrayInputStream is = new ByteArrayInputStream(buf); ps = conn.prepareStatement(rtp(INSERT_BLOB_TRIGGER)); - ps.setString(1, trigger.getName()); - ps.setString(2, trigger.getGroup()); + ps.setString(1, trigger.getKey().getName()); + ps.setString(2, trigger.getKey().getGroup()); ps.setBinaryStream(3, is, buf.length); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } @@ -1326,162 +1154,87 @@ * the state that the trigger should be stored in * @return the number of rows updated */ - public int updateTrigger(Connection conn, Trigger trigger, String state, + public int updateTrigger(Connection conn, OperableTrigger trigger, String state, JobDetail jobDetail) throws SQLException, IOException { // save some clock cycles by unnecessarily writing job data blob ... boolean updateJobData = trigger.getJobDataMap().isDirty(); ByteArrayOutputStream baos = null; - if(updateJobData && trigger.getJobDataMap().size() > 0) + if(updateJobData && trigger.getJobDataMap().size() > 0) { baos = serializeJobData(trigger.getJobDataMap()); + } PreparedStatement ps = null; int insertResult = 0; try { - if(updateJobData) + if(updateJobData) { ps = conn.prepareStatement(rtp(UPDATE_TRIGGER)); - else + } else { ps = conn.prepareStatement(rtp(UPDATE_TRIGGER_SKIP_DATA)); + } - ps.setString(1, trigger.getJobName()); - ps.setString(2, trigger.getJobGroup()); - ps.setBoolean(3, trigger.isVolatile()); - ps.setString(4, trigger.getDescription()); + ps.setString(1, trigger.getJobKey().getName()); + ps.setString(2, trigger.getJobKey().getGroup()); + ps.setString(3, trigger.getDescription()); long nextFireTime = -1; if (trigger.getNextFireTime() != null) { nextFireTime = trigger.getNextFireTime().getTime(); } - ps.setBigDecimal(5, new BigDecimal(String.valueOf(nextFireTime))); + ps.setBigDecimal(4, new BigDecimal(String.valueOf(nextFireTime))); long prevFireTime = -1; if (trigger.getPreviousFireTime() != null) { prevFireTime = trigger.getPreviousFireTime().getTime(); } - ps.setBigDecimal(6, new BigDecimal(String.valueOf(prevFireTime))); - ps.setString(7, state); - if (trigger instanceof SimpleTrigger) { - // updateSimpleTrigger(conn, (SimpleTrigger)trigger); - ps.setString(8, TTYPE_SIMPLE); - } else if (trigger instanceof CronTrigger) { - // updateCronTrigger(conn, (CronTrigger)trigger); - ps.setString(8, TTYPE_CRON); - } else { - // updateBlobTrigger(conn, trigger); - ps.setString(8, TTYPE_BLOB); - } - ps.setBigDecimal(9, new BigDecimal(String.valueOf(trigger + ps.setBigDecimal(5, new BigDecimal(String.valueOf(prevFireTime))); + ps.setString(6, state); + + TriggerPersistenceDelegate tDel = findTriggerPersistenceDelegate(trigger); + + String type = TTYPE_BLOB; + if(tDel != null) + type = tDel.getHandledTriggerTypeDiscriminator(); + + ps.setString(7, type); + + ps.setBigDecimal(8, new BigDecimal(String.valueOf(trigger .getStartTime().getTime()))); long endTime = 0; if (trigger.getEndTime() != null) { endTime = trigger.getEndTime().getTime(); } - ps.setBigDecimal(10, new BigDecimal(String.valueOf(endTime))); - ps.setString(11, trigger.getCalendarName()); - ps.setInt(12, trigger.getMisfireInstruction()); + ps.setBigDecimal(9, new BigDecimal(String.valueOf(endTime))); + ps.setString(10, trigger.getCalendarName()); + ps.setInt(11, trigger.getMisfireInstruction()); + ps.setInt(12, trigger.getPriority()); + if(updateJobData) { - ps.setBytes(13, baos.toByteArray()); - - ps.setString(14, trigger.getName()); - ps.setString(15, trigger.getGroup()); + setBytes(ps, 13, baos); + ps.setString(14, trigger.getKey().getName()); + ps.setString(15, trigger.getKey().getGroup()); + } else { + ps.setString(13, trigger.getKey().getName()); + ps.setString(14, trigger.getKey().getGroup()); } - else { - ps.setString(13, trigger.getName()); - ps.setString(14, trigger.getGroup()); - } insertResult = ps.executeUpdate(); + + if(tDel == null) + updateBlobTrigger(conn, trigger); + else + tDel.updateExtendedTriggerProperties(conn, trigger, state, jobDetail); + } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } - if (insertResult > 0) { - deleteTriggerListeners(conn, trigger.getName(), trigger.getGroup()); - - String[] trigListeners = trigger.getTriggerListenerNames(); - for (int i = 0; trigListeners != null && i < trigListeners.length; i++) - insertTriggerListener(conn, trigger, trigListeners[i]); - } - return insertResult; } /** *

- * Update the simple trigger data. - *

- * - * @param conn - * the DB Connection - * @param trigger - * the trigger to insert - * @return the number of rows updated - */ - public int updateSimpleTrigger(Connection conn, SimpleTrigger trigger) - throws SQLException { - PreparedStatement ps = null; - - try { - ps = conn.prepareStatement(rtp(UPDATE_SIMPLE_TRIGGER)); - - ps.setInt(1, trigger.getRepeatCount()); - ps.setBigDecimal(2, new BigDecimal(String.valueOf(trigger - .getRepeatInterval()))); - ps.setInt(3, trigger.getTimesTriggered()); - ps.setString(4, trigger.getName()); - ps.setString(5, trigger.getGroup()); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - /** - *

- * Update the cron trigger data. - *

- * - * @param conn - * the DB Connection - * @param trigger - * the trigger to insert - * @return the number of rows updated - */ - public int updateCronTrigger(Connection conn, CronTrigger trigger) - throws SQLException { - PreparedStatement ps = null; - - try { - ps = conn.prepareStatement(rtp(UPDATE_CRON_TRIGGER)); - ps.setString(1, trigger.getCronExpression()); - ps.setString(2, trigger.getName()); - ps.setString(3, trigger.getGroup()); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - /** - *

* Update the blob trigger data. *

* @@ -1491,8 +1244,8 @@ * the trigger to insert * @return the number of rows updated */ - public int updateBlobTrigger(Connection conn, Trigger trigger) - throws SQLException, IOException { + public int updateBlobTrigger(Connection conn, OperableTrigger trigger) + throws SQLException, IOException { PreparedStatement ps = null; ByteArrayOutputStream os = null; @@ -1508,18 +1261,15 @@ ps = conn.prepareStatement(rtp(UPDATE_BLOB_TRIGGER)); ps.setBinaryStream(1, is, buf.length); - ps.setString(2, trigger.getName()); - ps.setString(3, trigger.getGroup()); + ps.setString(2, trigger.getKey().getName()); + ps.setString(3, trigger.getKey().getGroup()); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } + closeStatement(ps); + if (os != null) { + os.close(); } - if (os != null) os.close(); } } @@ -1530,21 +1280,16 @@ * * @param conn * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger * @return true if the trigger exists, false otherwise */ - public boolean triggerExists(Connection conn, String triggerName, - String groupName) throws SQLException { + public boolean triggerExists(Connection conn, TriggerKey triggerKey) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_TRIGGER_EXISTENCE)); - ps.setString(1, triggerName); - ps.setString(2, groupName); + ps.setString(1, triggerKey.getName()); + ps.setString(2, triggerKey.getGroup()); rs = ps.executeQuery(); if (rs.next()) { @@ -1553,18 +1298,8 @@ return false; } } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -1575,32 +1310,22 @@ * * @param conn * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger * @param state * the new state for the trigger * @return the number of rows updated */ - public int updateTriggerState(Connection conn, String triggerName, - String groupName, String state) throws SQLException { + public int updateTriggerState(Connection conn, TriggerKey triggerKey, + String state) throws SQLException { PreparedStatement ps = null; try { ps = conn.prepareStatement(rtp(UPDATE_TRIGGER_STATE)); ps.setString(1, state); - ps.setString(2, triggerName); - ps.setString(3, groupName); - + ps.setString(2, triggerKey.getName()); + ps.setString(3, triggerKey.getGroup()); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } @@ -1612,10 +1337,6 @@ * * @param conn * the DB connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger * @param newState * the new state for the trigger * @param oldState1 @@ -1628,55 +1349,26 @@ * @throws SQLException */ public int updateTriggerStateFromOtherStates(Connection conn, - String triggerName, String groupName, String newState, - String oldState1, String oldState2, String oldState3) - throws SQLException { + TriggerKey triggerKey, String newState, String oldState1, + String oldState2, String oldState3) + throws SQLException { PreparedStatement ps = null; try { ps = conn.prepareStatement(rtp(UPDATE_TRIGGER_STATE_FROM_STATES)); ps.setString(1, newState); - ps.setString(2, triggerName); - ps.setString(3, groupName); + ps.setString(2, triggerKey.getName()); + ps.setString(3, triggerKey.getGroup()); ps.setString(4, oldState1); ps.setString(5, oldState2); ps.setString(6, oldState3); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } - public int updateTriggerStateFromOtherStatesBeforeTime(Connection conn, - String newState, String oldState1, String oldState2, long time) - throws SQLException { - PreparedStatement ps = null; - - try { - ps = conn - .prepareStatement(rtp(UPDATE_TRIGGER_STATE_FROM_OTHER_STATES_BEFORE_TIME)); - ps.setString(1, newState); - ps.setString(2, oldState1); - ps.setString(3, oldState2); - ps.setLong(4, time); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - /** *

* Update all triggers in the given group to the given new state, if they @@ -1685,8 +1377,8 @@ * * @param conn * the DB connection - * @param groupName - * the group containing the trigger + * @param matcher + * the groupMatcher to evaluate the triggers against * @param newState * the new state for the trigger * @param oldState1 @@ -1699,27 +1391,22 @@ * @throws SQLException */ public int updateTriggerGroupStateFromOtherStates(Connection conn, - String groupName, String newState, String oldState1, + GroupMatcher matcher, String newState, String oldState1, String oldState2, String oldState3) throws SQLException { PreparedStatement ps = null; try { ps = conn .prepareStatement(rtp(UPDATE_TRIGGER_GROUP_STATE_FROM_STATES)); ps.setString(1, newState); - ps.setString(2, groupName); + ps.setString(2, toSqlLikeClause(matcher)); ps.setString(3, oldState1); ps.setString(4, oldState2); ps.setString(5, oldState3); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } @@ -1731,10 +1418,6 @@ * * @param conn * the DB connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger * @param newState * the new state for the trigger * @param oldState @@ -1743,25 +1426,19 @@ * @throws SQLException */ public int updateTriggerStateFromOtherState(Connection conn, - String triggerName, String groupName, String newState, - String oldState) throws SQLException { + TriggerKey triggerKey, String newState, String oldState) throws SQLException { PreparedStatement ps = null; try { ps = conn.prepareStatement(rtp(UPDATE_TRIGGER_STATE_FROM_STATE)); ps.setString(1, newState); - ps.setString(2, triggerName); - ps.setString(3, groupName); + ps.setString(2, triggerKey.getName()); + ps.setString(3, triggerKey.getGroup()); ps.setString(4, oldState); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } @@ -1773,8 +1450,8 @@ * * @param conn * the DB connection - * @param groupName - * the group containing the triggers + * @param matcher + * the groupMatcher to evaluate the triggers against * @param newState * the new state for the trigger group * @param oldState @@ -1783,25 +1460,20 @@ * @throws SQLException */ public int updateTriggerGroupStateFromOtherState(Connection conn, - String groupName, String newState, String oldState) - throws SQLException { + GroupMatcher matcher, String newState, String oldState) + throws SQLException { PreparedStatement ps = null; try { ps = conn .prepareStatement(rtp(UPDATE_TRIGGER_GROUP_STATE_FROM_STATE)); ps.setString(1, newState); - ps.setString(2, groupName); + ps.setString(2, toSqlLikeClause(matcher)); ps.setString(3, oldState); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } @@ -1812,269 +1484,65 @@ * * @param conn * the DB Connection - * @param jobName - * the name of the job - * @param groupName - * the group containing the job * @param state * the new state for the triggers * @return the number of rows updated */ - public int updateTriggerStatesForJob(Connection conn, String jobName, - String groupName, String state) throws SQLException { + public int updateTriggerStatesForJob(Connection conn, JobKey jobKey, + String state) throws SQLException { PreparedStatement ps = null; try { ps = conn.prepareStatement(rtp(UPDATE_JOB_TRIGGER_STATES)); ps.setString(1, state); - ps.setString(2, jobName); - ps.setString(3, groupName); + ps.setString(2, jobKey.getName()); + ps.setString(3, jobKey.getGroup()); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } public int updateTriggerStatesForJobFromOtherState(Connection conn, - String jobName, String groupName, String state, String oldState) - throws SQLException { + JobKey jobKey, String state, String oldState) + throws SQLException { PreparedStatement ps = null; try { ps = conn .prepareStatement(rtp(UPDATE_JOB_TRIGGER_STATES_FROM_OTHER_STATE)); ps.setString(1, state); - ps.setString(2, jobName); - ps.setString(3, groupName); + ps.setString(2, jobKey.getName()); + ps.setString(3, jobKey.getGroup()); ps.setString(4, oldState); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } /** *

- * Delete all of the listeners associated with a given trigger. - *

- * - * @param conn - * the DB Connection - * @param triggerName - * the name of the trigger whose listeners will be deleted - * @param groupName - * the name of the group containing the trigger - * @return the number of rows deleted - */ - public int deleteTriggerListeners(Connection conn, String triggerName, - String groupName) throws SQLException { - PreparedStatement ps = null; - - try { - ps = conn.prepareStatement(rtp(DELETE_TRIGGER_LISTENERS)); - ps.setString(1, triggerName); - ps.setString(2, groupName); - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - /** - *

- * Associate a listener with the given trigger. - *

- * - * @param conn - * the DB Connection - * @param trigger - * the trigger - * @param listener - * the name of the listener to associate with the trigger - * @return the number of rows inserted - */ - public int insertTriggerListener(Connection conn, Trigger trigger, - String listener) throws SQLException { - PreparedStatement ps = null; - - try { - ps = conn.prepareStatement(rtp(INSERT_TRIGGER_LISTENER)); - ps.setString(1, trigger.getName()); - ps.setString(2, trigger.getGroup()); - ps.setString(3, listener); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - /** - *

- * Select the listeners associated with a given trigger. - *

- * - * @param conn - * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger - * @return array of String trigger listener names - */ - public String[] selectTriggerListeners(Connection conn, String triggerName, - String groupName) throws SQLException { - PreparedStatement ps = null; - ResultSet rs = null; - - try { - ps = conn.prepareStatement(rtp(SELECT_TRIGGER_LISTENERS)); - ps.setString(1, triggerName); - ps.setString(2, groupName); - rs = ps.executeQuery(); - - ArrayList list = new ArrayList(); - while (rs.next()) { - list.add(rs.getString(1)); - } - Object[] oArr = list.toArray(); - String[] sArr = new String[oArr.length]; - System.arraycopy(oArr, 0, sArr, 0, oArr.length); - return sArr; - } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - /** - *

- * Delete the simple trigger data for a trigger. - *

- * - * @param conn - * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger - * @return the number of rows deleted - */ - public int deleteSimpleTrigger(Connection conn, String triggerName, - String groupName) throws SQLException { - PreparedStatement ps = null; - - try { - ps = conn.prepareStatement(rtp(DELETE_SIMPLE_TRIGGER)); - ps.setString(1, triggerName); - ps.setString(2, groupName); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - /** - *

* Delete the cron trigger data for a trigger. *

* * @param conn * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger * @return the number of rows deleted */ - public int deleteCronTrigger(Connection conn, String triggerName, - String groupName) throws SQLException { + public int deleteBlobTrigger(Connection conn, TriggerKey triggerKey) throws SQLException { PreparedStatement ps = null; try { - ps = conn.prepareStatement(rtp(DELETE_CRON_TRIGGER)); - ps.setString(1, triggerName); - ps.setString(2, groupName); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - /** - *

- * Delete the cron trigger data for a trigger. - *

- * - * @param conn - * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger - * @return the number of rows deleted - */ - public int deleteBlobTrigger(Connection conn, String triggerName, - String groupName) throws SQLException { - PreparedStatement ps = null; - - try { ps = conn.prepareStatement(rtp(DELETE_BLOB_TRIGGER)); - ps.setString(1, triggerName); - ps.setString(2, groupName); + ps.setString(1, triggerKey.getName()); + ps.setString(2, triggerKey.getGroup()); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } @@ -2085,54 +1553,51 @@ * * @param conn * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger * @return the number of rows deleted */ - public int deleteTrigger(Connection conn, String triggerName, - String groupName) throws SQLException { + public int deleteTrigger(Connection conn, TriggerKey triggerKey) throws SQLException { PreparedStatement ps = null; + deleteTriggerExtension(conn, triggerKey); + try { ps = conn.prepareStatement(rtp(DELETE_TRIGGER)); - ps.setString(1, triggerName); - ps.setString(2, groupName); + ps.setString(1, triggerKey.getName()); + ps.setString(2, triggerKey.getGroup()); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } + + protected void deleteTriggerExtension(Connection conn, TriggerKey triggerKey) throws SQLException { + for(TriggerPersistenceDelegate tDel: triggerPersistenceDelegates) { + if(tDel.deleteExtendedTriggerProperties(conn, triggerKey) > 0) + return; // as soon as one affects a row, we're done. + } + + deleteBlobTrigger(conn, triggerKey); + } + /** *

* Select the number of triggers associated with a given job. *

* * @param conn * the DB Connection - * @param jobName - * the name of the job - * @param groupName - * the group containing the job * @return the number of triggers for the given job */ - public int selectNumTriggersForJob(Connection conn, String jobName, - String groupName) throws SQLException { + public int selectNumTriggersForJob(Connection conn, JobKey jobKey) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_NUM_TRIGGERS_FOR_JOB)); - ps.setString(1, jobName); - ps.setString(2, groupName); + ps.setString(1, jobKey.getName()); + ps.setString(2, jobKey.getGroup()); rs = ps.executeQuery(); if (rs.next()) { @@ -2141,76 +1606,72 @@ return 0; } } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } /** *

* Select the job to which the trigger is associated. *

+ * + * @param conn + * the DB Connection + * @return the {@link org.quartz.JobDetail} object + * associated with the given trigger + * @throws SQLException + * @throws ClassNotFoundException + */ + public JobDetail selectJobForTrigger(Connection conn, ClassLoadHelper loadHelper, + TriggerKey triggerKey) throws ClassNotFoundException, SQLException { + return selectJobForTrigger(conn, loadHelper, triggerKey, true); + } + + /** + *

+ * Select the job to which the trigger is associated. Allow option to load actual job class or not. When case of + * remove, we do not need to load the class, which in many cases, it's no longer exists. + * + *

* * @param conn * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger * @return the {@link org.quartz.JobDetail} object * associated with the given trigger * @throws SQLException * @throws ClassNotFoundException */ - public JobDetail selectJobForTrigger(Connection conn, String triggerName, - String groupName, ClassLoadHelper loadHelper) throws ClassNotFoundException, SQLException { + public JobDetail selectJobForTrigger(Connection conn, ClassLoadHelper loadHelper, + TriggerKey triggerKey, boolean loadJobClass) throws ClassNotFoundException, SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_JOB_FOR_TRIGGER)); - ps.setString(1, triggerName); - ps.setString(2, groupName); + ps.setString(1, triggerKey.getName()); + ps.setString(2, triggerKey.getGroup()); rs = ps.executeQuery(); if (rs.next()) { - JobDetail job = new JobDetail(); + JobDetailImpl job = new JobDetailImpl(); job.setName(rs.getString(1)); job.setGroup(rs.getString(2)); - job.setDurability(rs.getBoolean(3)); - job.setJobClass(loadHelper.loadClass(rs - .getString(4))); - job.setRequestsRecovery(rs.getBoolean(5)); + job.setDurability(getBoolean(rs, 3)); + if (loadJobClass) + job.setJobClass(loadHelper.loadClass(rs.getString(4), Job.class)); + job.setRequestsRecovery(getBoolean(rs, 5)); return job; } else { - logger.debug("No job for trigger '" + groupName + "." - + triggerName + "'."); + if (logger.isDebugEnabled()) { + logger.debug("No job for trigger '" + triggerKey + "'."); + } return null; } } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -2221,57 +1682,42 @@ * * @param conn * the DB Connection - * @param jobName - * the name of the trigger - * @param groupName - * the group containing the trigger * @return an array of (@link org.quartz.Trigger) objects * associated with a given job. * @throws SQLException + * @throws JobPersistenceException */ - public Trigger[] selectTriggersForJob(Connection conn, String jobName, - String groupName) throws SQLException, ClassNotFoundException, - IOException { + public List selectTriggersForJob(Connection conn, JobKey jobKey) throws SQLException, ClassNotFoundException, + IOException, JobPersistenceException { - ArrayList trigList = new ArrayList(); + LinkedList trigList = new LinkedList(); PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_FOR_JOB)); - ps.setString(1, jobName); - ps.setString(2, groupName); + ps.setString(1, jobKey.getName()); + ps.setString(2, jobKey.getGroup()); rs = ps.executeQuery(); while (rs.next()) { - Trigger t = selectTrigger(conn, - rs.getString(COL_TRIGGER_NAME), - rs.getString(COL_TRIGGER_GROUP)); - if(t != null) + OperableTrigger t = selectTrigger(conn, triggerKey(rs.getString(COL_TRIGGER_NAME), rs.getString(COL_TRIGGER_GROUP))); + if(t != null) { trigList.add(t); - } - } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { } } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + } finally { + closeResultSet(rs); + closeStatement(ps); } - return (Trigger[]) trigList.toArray(new Trigger[trigList.size()]); + return trigList; } - public Trigger[] selectTriggersForCalendar(Connection conn, String calName) - throws SQLException, ClassNotFoundException, IOException { + public List selectTriggersForCalendar(Connection conn, String calName) + throws SQLException, ClassNotFoundException, IOException, JobPersistenceException { - ArrayList trigList = new ArrayList(); + LinkedList trigList = new LinkedList(); PreparedStatement ps = null; ResultSet rs = null; @@ -2281,94 +1727,42 @@ rs = ps.executeQuery(); while (rs.next()) { - trigList.add(selectTrigger(conn, - rs.getString(COL_TRIGGER_NAME), rs - .getString(COL_TRIGGER_GROUP))); + trigList.add(selectTrigger(conn, triggerKey(rs.getString(COL_TRIGGER_NAME), rs.getString(COL_TRIGGER_GROUP)))); } } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } - return (Trigger[]) trigList.toArray(new Trigger[trigList.size()]); + return trigList; } - - public List selectStatefulJobsOfTriggerGroup(Connection conn, - String groupName) throws SQLException { - ArrayList jobList = new ArrayList(); - PreparedStatement ps = null; - ResultSet rs = null; - try { - ps = conn - .prepareStatement(rtp(SELECT_STATEFUL_JOBS_OF_TRIGGER_GROUP)); - ps.setString(1, groupName); - ps.setBoolean(2, true); - rs = ps.executeQuery(); - - while (rs.next()) { - jobList.add(new Key(rs.getString(COL_JOB_NAME), rs - .getString(COL_JOB_GROUP))); - } - } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - - return jobList; - } - /** *

* Select a trigger. *

* * @param conn * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger * @return the {@link org.quartz.Trigger} object + * @throws JobPersistenceException */ - public Trigger selectTrigger(Connection conn, String triggerName, - String groupName) throws SQLException, ClassNotFoundException, - IOException { + public OperableTrigger selectTrigger(Connection conn, TriggerKey triggerKey) throws SQLException, ClassNotFoundException, + IOException, JobPersistenceException { PreparedStatement ps = null; ResultSet rs = null; try { - Trigger trigger = null; + OperableTrigger trigger = null; ps = conn.prepareStatement(rtp(SELECT_TRIGGER)); - ps.setString(1, triggerName); - ps.setString(2, groupName); + ps.setString(1, triggerKey.getName()); + ps.setString(2, triggerKey.getGroup()); rs = ps.executeQuery(); if (rs.next()) { String jobName = rs.getString(COL_JOB_NAME); String jobGroup = rs.getString(COL_JOB_GROUP); - boolean volatility = rs.getBoolean(COL_IS_VOLATILE); String description = rs.getString(COL_DESCRIPTION); long nextFireTime = rs.getLong(COL_NEXT_FIRE_TIME); long prevFireTime = rs.getLong(COL_PREV_FIRE_TIME); @@ -2377,16 +1771,20 @@ long endTime = rs.getLong(COL_END_TIME); String calendarName = rs.getString(COL_CALENDAR_NAME); int misFireInstr = rs.getInt(COL_MISFIRE_INSTRUCTION); + int priority = rs.getInt(COL_PRIORITY); - Map map = null; - if (canUseProperties()) map = getMapFromProperties(rs); - else - map = (Map) getObjectFromBlob(rs, COL_JOB_DATAMAP); + Map map = null; + if (canUseProperties()) { + map = getMapFromProperties(rs); + } else { + map = (Map) getObjectFromBlob(rs, COL_JOB_DATAMAP); + } Date nft = null; if (nextFireTime > 0) { nft = new Date(nextFireTime); } + Date pft = null; if (prevFireTime > 0) { pft = new Date(prevFireTime); @@ -2397,103 +1795,86 @@ endTimeD = new Date(endTime); } - rs.close(); - ps.close(); + if (triggerType.equals(TTYPE_BLOB)) { + rs.close(); rs = null; + ps.close(); ps = null; - if (triggerType.equals(TTYPE_SIMPLE)) { - ps = conn.prepareStatement(rtp(SELECT_SIMPLE_TRIGGER)); - ps.setString(1, triggerName); - ps.setString(2, groupName); + ps = conn.prepareStatement(rtp(SELECT_BLOB_TRIGGER)); + ps.setString(1, triggerKey.getName()); + ps.setString(2, triggerKey.getGroup()); rs = ps.executeQuery(); if (rs.next()) { - int repeatCount = rs.getInt(COL_REPEAT_COUNT); - long repeatInterval = rs.getLong(COL_REPEAT_INTERVAL); - int timesTriggered = rs.getInt(COL_TIMES_TRIGGERED); - - SimpleTrigger st = new SimpleTrigger(triggerName, - groupName, jobName, jobGroup, startTimeD, - endTimeD, repeatCount, repeatInterval); - st.setCalendarName(calendarName); - st.setMisfireInstruction(misFireInstr); - st.setTimesTriggered(timesTriggered); - st.setVolatility(volatility); - st.setNextFireTime(nft); - st.setPreviousFireTime(pft); - st.setDescription(description); - if (null != map) { - st.setJobDataMap(new JobDataMap(map)); - } - trigger = st; + trigger = (OperableTrigger) getObjectFromBlob(rs, COL_BLOB); } - } else if (triggerType.equals(TTYPE_CRON)) { - ps = conn.prepareStatement(rtp(SELECT_CRON_TRIGGER)); - ps.setString(1, triggerName); - ps.setString(2, groupName); - rs = ps.executeQuery(); + } + else { + TriggerPersistenceDelegate tDel = findTriggerPersistenceDelegate(triggerType); + + if(tDel == null) + throw new JobPersistenceException("No TriggerPersistenceDelegate for trigger discriminator type: " + triggerType); - if (rs.next()) { - String cronExpr = rs.getString(COL_CRON_EXPRESSION); - String timeZoneId = rs.getString(COL_TIME_ZONE_ID); - - CronTrigger ct = null; - try { - TimeZone timeZone = null; - if (timeZoneId != null) { - timeZone = TimeZone.getTimeZone(timeZoneId); - } - ct = new CronTrigger(triggerName, groupName, - jobName, jobGroup, startTimeD, endTimeD, - cronExpr, timeZone); - } catch (Exception neverHappens) { - // expr must be valid, or it never would have - // gotten to the store... + TriggerPropertyBundle triggerProps = null; + try { + triggerProps = tDel.loadExtendedTriggerProperties(conn, triggerKey); + } catch (IllegalStateException isex) { + if (isTriggerStillPresent(ps)) { + throw isex; + } else { + // QTZ-386 Trigger has been deleted + return null; } - if (null != ct) { - ct.setCalendarName(calendarName); - ct.setMisfireInstruction(misFireInstr); - ct.setVolatility(volatility); - ct.setNextFireTime(nft); - ct.setPreviousFireTime(pft); - ct.setDescription(description); - if (null != map) { - ct.setJobDataMap(new JobDataMap(map)); - } - trigger = ct; - } } - } else if (triggerType.equals(TTYPE_BLOB)) { - ps = conn.prepareStatement(rtp(SELECT_BLOB_TRIGGER)); - ps.setString(1, triggerName); - ps.setString(2, groupName); - rs = ps.executeQuery(); - if (rs.next()) { - trigger = (Trigger) getObjectFromBlob(rs, COL_BLOB); + TriggerBuilder tb = newTrigger() + .withDescription(description) + .withPriority(priority) + .startAt(startTimeD) + .endAt(endTimeD) + .withIdentity(triggerKey) + .modifiedByCalendar(calendarName) + .withSchedule(triggerProps.getScheduleBuilder()) + .forJob(jobKey(jobName, jobGroup)); + + if (null != map) { + tb.usingJobData(new JobDataMap(map)); } - } else { - throw new ClassNotFoundException("class for trigger type '" - + triggerType + "' not found."); - } + + trigger = (OperableTrigger) tb.build(); + + trigger.setMisfireInstruction(misFireInstr); + trigger.setNextFireTime(nft); + trigger.setPreviousFireTime(pft); + + setTriggerStateProperties(trigger, triggerProps); + } } return trigger; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } + private boolean isTriggerStillPresent(PreparedStatement ps) throws SQLException { + ResultSet rs = null; + try { + rs = ps.executeQuery(); + return rs.next(); + } finally { + closeResultSet(rs); + } + } + + private void setTriggerStateProperties(OperableTrigger trigger, TriggerPropertyBundle props) throws JobPersistenceException { + + if(props.getStatePropertyNames() == null) + return; + + Util.setBeanProps(trigger, props.getStatePropertyNames(), props.getStatePropertyValues()); + } + /** *

* Select a trigger's JobDataMap. @@ -2516,20 +1897,19 @@ ResultSet rs = null; try { - Trigger trigger = null; - ps = conn.prepareStatement(rtp(SELECT_TRIGGER_DATA)); ps.setString(1, triggerName); ps.setString(2, groupName); rs = ps.executeQuery(); if (rs.next()) { - Map map = null; - if (canUseProperties()) + Map map = null; + if (canUseProperties()) { map = getMapFromProperties(rs); - else - map = (Map) getObjectFromBlob(rs, COL_JOB_DATAMAP); + } else { + map = (Map) getObjectFromBlob(rs, COL_JOB_DATAMAP); + } rs.close(); ps.close(); @@ -2539,18 +1919,8 @@ } } } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } return new JobDataMap(); @@ -2564,44 +1934,30 @@ * * @param conn * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger * @return the {@link org.quartz.Trigger} object */ - public String selectTriggerState(Connection conn, String triggerName, - String groupName) throws SQLException { + public String selectTriggerState(Connection conn, TriggerKey triggerKey) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { String state = null; ps = conn.prepareStatement(rtp(SELECT_TRIGGER_STATE)); - ps.setString(1, triggerName); - ps.setString(2, groupName); + ps.setString(1, triggerKey.getName()); + ps.setString(2, triggerKey.getGroup()); rs = ps.executeQuery(); if (rs.next()) { state = rs.getString(COL_TRIGGER_STATE); - } else + } else { state = STATE_DELETED; + } return state.intern(); } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -2613,23 +1969,19 @@ * * @param conn * the DB Connection - * @param triggerName - * the name of the trigger - * @param groupName - * the group containing the trigger * @return a TriggerStatus object, or null */ public TriggerStatus selectTriggerStatus(Connection conn, - String triggerName, String groupName) throws SQLException { + TriggerKey triggerKey) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { TriggerStatus status = null; ps = conn.prepareStatement(rtp(SELECT_TRIGGER_STATUS)); - ps.setString(1, triggerName); - ps.setString(2, groupName); + ps.setString(1, triggerKey.getName()); + ps.setString(2, triggerKey.getGroup()); rs = ps.executeQuery(); if (rs.next()) { @@ -2644,24 +1996,14 @@ } status = new TriggerStatus(state, nft); - status.setKey(new Key(triggerName, groupName)); - status.setJobKey(new Key(jobName, jobGroup)); + status.setKey(triggerKey); + status.setJobKey(jobKey(jobName, jobGroup)); } return status; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -2690,18 +2032,8 @@ return count; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -2714,36 +2046,44 @@ * the DB Connection * @return an array of String group names */ - public String[] selectTriggerGroups(Connection conn) throws SQLException { + public List selectTriggerGroups(Connection conn) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_TRIGGER_GROUPS)); rs = ps.executeQuery(); - ArrayList list = new ArrayList(); + LinkedList list = new LinkedList(); while (rs.next()) { list.add(rs.getString(1)); } - Object[] oArr = list.toArray(); - String[] sArr = new String[oArr.length]; - System.arraycopy(oArr, 0, sArr, 0, oArr.length); - return sArr; + return list; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } + closeResultSet(rs); + closeStatement(ps); + } + } + + public List selectTriggerGroups(Connection conn, GroupMatcher matcher) throws SQLException { + PreparedStatement ps = null; + ResultSet rs = null; + + try { + ps = conn.prepareStatement(rtp(SELECT_TRIGGER_GROUPS_FILTERED)); + ps.setString(1, toSqlLikeClause(matcher)); + rs = ps.executeQuery(); + + LinkedList list = new LinkedList(); + while (rs.next()) { + list.add(rs.getString(1)); } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + + return list; + } finally { + closeResultSet(rs); + closeStatement(ps); } } @@ -2754,47 +2094,40 @@ * * @param conn * the DB Connection - * @param groupName - * the group containing the triggers - * @return an array of String trigger names + * @param matcher + * to evaluate against known triggers + * @return a Set of TriggerKeys */ - public String[] selectTriggersInGroup(Connection conn, String groupName) - throws SQLException { + public Set selectTriggersInGroup(Connection conn, GroupMatcher matcher) + throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { - ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_IN_GROUP)); - ps.setString(1, groupName); + if(isMatcherEquals(matcher)) { + ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_IN_GROUP)); + ps.setString(1, toSqlEqualsClause(matcher)); + } + else { + ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_IN_GROUP_LIKE)); + ps.setString(1, toSqlLikeClause(matcher)); + } rs = ps.executeQuery(); - ArrayList list = new ArrayList(); + Set keys = new HashSet(); while (rs.next()) { - list.add(rs.getString(1)); + keys.add(triggerKey(rs.getString(1), rs.getString(2))); } - Object[] oArr = list.toArray(); - String[] sArr = new String[oArr.length]; - System.arraycopy(oArr, 0, sArr, 0, oArr.length); - return sArr; + return keys; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } public int insertPausedTriggerGroup(Connection conn, String groupName) - throws SQLException { + throws SQLException { PreparedStatement ps = null; try { @@ -2804,17 +2137,12 @@ return rows; } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } public int deletePausedTriggerGroup(Connection conn, String groupName) - throws SQLException { + throws SQLException { PreparedStatement ps = null; try { @@ -2824,17 +2152,27 @@ return rows; } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } + public int deletePausedTriggerGroup(Connection conn, GroupMatcher matcher) + throws SQLException { + PreparedStatement ps = null; + + try { + ps = conn.prepareStatement(rtp(DELETE_PAUSED_TRIGGER_GROUP)); + ps.setString(1, toSqlLikeClause(matcher)); + int rows = ps.executeUpdate(); + + return rows; + } finally { + closeStatement(ps); + } + } + public int deleteAllPausedTriggerGroups(Connection conn) - throws SQLException { + throws SQLException { PreparedStatement ps = null; try { @@ -2843,17 +2181,12 @@ return rows; } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } public boolean isTriggerGroupPaused(Connection conn, String groupName) - throws SQLException { + throws SQLException { PreparedStatement ps = null; ResultSet rs = null; @@ -2864,23 +2197,13 @@ return rs.next(); } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } public boolean isExistingTriggerGroup(Connection conn, String groupName) - throws SQLException { + throws SQLException { PreparedStatement ps = null; ResultSet rs = null; @@ -2889,22 +2212,14 @@ ps.setString(1, groupName); rs = ps.executeQuery(); - if (!rs.next()) return false; + if (!rs.next()) { + return false; + } return (rs.getInt(1) > 0); } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -2936,16 +2251,11 @@ try { ps = conn.prepareStatement(rtp(INSERT_CALENDAR)); ps.setString(1, calendarName); - ps.setBytes(2, baos.toByteArray()); + setBytes(ps, 2, baos); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } @@ -2972,17 +2282,12 @@ try { ps = conn.prepareStatement(rtp(UPDATE_CALENDAR)); - ps.setBytes(1, baos.toByteArray()); + setBytes(ps, 1, baos); ps.setString(2, calendarName); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } @@ -2998,7 +2303,7 @@ * @return true if the trigger exists, false otherwise */ public boolean calendarExists(Connection conn, String calendarName) - throws SQLException { + throws SQLException { PreparedStatement ps = null; ResultSet rs = null; @@ -3013,18 +2318,8 @@ return false; } } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -3045,7 +2340,7 @@ * if there were problems deserializing the calendar */ public Calendar selectCalendar(Connection conn, String calendarName) - throws ClassNotFoundException, IOException, SQLException { + throws ClassNotFoundException, IOException, SQLException { PreparedStatement ps = null; ResultSet rs = null; try { @@ -3064,18 +2359,8 @@ } return cal; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -3091,7 +2376,7 @@ * @return true if any triggers reference the calendar, false otherwise */ public boolean calendarIsReferenced(Connection conn, String calendarName) - throws SQLException { + throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { @@ -3105,18 +2390,8 @@ return false; } } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -3132,7 +2407,7 @@ * @return the number of rows deleted */ public int deleteCalendar(Connection conn, String calendarName) - throws SQLException { + throws SQLException { PreparedStatement ps = null; try { @@ -3141,12 +2416,7 @@ return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } @@ -3175,18 +2445,8 @@ return count; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -3199,36 +2459,23 @@ * the DB Connection * @return an array of String calendar names */ - public String[] selectCalendars(Connection conn) throws SQLException { + public List selectCalendars(Connection conn) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_CALENDARS)); rs = ps.executeQuery(); - ArrayList list = new ArrayList(); + LinkedList list = new LinkedList(); while (rs.next()) { list.add(rs.getString(1)); } - Object[] oArr = list.toArray(); - String[] sArr = new String[oArr.length]; - System.arraycopy(oArr, 0, sArr, 0, oArr.length); - return sArr; + return list; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -3244,6 +2491,8 @@ * @param conn * the DB Connection * @return the next fire time, or 0 if no trigger will be fired + * + * @deprecated Does not account for misfires. */ public long selectNextFireTime(Connection conn) throws SQLException { PreparedStatement ps = null; @@ -3259,18 +2508,8 @@ return 0l; } } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -3287,8 +2526,8 @@ * trigger that will be fired at the given fire time, or null if no * trigger will be fired at that time */ - public Key selectTriggerForFireTime(Connection conn, long fireTime) - throws SQLException { + public TriggerKey selectTriggerForFireTime(Connection conn, long fireTime) + throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { @@ -3298,29 +2537,96 @@ rs = ps.executeQuery(); if (rs.next()) { - return new Key(rs.getString(COL_TRIGGER_NAME), rs + return new TriggerKey(rs.getString(COL_TRIGGER_NAME), rs .getString(COL_TRIGGER_GROUP)); } else { return null; } } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } + + /** *

+ * Select the next trigger which will fire to fire between the two given timestamps + * in ascending order of fire time, and then descending by priority. + *

+ * + * @param conn + * the DB Connection + * @param noLaterThan + * highest value of getNextFireTime() of the triggers (exclusive) + * @param noEarlierThan + * highest value of getNextFireTime() of the triggers (inclusive) + * + * @return A (never null, possibly empty) list of the identifiers (Key objects) of the next triggers to be fired. + * + * @deprecated - This remained for compatibility reason. Use {@link #selectTriggerToAcquire(Connection, long, long, int)} instead. + */ + public List selectTriggerToAcquire(Connection conn, long noLaterThan, long noEarlierThan) + throws SQLException { + // This old API used to always return 1 trigger. + return selectTriggerToAcquire(conn, noLaterThan, noEarlierThan, 1); + } + + /** + *

+ * Select the next trigger which will fire to fire between the two given timestamps + * in ascending order of fire time, and then descending by priority. + *

+ * + * @param conn + * the DB Connection + * @param noLaterThan + * highest value of getNextFireTime() of the triggers (exclusive) + * @param noEarlierThan + * highest value of getNextFireTime() of the triggers (inclusive) + * @param maxCount + * maximum number of trigger keys allow to acquired in the returning list. + * + * @return A (never null, possibly empty) list of the identifiers (Key objects) of the next triggers to be fired. + */ + public List selectTriggerToAcquire(Connection conn, long noLaterThan, long noEarlierThan, int maxCount) + throws SQLException { + PreparedStatement ps = null; + ResultSet rs = null; + List nextTriggers = new LinkedList(); + try { + ps = conn.prepareStatement(rtp(SELECT_NEXT_TRIGGER_TO_ACQUIRE)); + + // Set max rows to retrieve + if (maxCount < 1) + maxCount = 1; // we want at least one trigger back. + ps.setMaxRows(maxCount); + + // Try to give jdbc driver a hint to hopefully not pull over more than the few rows we actually need. + // Note: in some jdbc drivers, such as MySQL, you must set maxRows before fetchSize, or you get exception! + ps.setFetchSize(maxCount); + + ps.setString(1, STATE_WAITING); + ps.setBigDecimal(2, new BigDecimal(String.valueOf(noLaterThan))); + ps.setBigDecimal(3, new BigDecimal(String.valueOf(noEarlierThan))); + rs = ps.executeQuery(); + + while (rs.next() && nextTriggers.size() <= maxCount) { + nextTriggers.add(triggerKey( + rs.getString(COL_TRIGGER_NAME), + rs.getString(COL_TRIGGER_GROUP))); + } + + return nextTriggers; + } finally { + closeResultSet(rs); + closeStatement(ps); + } + } + + /** + *

* Insert a fired trigger. *

* @@ -3332,56 +2638,96 @@ * the state that the trigger should be stored in * @return the number of rows inserted */ - public int insertFiredTrigger(Connection conn, Trigger trigger, + public int insertFiredTrigger(Connection conn, OperableTrigger trigger, String state, JobDetail job) throws SQLException { PreparedStatement ps = null; try { ps = conn.prepareStatement(rtp(INSERT_FIRED_TRIGGER)); ps.setString(1, trigger.getFireInstanceId()); - ps.setString(2, trigger.getName()); - ps.setString(3, trigger.getGroup()); - ps.setBoolean(4, trigger.isVolatile()); - ps.setString(5, instanceId); - ps.setBigDecimal(6, new BigDecimal(String.valueOf(trigger - .getNextFireTime().getTime()))); + ps.setString(2, trigger.getKey().getName()); + ps.setString(3, trigger.getKey().getGroup()); + ps.setString(4, instanceId); + ps.setBigDecimal(5, new BigDecimal(String.valueOf(System.currentTimeMillis()))); + ps.setBigDecimal(6, new BigDecimal(String.valueOf(trigger.getNextFireTime().getTime()))); ps.setString(7, state); if (job != null) { - ps.setString(8, trigger.getJobName()); - ps.setString(9, trigger.getJobGroup()); - ps.setBoolean(10, job.isStateful()); - ps.setBoolean(11, job.requestsRecovery()); + ps.setString(8, trigger.getJobKey().getName()); + ps.setString(9, trigger.getJobKey().getGroup()); + setBoolean(ps, 10, job.isConcurrentExectionDisallowed()); + setBoolean(ps, 11, job.requestsRecovery()); } else { ps.setString(8, null); ps.setString(9, null); - ps.setBoolean(10, false); - ps.setBoolean(11, false); + setBoolean(ps, 10, false); + setBoolean(ps, 11, false); } + ps.setInt(12, trigger.getPriority()); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } /** *

+ * Update a fired trigger. + *

+ * + * @param conn + * the DB Connection + * @param trigger + * the trigger + * @param state + * the state that the trigger should be stored in + * @return the number of rows inserted + */ + public int updateFiredTrigger(Connection conn, OperableTrigger trigger, + String state, JobDetail job) throws SQLException { + PreparedStatement ps = null; + try { + ps = conn.prepareStatement(rtp(UPDATE_FIRED_TRIGGER)); + + ps.setString(1, instanceId); + + ps.setBigDecimal(2, new BigDecimal(String.valueOf(System.currentTimeMillis()))); + ps.setBigDecimal(3, new BigDecimal(String.valueOf(trigger.getNextFireTime().getTime()))); + ps.setString(4, state); + + if (job != null) { + ps.setString(5, trigger.getJobKey().getName()); + ps.setString(6, trigger.getJobKey().getGroup()); + setBoolean(ps, 7, job.isConcurrentExectionDisallowed()); + setBoolean(ps, 8, job.requestsRecovery()); + } else { + ps.setString(5, null); + ps.setString(6, null); + setBoolean(ps, 7, false); + setBoolean(ps, 8, false); + } + + ps.setString(9, trigger.getFireInstanceId()); + + + return ps.executeUpdate(); + } finally { + closeStatement(ps); + } + } + + /** + *

* Select the states of all fired-trigger records for a given trigger, or * trigger group if trigger name is null. *

* * @return a List of FiredTriggerRecord objects. */ - public List selectFiredTriggerRecords(Connection conn, String triggerName, - String groupName) throws SQLException { + public List selectFiredTriggerRecords(Connection conn, String triggerName, String groupName) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { - List lst = new LinkedList(); + List lst = new LinkedList(); if (triggerName != null) { ps = conn.prepareStatement(rtp(SELECT_FIRED_TRIGGER)); @@ -3399,34 +2745,25 @@ rec.setFireInstanceId(rs.getString(COL_ENTRY_ID)); rec.setFireInstanceState(rs.getString(COL_ENTRY_STATE)); rec.setFireTimestamp(rs.getLong(COL_FIRED_TIME)); + rec.setScheduleTimestamp(rs.getLong(COL_SCHED_TIME)); + rec.setPriority(rs.getInt(COL_PRIORITY)); rec.setSchedulerInstanceId(rs.getString(COL_INSTANCE_NAME)); - rec.setTriggerIsVolatile(rs.getBoolean(COL_IS_VOLATILE)); - rec.setTriggerKey(new Key(rs.getString(COL_TRIGGER_NAME), rs + rec.setTriggerKey(triggerKey(rs.getString(COL_TRIGGER_NAME), rs .getString(COL_TRIGGER_GROUP))); if (!rec.getFireInstanceState().equals(STATE_ACQUIRED)) { - rec.setJobIsStateful(rs.getBoolean(COL_IS_STATEFUL)); + rec.setJobDisallowsConcurrentExecution(getBoolean(rs, COL_IS_NONCONCURRENT)); rec.setJobRequestsRecovery(rs .getBoolean(COL_REQUESTS_RECOVERY)); - rec.setJobKey(new Key(rs.getString(COL_JOB_NAME), rs + rec.setJobKey(jobKey(rs.getString(COL_JOB_NAME), rs .getString(COL_JOB_GROUP))); } lst.add(rec); } return lst; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -3438,12 +2775,11 @@ * * @return a List of FiredTriggerRecord objects. */ - public List selectFiredTriggerRecordsByJob(Connection conn, String jobName, - String groupName) throws SQLException { + public List selectFiredTriggerRecordsByJob(Connection conn, String jobName, String groupName) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { - List lst = new LinkedList(); + List lst = new LinkedList(); if (jobName != null) { ps = conn.prepareStatement(rtp(SELECT_FIRED_TRIGGERS_OF_JOB)); @@ -3462,44 +2798,35 @@ rec.setFireInstanceId(rs.getString(COL_ENTRY_ID)); rec.setFireInstanceState(rs.getString(COL_ENTRY_STATE)); rec.setFireTimestamp(rs.getLong(COL_FIRED_TIME)); + rec.setScheduleTimestamp(rs.getLong(COL_SCHED_TIME)); + rec.setPriority(rs.getInt(COL_PRIORITY)); rec.setSchedulerInstanceId(rs.getString(COL_INSTANCE_NAME)); - rec.setTriggerIsVolatile(rs.getBoolean(COL_IS_VOLATILE)); - rec.setTriggerKey(new Key(rs.getString(COL_TRIGGER_NAME), rs + rec.setTriggerKey(triggerKey(rs.getString(COL_TRIGGER_NAME), rs .getString(COL_TRIGGER_GROUP))); if (!rec.getFireInstanceState().equals(STATE_ACQUIRED)) { - rec.setJobIsStateful(rs.getBoolean(COL_IS_STATEFUL)); + rec.setJobDisallowsConcurrentExecution(getBoolean(rs, COL_IS_NONCONCURRENT)); rec.setJobRequestsRecovery(rs .getBoolean(COL_REQUESTS_RECOVERY)); - rec.setJobKey(new Key(rs.getString(COL_JOB_NAME), rs + rec.setJobKey(jobKey(rs.getString(COL_JOB_NAME), rs .getString(COL_JOB_GROUP))); } lst.add(rec); } return lst; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } - public List selectInstancesFiredTriggerRecords(Connection conn, + public List selectInstancesFiredTriggerRecords(Connection conn, String instanceName) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { - List lst = new LinkedList(); + List lst = new LinkedList(); ps = conn.prepareStatement(rtp(SELECT_INSTANCES_FIRED_TRIGGERS)); ps.setString(1, instanceName); @@ -3511,39 +2838,63 @@ rec.setFireInstanceId(rs.getString(COL_ENTRY_ID)); rec.setFireInstanceState(rs.getString(COL_ENTRY_STATE)); rec.setFireTimestamp(rs.getLong(COL_FIRED_TIME)); + rec.setScheduleTimestamp(rs.getLong(COL_SCHED_TIME)); rec.setSchedulerInstanceId(rs.getString(COL_INSTANCE_NAME)); - rec.setTriggerIsVolatile(rs.getBoolean(COL_IS_VOLATILE)); - rec.setTriggerKey(new Key(rs.getString(COL_TRIGGER_NAME), rs + rec.setTriggerKey(triggerKey(rs.getString(COL_TRIGGER_NAME), rs .getString(COL_TRIGGER_GROUP))); if (!rec.getFireInstanceState().equals(STATE_ACQUIRED)) { - rec.setJobIsStateful(rs.getBoolean(COL_IS_STATEFUL)); + rec.setJobDisallowsConcurrentExecution(getBoolean(rs, COL_IS_NONCONCURRENT)); rec.setJobRequestsRecovery(rs .getBoolean(COL_REQUESTS_RECOVERY)); - rec.setJobKey(new Key(rs.getString(COL_JOB_NAME), rs + rec.setJobKey(jobKey(rs.getString(COL_JOB_NAME), rs .getString(COL_JOB_GROUP))); } + rec.setPriority(rs.getInt(COL_PRIORITY)); lst.add(rec); } return lst; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } /** *

+ * Select the distinct instance names of all fired-trigger records. + *

+ * + *

+ * This is useful when trying to identify orphaned fired triggers (a + * fired trigger without a scheduler state record.) + *

+ * + * @return a Set of String objects. + */ + public Set selectFiredTriggerInstanceNames(Connection conn) + throws SQLException { + PreparedStatement ps = null; + ResultSet rs = null; + try { + Set instanceNames = new HashSet(); + + ps = conn.prepareStatement(rtp(SELECT_FIRED_TRIGGER_INSTANCE_NAMES)); + rs = ps.executeQuery(); + + while (rs.next()) { + instanceNames.add(rs.getString(COL_INSTANCE_NAME)); + } + + return instanceNames; + } finally { + closeResultSet(rs); + closeStatement(ps); + } + } + + /** + *

* Delete a fired trigger. *

* @@ -3554,142 +2905,89 @@ * @return the number of rows deleted */ public int deleteFiredTrigger(Connection conn, String entryId) - throws SQLException { + throws SQLException { PreparedStatement ps = null; try { ps = conn.prepareStatement(rtp(DELETE_FIRED_TRIGGER)); ps.setString(1, entryId); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } - public int selectJobExecutionCount(Connection conn, String jobName, - String jobGroup) throws SQLException { + public int selectJobExecutionCount(Connection conn, JobKey jobKey) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_JOB_EXECUTION_COUNT)); - ps.setString(1, jobName); - ps.setString(2, jobGroup); + ps.setString(1, jobKey.getName()); + ps.setString(2, jobKey.getGroup()); rs = ps.executeQuery(); - if (rs.next()) return rs.getInt(1); - else - return 0; - + return (rs.next()) ? rs.getInt(1) : 0; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } - - public int deleteVolatileFiredTriggers(Connection conn) throws SQLException { + + public int insertSchedulerState(Connection conn, String theInstanceId, + long checkInTime, long interval) + throws SQLException { PreparedStatement ps = null; try { - ps = conn.prepareStatement(rtp(DELETE_VOLATILE_FIRED_TRIGGERS)); - ps.setBoolean(1, true); - - return ps.executeUpdate(); - } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - - public int insertSchedulerState(Connection conn, String instanceId, - long checkInTime, long interval, String recoverer) - throws SQLException { - PreparedStatement ps = null; - try { ps = conn.prepareStatement(rtp(INSERT_SCHEDULER_STATE)); - ps.setString(1, instanceId); + ps.setString(1, theInstanceId); ps.setLong(2, checkInTime); ps.setLong(3, interval); - ps.setString(4, recoverer); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } - public int deleteSchedulerState(Connection conn, String instanceId) - throws SQLException { + public int deleteSchedulerState(Connection conn, String theInstanceId) + throws SQLException { PreparedStatement ps = null; try { ps = conn.prepareStatement(rtp(DELETE_SCHEDULER_STATE)); - ps.setString(1, instanceId); + ps.setString(1, theInstanceId); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } - public int updateSchedulerState(Connection conn, String instanceId, long checkInTime, String recoverer) - throws SQLException { + public int updateSchedulerState(Connection conn, String theInstanceId, long checkInTime) + throws SQLException { PreparedStatement ps = null; try { ps = conn.prepareStatement(rtp(UPDATE_SCHEDULER_STATE)); ps.setLong(1, checkInTime); - ps.setString(2, recoverer); - ps.setString(3, instanceId); + ps.setString(2, theInstanceId); return ps.executeUpdate(); } finally { - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeStatement(ps); } } - public List selectSchedulerStateRecords(Connection conn, String instanceId) - throws SQLException { + public List selectSchedulerStateRecords(Connection conn, String theInstanceId) + throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { - List lst = new LinkedList(); + List lst = new LinkedList(); - if (instanceId != null) { + if (theInstanceId != null) { ps = conn.prepareStatement(rtp(SELECT_SCHEDULER_STATE)); - ps.setString(1, instanceId); + ps.setString(1, theInstanceId); } else { ps = conn.prepareStatement(rtp(SELECT_SCHEDULER_STATES)); } @@ -3701,25 +2999,14 @@ rec.setSchedulerInstanceId(rs.getString(COL_INSTANCE_NAME)); rec.setCheckinTimestamp(rs.getLong(COL_LAST_CHECKIN_TIME)); rec.setCheckinInterval(rs.getLong(COL_CHECKIN_INTERVAL)); - rec.setRecoverer(rs.getString(COL_RECOVERER)); lst.add(rec); } return lst; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } + closeResultSet(rs); + closeStatement(ps); } } @@ -3739,9 +3026,16 @@ * @return the query, with proper table prefix substituted */ protected final String rtp(String query) { - return Util.rtp(query, tablePrefix); + return Util.rtp(query, tablePrefix, getSchedulerNameLiteral()); } + private String schedNameLiteral = null; + protected String getSchedulerNameLiteral() { + if(schedNameLiteral == null) + schedNameLiteral = "'" + schedName + "'"; + return schedNameLiteral; + } + /** *

* Create a serialized java.util.ByteArrayOutputStream @@ -3755,7 +3049,7 @@ * if serialization causes an error */ protected ByteArrayOutputStream serializeObject(Object obj) - throws IOException { + throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); if (null != obj) { ObjectOutputStream out = new ObjectOutputStream(baos); @@ -3771,29 +3065,61 @@ * version of a {@link org.quartz.JobDataMap}. *

* - * @param obj - * the object to serialize + * @param data + * the JobDataMap to serialize * @return the serialized ByteArrayOutputStream * @throws IOException * if serialization causes an error */ protected ByteArrayOutputStream serializeJobData(JobDataMap data) - throws IOException { - if (canUseProperties()) return serializeProperties(data); + throws IOException { + if (canUseProperties()) { + return serializeProperties(data); + } - if (null != data) { - data.removeTransientData(); + try { return serializeObject(data); - } else { - return serializeObject(null); + } catch (NotSerializableException e) { + throw new NotSerializableException( + "Unable to serialize JobDataMap for insertion into " + + "database because the value of property '" + + getKeyOfNonSerializableValue(data) + + "' is not serializable: " + e.getMessage()); } } /** + * Find the key of the first non-serializable value in the given Map. + * + * @return The key of the first non-serializable value in the given Map or + * null if all values are serializable. + */ + protected Object getKeyOfNonSerializableValue(Map data) { + for (Iterator entryIter = data.entrySet().iterator(); entryIter.hasNext();) { + Map.Entry entry = (Map.Entry)entryIter.next(); + + ByteArrayOutputStream baos = null; + try { + baos = serializeObject(entry.getValue()); + } catch (IOException e) { + return entry.getKey(); + } finally { + if (baos != null) { + try { baos.close(); } catch (IOException ignore) {} + } + } + } + + // As long as it is true that the Map was not serializable, we should + // not hit this case. + return null; + } + + /** * serialize the java.util.Properties */ private ByteArrayOutputStream serializeProperties(JobDataMap data) - throws IOException { + throws IOException { ByteArrayOutputStream ba = new ByteArrayOutputStream(); if (null != data) { Properties properties = convertToProperty(data.getWrappedMap()); @@ -3806,40 +3132,37 @@ /** * convert the JobDataMap into a list of properties */ - protected Map convertFromProperty(Properties properties) throws IOException { - Map data = new HashMap(); - Set keys = properties.keySet(); - Iterator it = keys.iterator(); - while (it.hasNext()) { - Object key = it.next(); - Object val = properties.get(key); - data.put(key, val); - } - - return data; + protected Map convertFromProperty(Properties properties) throws IOException { + return new HashMap(properties); } /** * convert the JobDataMap into a list of properties */ - protected Properties convertToProperty(Map data) throws IOException { + protected Properties convertToProperty(Map data) throws IOException { Properties properties = new Properties(); - Set keys = data.keySet(); - Iterator it = keys.iterator(); - while (it.hasNext()) { - Object key = it.next(); - Object val = data.get(key); - if(!(key instanceof String)) + + for (Iterator entryIter = data.entrySet().iterator(); entryIter.hasNext();) { + Map.Entry entry = (Map.Entry)entryIter.next(); + + Object key = entry.getKey(); + Object val = (entry.getValue() == null) ? "" : entry.getValue(); + + if(!(key instanceof String)) { throw new IOException("JobDataMap keys/values must be Strings " + "when the 'useProperties' property is set. " + " offending Key: " + key); - if(!(val instanceof String)) + } + + if(!(val instanceof String)) { throw new IOException("JobDataMap values must be Strings " + "when the 'useProperties' property is set. " + " Key of offending value: " + key); - if (val == null) val = ""; + } + properties.put(key, val); } + return properties; } @@ -3861,90 +3184,29 @@ * if deserialization causes an error */ protected Object getObjectFromBlob(ResultSet rs, String colName) - throws ClassNotFoundException, IOException, SQLException { + throws ClassNotFoundException, IOException, SQLException { Object obj = null; Blob blobLocator = rs.getBlob(colName); - if (blobLocator != null) { + if (blobLocator != null && blobLocator.length() != 0) { InputStream binaryInput = blobLocator.getBinaryStream(); if (null != binaryInput) { - ObjectInputStream in = new ObjectInputStream(binaryInput); - obj = in.readObject(); - in.close(); - } - } - return obj; - } - - public Key[] selectVolatileTriggers(Connection conn) throws SQLException { - PreparedStatement ps = null; - ResultSet rs = null; - - try { - ps = conn.prepareStatement(rtp(SELECT_VOLATILE_TRIGGERS)); - ps.setBoolean(1, true); - rs = ps.executeQuery(); - - ArrayList list = new ArrayList(); - while (rs.next()) { - String triggerName = rs.getString(COL_TRIGGER_NAME); - String groupName = rs.getString(COL_TRIGGER_GROUP); - list.add(new Key(triggerName, groupName)); - } - Object[] oArr = list.toArray(); - Key[] kArr = new Key[oArr.length]; - System.arraycopy(oArr, 0, kArr, 0, oArr.length); - return kArr; - } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { + if (binaryInput instanceof ByteArrayInputStream + && ((ByteArrayInputStream) binaryInput).available() == 0 ) { + //do nothing + } else { + ObjectInputStream in = new ObjectInputStream(binaryInput); + try { + obj = in.readObject(); + } finally { + in.close(); + } } } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } - } - } - public Key[] selectVolatileJobs(Connection conn) throws SQLException { - PreparedStatement ps = null; - ResultSet rs = null; - - try { - ps = conn.prepareStatement(rtp(SELECT_VOLATILE_JOBS)); - ps.setBoolean(1, true); - rs = ps.executeQuery(); - - ArrayList list = new ArrayList(); - while (rs.next()) { - String triggerName = rs.getString(COL_JOB_NAME); - String groupName = rs.getString(COL_JOB_GROUP); - list.add(new Key(triggerName, groupName)); - } - Object[] oArr = list.toArray(); - Key[] kArr = new Key[oArr.length]; - System.arraycopy(oArr, 0, kArr, 0, oArr.length); - return kArr; - } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } - } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } - } } + return obj; } /** @@ -3964,8 +3226,8 @@ * @throws IOException * if deserialization causes an error */ - protected Object getJobDetailFromBlob(ResultSet rs, String colName) - throws ClassNotFoundException, IOException, SQLException { + protected Object getJobDataFromBlob(ResultSet rs, String colName) + throws ClassNotFoundException, IOException, SQLException { if (canUseProperties()) { Blob blobLocator = rs.getBlob(colName); if (blobLocator != null) { @@ -3982,11 +3244,11 @@ /** * @see org.quartz.impl.jdbcjobstore.DriverDelegate#selectPausedTriggerGroups(java.sql.Connection) */ - public Set selectPausedTriggerGroups(Connection conn) throws SQLException { + public Set selectPausedTriggerGroups(Connection conn) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; - HashSet set = new HashSet(); + HashSet set = new HashSet(); try { ps = conn.prepareStatement(rtp(SELECT_PAUSED_TRIGGER_GROUPS)); rs = ps.executeQuery(); @@ -3997,20 +3259,81 @@ } return set; } finally { - if (null != rs) { - try { - rs.close(); - } catch (SQLException ignore) { - } + closeResultSet(rs); + closeStatement(ps); + } + } + + /** + * Cleanup helper method that closes the given ResultSet + * while ignoring any errors. + */ + protected static void closeResultSet(ResultSet rs) { + if (null != rs) { + try { + rs.close(); + } catch (SQLException ignore) { } - if (null != ps) { - try { - ps.close(); - } catch (SQLException ignore) { - } + } + } + + /** + * Cleanup helper method that closes the given Statement + * while ignoring any errors. + */ + protected static void closeStatement(Statement statement) { + if (null != statement) { + try { + statement.close(); + } catch (SQLException ignore) { } } } + + + /** + * Sets the designated parameter to the given Java boolean value. + * This just wraps {@link PreparedStatement#setBoolean(int, boolean)} + * by default, but it can be overloaded by subclass delegates for databases that + * don't explicitly support the boolean type. + */ + protected void setBoolean(PreparedStatement ps, int index, boolean val) throws SQLException { + ps.setBoolean(index, val); + } + + /** + * Retrieves the value of the designated column in the current row as + * a boolean. + * This just wraps {@link ResultSet#getBoolean(java.lang.String)} + * by default, but it can be overloaded by subclass delegates for databases that + * don't explicitly support the boolean type. + */ + protected boolean getBoolean(ResultSet rs, String columnName) throws SQLException { + return rs.getBoolean(columnName); + } + + /** + * Retrieves the value of the designated column index in the current row as + * a boolean. + * This just wraps {@link ResultSet#getBoolean(java.lang.String)} + * by default, but it can be overloaded by subclass delegates for databases that + * don't explicitly support the boolean type. + */ + protected boolean getBoolean(ResultSet rs, int columnIndex) throws SQLException { + return rs.getBoolean(columnIndex); + } + + /** + * Sets the designated parameter to the byte array of the given + * ByteArrayOutputStream. Will set parameter value to null if the + * ByteArrayOutputStream is null. + * This just wraps {@link PreparedStatement#setBytes(int, byte[])} + * by default, but it can be overloaded by subclass delegates for databases that + * don't explicitly support storing bytes in this way. + */ + protected void setBytes(PreparedStatement ps, int index, ByteArrayOutputStream baos) throws SQLException { + ps.setBytes(index, (baos == null) ? new byte[0] : baos.toByteArray()); + } } // EOF Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/StdRowLockSemaphore.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/StdRowLockSemaphore.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/StdRowLockSemaphore.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/StdRowLockSemaphore.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,28 +15,21 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.impl.jdbcjobstore; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.HashSet; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - /** - * An interface for providing thread/resource locking in order to protect - * resources from being altered by multiple threads at the same time. + * Internal database based lock handler for providing thread/resource locking + * in order to protect resources from being altered by multiple threads at the + * same time. * * @author jhouse */ -public class StdRowLockSemaphore implements Semaphore, Constants, - StdJDBCConstants { +public class StdRowLockSemaphore extends DBSemaphore { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -47,24 +40,13 @@ */ public static final String SELECT_FOR_LOCK = "SELECT * FROM " - + TABLE_PREFIX_SUBST + TABLE_LOCKS + " WHERE " + COL_LOCK_NAME - + " = ? FOR UPDATE"; + + TABLE_PREFIX_SUBST + TABLE_LOCKS + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + + " AND " + COL_LOCK_NAME + " = ? FOR UPDATE"; - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Data members. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ + public static final String INSERT_LOCK = "INSERT INTO " + + TABLE_PREFIX_SUBST + TABLE_LOCKS + "(" + COL_SCHEDULER_NAME + ", " + COL_LOCK_NAME + ") VALUES (" + + SCHED_NAME_SUBST + ", ?)"; - ThreadLocal lockOwners = new ThreadLocal(); - - // java.util.HashMap threadLocksOb = new java.util.HashMap(); - private String selectWithLockSQL = SELECT_FOR_LOCK; - - private String tablePrefix; - /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -73,15 +55,14 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - public StdRowLockSemaphore(String tablePrefix, String selectWithLockSQL) { - this.tablePrefix = tablePrefix; - - if (selectWithLockSQL != null && selectWithLockSQL.trim().length() != 0) - this.selectWithLockSQL = selectWithLockSQL; - - this.selectWithLockSQL = Util.rtp(this.selectWithLockSQL, tablePrefix); + public StdRowLockSemaphore() { + super(DEFAULT_TABLE_PREFIX, null, SELECT_FOR_LOCK, INSERT_LOCK); } + public StdRowLockSemaphore(String tablePrefix, String schedName, String selectWithLockSQL) { + super(tablePrefix, schedName, selectWithLockSQL != null ? selectWithLockSQL : SELECT_FOR_LOCK, INSERT_LOCK); + } + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -90,130 +71,115 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - Log getLog() { - return LogFactory.getLog(getClass()); - //return LogFactory.getLog("LOCK:"+Thread.currentThread().getName()); - } - - private HashSet getThreadLocks() { - HashSet threadLocks = (HashSet) lockOwners.get(); - if (threadLocks == null) { - threadLocks = new HashSet(); - lockOwners.set(threadLocks); - } - return threadLocks; - } - /** - * Grants a lock on the identified resource to the calling thread (blocking - * until it is available). - * - * @return true if the lock was obtained. + * Execute the SQL select for update that will lock the proper database row. */ - public boolean obtainLock(Connection conn, String lockName) - throws LockException { - - lockName = lockName.intern(); - - Log log = getLog(); + @Override + protected void executeSQL(Connection conn, final String lockName, final String expandedSQL, final String expandedInsertSQL) throws LockException { + PreparedStatement ps = null; + ResultSet rs = null; + SQLException initCause = null; - if(log.isDebugEnabled()) - log.debug( - "Lock '" + lockName + "' is desired by: " - + Thread.currentThread().getName()); - if (!isLockOwner(conn, lockName)) { - - PreparedStatement ps = null; - ResultSet rs = null; + // attempt lock two times (to work-around possible race conditions in inserting the lock row the first time running) + int count = 0; + do { + count++; try { - ps = conn.prepareStatement(selectWithLockSQL); + ps = conn.prepareStatement(expandedSQL); ps.setString(1, lockName); - - if(log.isDebugEnabled()) - log.debug( - "Lock '" + lockName + "' is being obtained: " - + Thread.currentThread().getName()); + if (getLog().isDebugEnabled()) { + getLog().debug( + "Lock '" + lockName + "' is being obtained: " + + Thread.currentThread().getName()); + } rs = ps.executeQuery(); - if (!rs.next()) + if (!rs.next()) { + getLog().debug( + "Inserting new lock row for lock: '" + lockName + "' being obtained by thread: " + + Thread.currentThread().getName()); + rs.close(); + rs = null; + ps.close(); + ps = null; + ps = conn.prepareStatement(expandedInsertSQL); + ps.setString(1, lockName); + + int res = ps.executeUpdate(); + + if(res != 1) { + if(count < 3) { + // pause a bit to give another thread some time to commit the insert of the new lock row + try { + Thread.sleep(1000L); + } catch (InterruptedException ignore) { + Thread.currentThread().interrupt(); + } + // try again ... + continue; + } + throw new SQLException(Util.rtp( - "No row exists in table " + TABLE_PREFIX_SUBST - + TABLE_LOCKS + " for lock named: " - + lockName, tablePrefix)); + "No row exists, and one could not be inserted in table " + TABLE_PREFIX_SUBST + TABLE_LOCKS + + " for lock named: " + lockName, getTablePrefix(), getSchedulerNameLiteral())); + } + } + + return; // obtained lock, go } catch (SQLException sqle) { //Exception src = // (Exception)getThreadLocksObtainer().get(lockName); //if(src != null) // src.printStackTrace(); //else // System.err.println("--- ***************** NO OBTAINER!"); - - if(log.isDebugEnabled()) - log.debug( - "Lock '" + lockName + "' was not obtained by: " - + Thread.currentThread().getName()); + + if(initCause == null) + initCause = sqle; + + if (getLog().isDebugEnabled()) { + getLog().debug( + "Lock '" + lockName + "' was not obtained by: " + + Thread.currentThread().getName() + (count < 3 ? " - will try again." : "")); + } + + if(count < 3) { + // pause a bit to give another thread some time to commit the insert of the new lock row + try { + Thread.sleep(1000L); + } catch (InterruptedException ignore) { + Thread.currentThread().interrupt(); + } + // try again ... + continue; + } + throw new LockException("Failure obtaining db row lock: " + sqle.getMessage(), sqle); } finally { - if (rs != null) try { - rs.close(); - } catch (Exception ignore) { + if (rs != null) { + try { + rs.close(); + } catch (Exception ignore) { + } } - if (ps != null) try { - ps.close(); - } catch (Exception ignore) { + if (ps != null) { + try { + ps.close(); + } catch (Exception ignore) { + } } } - if(log.isDebugEnabled()) - log.debug( - "Lock '" + lockName + "' given to: " - + Thread.currentThread().getName()); - getThreadLocks().add(lockName); - //getThreadLocksObtainer().put(lockName, new - // Exception("Obtainer...")); - } else - if(log.isDebugEnabled()) - log.debug( - "Lock '" + lockName + "' Is already owned by: " - + Thread.currentThread().getName()); - - return true; + } while(count < 4); + + throw new LockException("Failure obtaining db row lock, reached maximum number of attempts. Initial exception (if any) attached as root cause.", initCause); } - /** - * Release the lock on the identified resource if it is held by the calling - * thread. - */ - public void releaseLock(Connection conn, String lockName) { - - lockName = lockName.intern(); - - if (isLockOwner(conn, lockName)) { - if(getLog().isDebugEnabled()) - getLog().debug( - "Lock '" + lockName + "' returned by: " - + Thread.currentThread().getName()); - getThreadLocks().remove(lockName); - //getThreadLocksObtainer().remove(lockName); - } else - if(getLog().isDebugEnabled()) - getLog().warn( - "Lock '" + lockName + "' attempt to retun by: " - + Thread.currentThread().getName() - + " -- but not owner!", - new Exception("stack-trace of wrongful returner")); - + protected String getSelectWithLockSQL() { + return getSQL(); } - /** - * Determine whether the calling thread owns a lock on the identified - * resource. - */ - public boolean isLockOwner(Connection conn, String lockName) { - - lockName = lockName.intern(); - - return getThreadLocks().contains(lockName); + public void setSelectWithLockSQL(String selectWithLockSQL) { + setSQL(selectWithLockSQL); } - } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/SybaseDelegate.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/TablePrefixAware.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/TriggerPersistenceDelegate.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/TriggerStatus.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/UpdateLockRowSemaphore.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/Util.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/Util.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/Util.java 17 Aug 2012 15:10:18 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/Util.java 15 Dec 2014 10:09:50 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,13 +15,20 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ + package org.quartz.impl.jdbcjobstore; +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; import java.text.MessageFormat; +import java.util.Locale; +import org.quartz.JobPersistenceException; + /** *

* This class contains utility functions for use in all delegate classes. @@ -31,6 +38,12 @@ */ public final class Util { + /** + * Private constructor because this is a pure utility class. + */ + private Util() { + } + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -47,12 +60,12 @@ * * @param query * the unsubstitued query - * @param query + * @param tablePrefix * the table prefix * @return the query, with proper table prefix substituted */ - public static final String rtp(String query, String tablePrefix) { - return MessageFormat.format(query, new Object[]{tablePrefix}); + public static String rtp(String query, String tablePrefix, String schedNameLiteral) { + return MessageFormat.format(query, new Object[]{tablePrefix, schedNameLiteral}); } /** @@ -66,7 +79,7 @@ * the group containing the job * @return a unique String key */ - static final String getJobNameKey(String jobName, String groupName) { + static String getJobNameKey(String jobName, String groupName) { return (groupName + "_$x$x$_" + jobName).intern(); } @@ -81,9 +94,90 @@ * the group containing the trigger * @return a unique String key */ - static final String getTriggerNameKey(String triggerName, String groupName) { + static String getTriggerNameKey(String triggerName, String groupName) { return (groupName + "_$x$x$_" + triggerName).intern(); } + + /** + * Cleanup helper method that closes the given ResultSet + * while ignoring any errors. + */ + public static void closeResultSet(ResultSet rs) { + if (null != rs) { + try { + rs.close(); + } catch (SQLException ignore) { + } + } + } + + /** + * Cleanup helper method that closes the given Statement + * while ignoring any errors. + */ + public static void closeStatement(Statement statement) { + if (null != statement) { + try { + statement.close(); + } catch (SQLException ignore) { + } + } + } + + + public static void setBeanProps(Object obj, String[] propNames, Object[] propValues) throws JobPersistenceException { + + if(propNames == null || propNames.length == 0) + return; + if(propNames.length != propValues.length) + throw new IllegalArgumentException("propNames[].lenght != propValues[].length"); + + String name = null; + + try { + BeanInfo bi = Introspector.getBeanInfo(obj.getClass()); + PropertyDescriptor[] propDescs = bi.getPropertyDescriptors(); + + for(int i=0; i < propNames.length; i++) { + name = propNames[i]; + String c = name.substring(0, 1).toUpperCase(Locale.US); + String methName = "set" + c + name.substring(1); + + java.lang.reflect.Method setMeth = getSetMethod(methName, propDescs); + + if (setMeth == null) { + throw new NoSuchMethodException( + "No setter for property '" + name + "'"); + } + + Class[] params = setMeth.getParameterTypes(); + if (params.length != 1) { + throw new NoSuchMethodException( + "No 1-argument setter for property '" + name + "'"); + } + + setMeth.invoke(obj, new Object[]{ propValues[i] }); + } + } + catch(Exception e) { + throw new JobPersistenceException( + "Unable to set property named: " + name +" of object of type: " + obj.getClass().getCanonicalName(), + e); + } + } + + private static java.lang.reflect.Method getSetMethod(String name, PropertyDescriptor[] props) { + for (int i = 0; i < props.length; i++) { + java.lang.reflect.Method wMeth = props[i].getWriteMethod(); + + if (wMeth != null && wMeth.getName().equals(name)) { + return wMeth; + } + } + + return null; + } + } // EOF Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/WebLogicDelegate.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/oracle/OracleDelegate.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/jdbcjobstore/oracle/weblogic/WebLogicOracleDelegate.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/matchers/AndMatcher.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/matchers/EverythingMatcher.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/matchers/GroupMatcher.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/matchers/KeyMatcher.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/matchers/NameMatcher.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/matchers/NotMatcher.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/matchers/OrMatcher.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/matchers/StringMatcher.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/triggers/AbstractTrigger.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/triggers/CalendarIntervalTriggerImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/triggers/CoreTrigger.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/triggers/CronTriggerImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/triggers/DailyTimeIntervalTriggerImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/triggers/SimpleTriggerImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/impl/triggers/package.html'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/jobs/FileScanJob.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/jobs/FileScanListener.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/jobs/NativeJob.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/jobs/NoOpJob.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/jobs/ee/ejb/EJBInvokerJob.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/jobs/ee/jmx/JMXInvokerJob.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/jobs/ee/mail/SendMailJob.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/listeners/BroadcastJobListener.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/listeners/BroadcastSchedulerListener.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/listeners/BroadcastTriggerListener.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/listeners/JobChainingJobListener.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/listeners/JobListenerSupport.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/listeners/SchedulerListenerSupport.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/listeners/TriggerListenerSupport.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/management/ManagementRESTServiceConfiguration.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/management/ManagementServer.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/plugins/SchedulerPluginWithUserTransactionSupport.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/plugins/history/LoggingJobHistoryPlugin.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/plugins/history/LoggingJobHistoryPlugin.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/plugins/history/LoggingJobHistoryPlugin.java 17 Aug 2012 15:10:21 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/plugins/history/LoggingJobHistoryPlugin.java 15 Dec 2014 10:09:53 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,19 +15,18 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.plugins.history; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.Trigger; import org.quartz.JobListener; +import org.quartz.impl.matchers.EverythingMatcher; +import org.quartz.spi.ClassLoadHelper; import org.quartz.spi.SchedulerPlugin; import java.text.MessageFormat; @@ -291,7 +290,9 @@ private String jobFailedMessage = "Job {1}.{0} execution failed at {2, date, HH:mm:ss MM/dd/yyyy} and reports: {8}"; private String jobWasVetoedMessage = "Job {1}.{0} was vetoed. It was to be fired (by trigger {4}.{3}) at: {2, date, HH:mm:ss MM/dd/yyyy}"; - + + private final Logger log = LoggerFactory.getLogger(getClass()); + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -311,15 +312,13 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - protected Log getLog() { - return LogFactory.getLog(LoggingJobHistoryPlugin.class); + protected Logger getLog() { + return log; } /** * Get the message that is logged when a Job successfully completes its * execution. - * - * @return String */ public String getJobSuccessMessage() { return jobSuccessMessage; @@ -328,17 +327,13 @@ /** * Get the message that is logged when a Job fails its * execution. - * - * @return String */ public String getJobFailedMessage() { return jobFailedMessage; } /** * Get the message that is logged when a Job is about to execute. - * - * @return String */ public String getJobToBeFiredMessage() { return jobToBeFiredMessage; @@ -348,7 +343,7 @@ * Set the message that is logged when a Job successfully completes its * execution. * - * @param jobCompleteMessage + * @param jobSuccessMessage * String in java.text.MessageFormat syntax. */ public void setJobSuccessMessage(String jobSuccessMessage) { @@ -359,7 +354,7 @@ * Set the message that is logged when a Job fails its * execution. * - * @param jobCompleteMessage + * @param jobFailedMessage * String in java.text.MessageFormat syntax. */ public void setJobFailedMessage(String jobFailedMessage) { @@ -379,8 +374,6 @@ /** * Get the message that is logged when a Job execution is vetoed by a * trigger listener. - * - * @return String */ public String getJobWasVetoedMessage() { return jobWasVetoedMessage; @@ -390,7 +383,7 @@ * Set the message that is logged when a Job execution is vetoed by a * trigger listener. * - * @param jobToBeFiredMessage + * @param jobWasVetoedMessage * String in java.text.MessageFormat syntax. */ public void setJobWasVetoedMessage(String jobWasVetoedMessage) { @@ -414,10 +407,10 @@ * @throws SchedulerConfigException * if there is an error initializing. */ - public void initialize(String name, Scheduler scheduler) - throws SchedulerException { - this.name = name; - scheduler.addGlobalJobListener(this); + public void initialize(String pname, Scheduler scheduler,ClassLoadHelper classLoadHelper) + throws SchedulerException { + this.name = pname; + scheduler.getListenerManager().addJobListener(this, EverythingMatcher.allJobs()); } public void start() { @@ -465,11 +458,13 @@ Trigger trigger = context.getTrigger(); - Object[] args = {context.getJobDetail().getName(), - context.getJobDetail().getGroup(), new java.util.Date(), - trigger.getName(), trigger.getGroup(), - trigger.getPreviousFireTime(), trigger.getNextFireTime(), - new Integer(context.getRefireCount())}; + Object[] args = { + context.getJobDetail().getKey().getName(), + context.getJobDetail().getKey().getGroup(), new java.util.Date(), + trigger.getKey().getName(), trigger.getKey().getGroup(), + trigger.getPreviousFireTime(), trigger.getNextFireTime(), + Integer.valueOf(context.getRefireCount()) + }; getLog().info(MessageFormat.format(getJobToBeFiredMessage(), args)); } @@ -490,25 +485,30 @@ } String errMsg = jobException.getMessage(); - args = new Object[]{context.getJobDetail().getName(), - context.getJobDetail().getGroup(), new java.util.Date(), - trigger.getName(), trigger.getGroup(), + args = + new Object[] { + context.getJobDetail().getKey().getName(), + context.getJobDetail().getKey().getGroup(), new java.util.Date(), + trigger.getKey().getName(), trigger.getKey().getGroup(), trigger.getPreviousFireTime(), trigger.getNextFireTime(), - new Integer(context.getRefireCount()), errMsg}; + Integer.valueOf(context.getRefireCount()), errMsg + }; getLog().warn(MessageFormat.format(getJobFailedMessage(), args), jobException); - } - else { + } else { if (!getLog().isInfoEnabled()) { return; } String result = String.valueOf(context.getResult()); - args = new Object[]{context.getJobDetail().getName(), - context.getJobDetail().getGroup(), new java.util.Date(), - trigger.getName(), trigger.getGroup(), + args = + new Object[] { + context.getJobDetail().getKey().getName(), + context.getJobDetail().getKey().getGroup(), new java.util.Date(), + trigger.getKey().getName(), trigger.getKey().getGroup(), trigger.getPreviousFireTime(), trigger.getNextFireTime(), - new Integer(context.getRefireCount()), result}; + Integer.valueOf(context.getRefireCount()), result + }; getLog().info(MessageFormat.format(getJobSuccessMessage(), args)); } @@ -525,11 +525,13 @@ Trigger trigger = context.getTrigger(); - Object[] args = {context.getJobDetail().getName(), - context.getJobDetail().getGroup(), new java.util.Date(), - trigger.getName(), trigger.getGroup(), - trigger.getPreviousFireTime(), trigger.getNextFireTime(), - new Integer(context.getRefireCount())}; + Object[] args = { + context.getJobDetail().getKey().getName(), + context.getJobDetail().getKey().getGroup(), new java.util.Date(), + trigger.getKey().getName(), trigger.getKey().getGroup(), + trigger.getPreviousFireTime(), trigger.getNextFireTime(), + Integer.valueOf(context.getRefireCount()) + }; getLog().info(MessageFormat.format(getJobWasVetoedMessage(), args)); } Index: 3rdParty_sources/quartz/org/quartz/plugins/history/LoggingTriggerHistoryPlugin.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/plugins/history/LoggingTriggerHistoryPlugin.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/plugins/history/LoggingTriggerHistoryPlugin.java 17 Aug 2012 15:10:21 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/plugins/history/LoggingTriggerHistoryPlugin.java 15 Dec 2014 10:09:53 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,20 +15,20 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.plugins.history; import java.text.MessageFormat; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.quartz.JobExecutionContext; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.Trigger; import org.quartz.TriggerListener; +import org.quartz.Trigger.CompletedExecutionInstruction; +import org.quartz.impl.matchers.EverythingMatcher; +import org.quartz.spi.ClassLoadHelper; import org.quartz.spi.SchedulerPlugin; /** @@ -228,6 +228,8 @@ private String triggerCompleteMessage = "Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy} with resulting trigger instruction code: {9}"; + private final Logger log = LoggerFactory.getLogger(getClass()); + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -247,8 +249,8 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - protected Log getLog() { - return LogFactory.getLog(LoggingTriggerHistoryPlugin.class); + protected Logger getLog() { + return log; } /** @@ -327,11 +329,11 @@ * @throws SchedulerConfigException * if there is an error initializing. */ - public void initialize(String name, Scheduler scheduler) - throws SchedulerException { - this.name = name; + public void initialize(String pname, Scheduler scheduler, ClassLoadHelper classLoadHelper) + throws SchedulerException { + this.name = pname; - scheduler.addGlobalTriggerListener(this); + scheduler.getListenerManager().addTriggerListener(this, EverythingMatcher.allTriggers()); } public void start() { @@ -374,11 +376,13 @@ return; } - Object[] args = {trigger.getName(), trigger.getGroup(), - trigger.getPreviousFireTime(), trigger.getNextFireTime(), - new java.util.Date(), context.getJobDetail().getName(), - context.getJobDetail().getGroup(), - new Integer(context.getRefireCount())}; + Object[] args = { + trigger.getKey().getName(), trigger.getKey().getGroup(), + trigger.getPreviousFireTime(), trigger.getNextFireTime(), + new java.util.Date(), context.getJobDetail().getKey().getName(), + context.getJobDetail().getKey().getGroup(), + Integer.valueOf(context.getRefireCount()) + }; getLog().info(MessageFormat.format(getTriggerFiredMessage(), args)); } @@ -388,34 +392,43 @@ return; } - Object[] args = {trigger.getName(), trigger.getGroup(), - trigger.getPreviousFireTime(), trigger.getNextFireTime(), - new java.util.Date(), trigger.getJobGroup(), - trigger.getJobGroup(),}; + Object[] args = { + trigger.getKey().getName(), trigger.getKey().getGroup(), + trigger.getPreviousFireTime(), trigger.getNextFireTime(), + new java.util.Date(), trigger.getJobKey().getName(), + trigger.getJobKey().getGroup() + }; getLog().info(MessageFormat.format(getTriggerMisfiredMessage(), args)); } public void triggerComplete(Trigger trigger, JobExecutionContext context, - int triggerInstructionCode) { + CompletedExecutionInstruction triggerInstructionCode) { if (!getLog().isInfoEnabled()) { return; } String instrCode = "UNKNOWN"; - if (triggerInstructionCode == Trigger.INSTRUCTION_DELETE_TRIGGER) instrCode = "DELETE TRIGGER"; - else if (triggerInstructionCode == Trigger.INSTRUCTION_NOOP) instrCode = "DO NOTHING"; - else if (triggerInstructionCode == Trigger.INSTRUCTION_RE_EXECUTE_JOB) instrCode = "RE-EXECUTE JOB"; - else if (triggerInstructionCode == Trigger.INSTRUCTION_SET_ALL_JOB_TRIGGERS_COMPLETE) instrCode = "SET ALL OF JOB'S TRIGGERS COMPLETE"; - else if (triggerInstructionCode == Trigger.INSTRUCTION_SET_TRIGGER_COMPLETE) - instrCode = "SET THIS TRIGGER COMPLETE"; + if (triggerInstructionCode == CompletedExecutionInstruction.DELETE_TRIGGER) { + instrCode = "DELETE TRIGGER"; + } else if (triggerInstructionCode == CompletedExecutionInstruction.NOOP) { + instrCode = "DO NOTHING"; + } else if (triggerInstructionCode == CompletedExecutionInstruction.RE_EXECUTE_JOB) { + instrCode = "RE-EXECUTE JOB"; + } else if (triggerInstructionCode == CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_COMPLETE) { + instrCode = "SET ALL OF JOB'S TRIGGERS COMPLETE"; + } else if (triggerInstructionCode == CompletedExecutionInstruction.SET_TRIGGER_COMPLETE) { + instrCode = "SET THIS TRIGGER COMPLETE"; + } - Object[] args = {trigger.getName(), trigger.getGroup(), - trigger.getPreviousFireTime(), trigger.getNextFireTime(), - new java.util.Date(), context.getJobDetail().getName(), - context.getJobDetail().getGroup(), - new Integer(context.getRefireCount()), - new Integer(triggerInstructionCode), instrCode}; + Object[] args = { + trigger.getKey().getName(), trigger.getKey().getGroup(), + trigger.getPreviousFireTime(), trigger.getNextFireTime(), + new java.util.Date(), context.getJobDetail().getKey().getName(), + context.getJobDetail().getKey().getGroup(), + Integer.valueOf(context.getRefireCount()), + triggerInstructionCode.toString(), instrCode + }; getLog().info(MessageFormat.format(getTriggerCompleteMessage(), args)); } Index: 3rdParty_sources/quartz/org/quartz/plugins/management/ShutdownHookPlugin.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/plugins/management/ShutdownHookPlugin.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/plugins/management/ShutdownHookPlugin.java 17 Aug 2012 15:10:22 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/plugins/management/ShutdownHookPlugin.java 15 Dec 2014 10:09:55 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,15 +15,13 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.plugins.management; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.quartz.Scheduler; import org.quartz.SchedulerException; +import org.quartz.spi.ClassLoadHelper; import org.quartz.spi.SchedulerPlugin; /** @@ -44,12 +42,10 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - private String name; - - private Scheduler scheduler; - private boolean cleanShutdown = true; + private final Logger log = LoggerFactory.getLogger(getClass()); + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -97,8 +93,8 @@ cleanShutdown = b; } - protected static Log getLog() { - return LogFactory.getLog(ShutdownHookPlugin.class); + protected Logger getLog() { + return log; } /* @@ -118,15 +114,14 @@ * @throws SchedulerConfigException * if there is an error initializing. */ - public void initialize(String name, final Scheduler scheduler) - throws SchedulerException { - this.name = name; - this.scheduler = scheduler; + public void initialize(String name, final Scheduler scheduler, ClassLoadHelper classLoadHelper) + throws SchedulerException { getLog().info("Registering Quartz shutdown hook."); Thread t = new Thread("Quartz Shutdown-Hook " + scheduler.getSchedulerName()) { + @Override public void run() { getLog().info("Shutting down Quartz..."); try { Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/plugins/xml/JobInitializationPlugin.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/plugins/xml/JobInitializationPluginMultiple.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/plugins/xml/XMLSchedulingDataProcessorPlugin.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/simpl/CascadingClassLoadHelper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/simpl/CascadingClassLoadHelper.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/simpl/CascadingClassLoadHelper.java 17 Aug 2012 15:10:16 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/simpl/CascadingClassLoadHelper.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.simpl; import java.util.Iterator; @@ -31,7 +28,7 @@ * A ClassLoadHelper uses all of the ClassLoadHelper * types that are found in this package in its attempts to load a class, when * one scheme is found to work, it is promoted to the scheme that will be used - * first the next time a class is loaded (in order to improve perfomance). + * first the next time a class is loaded (in order to improve performance). * *

* This approach is used because of the wide variance in class loader behavior @@ -49,6 +46,7 @@ * @see org.quartz.simpl.InitThreadContextClassLoadHelper * * @author jhouse + * @author pl47ypus */ public class CascadingClassLoadHelper implements ClassLoadHelper { @@ -61,7 +59,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - private LinkedList loadHelpers; + private LinkedList loadHelpers; private ClassLoadHelper bestCandidate; @@ -75,60 +73,71 @@ /** * Called to give the ClassLoadHelper a chance to initialize itself, - * including the oportunity to "steal" the class loader off of the calling + * including the opportunity to "steal" the class loader off of the calling * thread, which is the thread that is initializing Quartz. */ public void initialize() { - loadHelpers = new LinkedList(); + loadHelpers = new LinkedList(); loadHelpers.add(new LoadingLoaderClassLoadHelper()); loadHelpers.add(new SimpleClassLoadHelper()); loadHelpers.add(new ThreadContextClassLoadHelper()); loadHelpers.add(new InitThreadContextClassLoadHelper()); - Iterator iter = loadHelpers.iterator(); - while (iter.hasNext()) { - ClassLoadHelper loadHelper = (ClassLoadHelper) iter.next(); + for(ClassLoadHelper loadHelper: loadHelpers) { loadHelper.initialize(); } } /** * Return the class with the given name. */ - public Class loadClass(String name) throws ClassNotFoundException { + public Class loadClass(String name) throws ClassNotFoundException { if (bestCandidate != null) { try { return bestCandidate.loadClass(name); - } catch (Exception e) { + } catch (Throwable t) { bestCandidate = null; } } - ClassNotFoundException cnfe = null; - Class clazz = null; + Throwable throwable = null; + Class clazz = null; ClassLoadHelper loadHelper = null; - Iterator iter = loadHelpers.iterator(); + Iterator iter = loadHelpers.iterator(); while (iter.hasNext()) { - loadHelper = (ClassLoadHelper) iter.next(); + loadHelper = iter.next(); try { clazz = loadHelper.loadClass(name); break; - } catch (ClassNotFoundException e) { - cnfe = e; + } catch (Throwable t) { + throwable = t; } } - if (clazz == null) throw cnfe; + if (clazz == null) { + if (throwable instanceof ClassNotFoundException) { + throw (ClassNotFoundException)throwable; + } + else { + throw new ClassNotFoundException( String.format( "Unable to load class %s by any known loaders.", name), throwable); + } + } bestCandidate = loadHelper; return clazz; } + @SuppressWarnings("unchecked") + public Class loadClass(String name, Class clazz) + throws ClassNotFoundException { + return (Class) loadClass(name); + } + /** * Finds a resource with a given name. This method returns null if no * resource with this name is found. @@ -137,20 +146,23 @@ */ public URL getResource(String name) { + URL result = null; + if (bestCandidate != null) { - try { - return bestCandidate.getResource(name); - } catch (Exception e) { - bestCandidate = null; + result = bestCandidate.getResource(name); + if(result == null) { + bestCandidate = null; } + else { + return result; + } } - URL result = null; ClassLoadHelper loadHelper = null; - Iterator iter = loadHelpers.iterator(); + Iterator iter = loadHelpers.iterator(); while (iter.hasNext()) { - loadHelper = (ClassLoadHelper) iter.next(); + loadHelper = iter.next(); result = loadHelper.getResource(name); if (result != null) { @@ -160,7 +172,6 @@ bestCandidate = loadHelper; return result; - } /** @@ -171,20 +182,23 @@ */ public InputStream getResourceAsStream(String name) { + InputStream result = null; + if (bestCandidate != null) { - try { - return bestCandidate.getResourceAsStream(name); - } catch (Exception e) { + result = bestCandidate.getResourceAsStream(name); + if(result == null) { bestCandidate = null; } + else { + return result; + } } - InputStream result = null; ClassLoadHelper loadHelper = null; - Iterator iter = loadHelpers.iterator(); + Iterator iter = loadHelpers.iterator(); while (iter.hasNext()) { - loadHelper = (ClassLoadHelper) iter.next(); + loadHelper = iter.next(); result = loadHelper.getResourceAsStream(name); if (result != null) { @@ -194,7 +208,17 @@ bestCandidate = loadHelper; return result; + } + /** + * Enable sharing of the "best" class-loader with 3rd party. + * + * @return the class-loader user be the helper. + */ + public ClassLoader getClassLoader() { + return (this.bestCandidate == null) ? + Thread.currentThread().getContextClassLoader() : + this.bestCandidate.getClassLoader(); } } Index: 3rdParty_sources/quartz/org/quartz/simpl/HostnameInstanceIdGenerator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/simpl/HostnameInstanceIdGenerator.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/simpl/HostnameInstanceIdGenerator.java 17 Aug 2012 15:10:16 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/simpl/HostnameInstanceIdGenerator.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -37,13 +37,11 @@ * @see InstanceIdGenerator * @see SimpleInstanceIdGenerator */ -public class HostnameInstanceIdGenerator implements InstanceIdGenerator -{ +public class HostnameInstanceIdGenerator implements InstanceIdGenerator { public String generateInstanceId() throws SchedulerException { try { return InetAddress.getLocalHost().getHostName(); - } - catch (Exception e) { + } catch (Exception e) { throw new SchedulerException("Couldn't get host name!", e); } } Index: 3rdParty_sources/quartz/org/quartz/simpl/InitThreadContextClassLoadHelper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/simpl/InitThreadContextClassLoadHelper.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/simpl/InitThreadContextClassLoadHelper.java 17 Aug 2012 15:10:16 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/simpl/InitThreadContextClassLoadHelper.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.simpl; import org.quartz.spi.ClassLoadHelper; @@ -36,6 +33,7 @@ * @see org.quartz.simpl.LoadingLoaderClassLoadHelper * * @author jhouse + * @author pl47ypus */ public class InitThreadContextClassLoadHelper implements ClassLoadHelper { @@ -60,7 +58,7 @@ /** * Called to give the ClassLoadHelper a chance to initialize itself, - * including the oportunity to "steal" the class loader off of the calling + * including the opportunity to "steal" the class loader off of the calling * thread, which is the thread that is initializing Quartz. */ public void initialize() { @@ -70,10 +68,16 @@ /** * Return the class with the given name. */ - public Class loadClass(String name) throws ClassNotFoundException { + public Class loadClass(String name) throws ClassNotFoundException { return initClassLoader.loadClass(name); } + @SuppressWarnings("unchecked") + public Class loadClass(String name, Class clazz) + throws ClassNotFoundException { + return (Class) loadClass(name); + } + /** * Finds a resource with a given name. This method returns null if no * resource with this name is found. @@ -93,4 +97,13 @@ public InputStream getResourceAsStream(String name) { return initClassLoader.getResourceAsStream(name); } + + /** + * Enable sharing of the class-loader with 3rd party. + * + * @return the class-loader user be the helper. + */ + public ClassLoader getClassLoader() { + return this.initClassLoader; + } } Index: 3rdParty_sources/quartz/org/quartz/simpl/LoadingLoaderClassLoadHelper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/simpl/LoadingLoaderClassLoadHelper.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/simpl/LoadingLoaderClassLoadHelper.java 17 Aug 2012 15:10:16 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/simpl/LoadingLoaderClassLoadHelper.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.simpl; import org.quartz.spi.ClassLoadHelper; @@ -35,6 +32,7 @@ * @see org.quartz.simpl.CascadingClassLoadHelper * * @author jhouse + * @author pl47ypus */ public class LoadingLoaderClassLoadHelper implements ClassLoadHelper { @@ -48,7 +46,7 @@ /** * Called to give the ClassLoadHelper a chance to initialize itself, - * including the oportunity to "steal" the class loader off of the calling + * including the opportunity to "steal" the class loader off of the calling * thread, which is the thread that is initializing Quartz. */ public void initialize() { @@ -57,10 +55,16 @@ /** * Return the class with the given name. */ - public Class loadClass(String name) throws ClassNotFoundException { + public Class loadClass(String name) throws ClassNotFoundException { return getClassLoader().loadClass(name); } + @SuppressWarnings("unchecked") + public Class loadClass(String name, Class clazz) + throws ClassNotFoundException { + return (Class) loadClass(name); + } + /** * Finds a resource with a given name. This method returns null if no * resource with this name is found. @@ -81,7 +85,12 @@ return getClassLoader().getResourceAsStream(name); } - private ClassLoader getClassLoader() { + /** + * Enable sharing of the class-loader with 3rd party. + * + * @return the class-loader user be the helper. + */ + public ClassLoader getClassLoader() { return this.getClass().getClassLoader(); } } Index: 3rdParty_sources/quartz/org/quartz/simpl/PropertySettingJobFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/simpl/PropertySettingJobFactory.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/simpl/PropertySettingJobFactory.java 17 Aug 2012 15:10:16 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/simpl/PropertySettingJobFactory.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -21,12 +21,14 @@ import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; +import java.util.Iterator; import java.util.Locale; +import java.util.Map; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.quartz.Job; import org.quartz.JobDataMap; +import org.quartz.Scheduler; +import org.quartz.SchedulerContext; import org.quartz.SchedulerException; import org.quartz.spi.TriggerFiredBundle; @@ -35,29 +37,39 @@ /** * A JobFactory that instantiates the Job instance (using the default no-arg * constructor, or more specifically: class.newInstance()), and - * then attempts to set all values in the JobExecutionContext's - * JobDataMap onto bean properties of the Job. + * then attempts to set all values from the SchedulerContext and + * the JobExecutionContext's merged JobDataMap onto + * bean properties of the Job. * + *

Set the warnIfPropertyNotFound property to true if you'd like noisy logging in + * the case of values in the JobDataMap not mapping to properties on your Job + * class. This may be useful for troubleshooting typos of property names, etc. + * but very noisy if you regularly (and purposely) have extra things in your + * JobDataMap.

+ * + *

Also of possible interest is the throwIfPropertyNotFound property which + * will throw exceptions on unmatched JobDataMap keys.

+ * * @see org.quartz.spi.JobFactory * @see SimpleJobFactory - * @see JobExecutionContext#getMergedJobDataMap() + * @see SchedulerContext + * @see org.quartz.JobExecutionContext#getMergedJobDataMap() * @see #setWarnIfPropertyNotFound(boolean) * @see #setThrowIfPropertyNotFound(boolean) * * @author jhouse */ public class PropertySettingJobFactory extends SimpleJobFactory { - - private Log log = LogFactory.getLog(SimpleJobFactory.class); - - private boolean warnIfNotFound = true; + private boolean warnIfNotFound = false; private boolean throwIfNotFound = false; - public Job newJob(TriggerFiredBundle bundle) throws SchedulerException { + @Override + public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException { - Job job = super.newJob(bundle); + Job job = super.newJob(bundle, scheduler); JobDataMap jobDataMap = new JobDataMap(); + jobDataMap.putAll(scheduler.getContext()); jobDataMap.putAll(bundle.getJobDetail().getJobDataMap()); jobDataMap.putAll(bundle.getTrigger().getJobDataMap()); @@ -71,187 +83,175 @@ BeanInfo bi = null; try { bi = Introspector.getBeanInfo(obj.getClass()); - } catch (IntrospectionException e1) { - if(isThrowIfPropertyNotFound()) { - throw new SchedulerException("Unable to introspect Job class.", e1); - } - if(isWarnIfPropertyNotFound()) { - log.warn("Unable to introspect Job class.", e1); - } + } catch (IntrospectionException e) { + handleError("Unable to introspect Job class.", e); } PropertyDescriptor[] propDescs = bi.getPropertyDescriptors(); - java.util.Iterator keys = data.keySet().iterator(); - while (keys.hasNext()) { - String name = (String) keys.next(); + // Get the wrapped entry set so don't have to incur overhead of wrapping for + // dirty flag checking since this is read only access + for (Iterator entryIter = data.getWrappedMap().entrySet().iterator(); entryIter.hasNext();) { + Map.Entry entry = (Map.Entry)entryIter.next(); + + String name = (String)entry.getKey(); String c = name.substring(0, 1).toUpperCase(Locale.US); String methName = "set" + c + name.substring(1); java.lang.reflect.Method setMeth = getSetMethod(methName, propDescs); - Class paramType = null; + Class paramType = null; Object o = null; try { if (setMeth == null) { - if(isThrowIfPropertyNotFound()) { - throw new SchedulerException( - "No setter on Job class " + obj.getClass() + - " for property '" + name + "'"); - } - if(isWarnIfPropertyNotFound()) { - log.warn( - "No setter on Job class " + obj.getClass() + - " for property '" + name + "'"); - } + handleError( + "No setter on Job class " + obj.getClass().getName() + + " for property '" + name + "'"); continue; } paramType = setMeth.getParameterTypes()[0]; - o = data.get(name); + o = entry.getValue(); - if (paramType.equals(int.class)) { - if(o instanceof Integer) - setMeth.invoke(obj, - new Object[]{o}); - else if(o instanceof String) - setMeth.invoke(obj, - new Object[]{data.getIntegerFromString(name)}); - } else if (paramType.equals(long.class)) { - if(o instanceof Long) - setMeth.invoke(obj, - new Object[]{o}); - else if(o instanceof String) - setMeth.invoke(obj, - new Object[]{data.getLongFromString(name)}); - } else if (paramType.equals(float.class)) { - if(o instanceof Float) - setMeth.invoke(obj, - new Object[]{o}); - else if(o instanceof String) - setMeth.invoke(obj, - new Object[]{data.getFloatFromString(name)}); - } else if (paramType.equals(double.class)) { - if(o instanceof Double) - setMeth.invoke(obj, - new Object[]{o}); - else if(o instanceof String) - setMeth.invoke(obj, - new Object[]{data.getDoubleFromString(name)}); - } else if (paramType.equals(boolean.class)) { - if(o instanceof Boolean) - setMeth.invoke(obj, - new Object[]{o}); - else if(o instanceof String) - setMeth.invoke(obj, - new Object[]{data.getBooleanFromString(name)}); - } else if (paramType.equals(String.class)) { - if(o instanceof String) - setMeth.invoke(obj, - new Object[]{o}); - } else { - if(paramType.isAssignableFrom(o.getClass())) { - setMeth.invoke(obj, - new Object[]{o}); + Object parm = null; + if (paramType.isPrimitive()) { + if (o == null) { + handleError( + "Cannot set primitive property '" + name + + "' on Job class " + obj.getClass().getName() + + " to null."); + continue; } - else - throw new NoSuchMethodException(); + + if (paramType.equals(int.class)) { + if (o instanceof String) { + parm = Integer.valueOf((String)o); + } else if (o instanceof Integer) { + parm = o; + } + } else if (paramType.equals(long.class)) { + if (o instanceof String) { + parm = Long.valueOf((String)o); + } else if (o instanceof Long) { + parm = o; + } + } else if (paramType.equals(float.class)) { + if (o instanceof String) { + parm = Float.valueOf((String)o); + } else if (o instanceof Float) { + parm = o; + } + } else if (paramType.equals(double.class)) { + if (o instanceof String) { + parm = Double.valueOf((String)o); + } else if (o instanceof Double) { + parm = o; + } + } else if (paramType.equals(boolean.class)) { + if (o instanceof String) { + parm = Boolean.valueOf((String)o); + } else if (o instanceof Boolean) { + parm = o; + } + } else if (paramType.equals(byte.class)) { + if (o instanceof String) { + parm = Byte.valueOf((String)o); + } else if (o instanceof Byte) { + parm = o; + } + } else if (paramType.equals(short.class)) { + if (o instanceof String) { + parm = Short.valueOf((String)o); + } else if (o instanceof Short) { + parm = o; + } + } else if (paramType.equals(char.class)) { + if (o instanceof String) { + String str = (String)o; + if (str.length() == 1) { + parm = Character.valueOf(str.charAt(0)); + } + } else if (o instanceof Character) { + parm = o; + } + } + } else if ((o != null) && (paramType.isAssignableFrom(o.getClass()))) { + parm = o; } - } catch (NumberFormatException nfe) { - if(isThrowIfPropertyNotFound()) { - throw new SchedulerException( - "The setter on Job class " + obj.getClass() + - " for property '" + name + - "' expects a " + paramType + - " but was given " + o, nfe); + + // If the parameter wasn't originally null, but we didn't find a + // matching parameter, then we are stuck. + if ((o != null) && (parm == null)) { + handleError( + "The setter on Job class " + obj.getClass().getName() + + " for property '" + name + + "' expects a " + paramType + + " but was given " + o.getClass().getName()); + continue; } - if(isWarnIfPropertyNotFound()) { - log.warn( - "The setter on Job class " + obj.getClass() + - " for property '" + name + - "' expects a " + paramType + - " but was given " + o, nfe); - } - continue; - } catch (NoSuchMethodException e) { - if(isThrowIfPropertyNotFound()) { - throw new SchedulerException( - "The setter on Job class " + obj.getClass() + - " for property '" + name + - "' expects a " + paramType + - " but was given " + o.getClass()); - } - if(isWarnIfPropertyNotFound()) { - log.warn( - "The setter on Job class " + obj.getClass() + - " for property '" + name + - "' expects a " + paramType + - " but was given a " + o.getClass()); - } - continue; + + setMeth.invoke(obj, new Object[]{ parm }); + } catch (NumberFormatException nfe) { + handleError( + "The setter on Job class " + obj.getClass().getName() + + " for property '" + name + + "' expects a " + paramType + + " but was given " + o.getClass().getName(), nfe); } catch (IllegalArgumentException e) { - if(isThrowIfPropertyNotFound()) { - throw new SchedulerException( - "The setter on Job class " + obj.getClass() + - " for property '" + name + - "' expects a " + paramType + - " but was given " + o.getClass(),e ); - } - if(isWarnIfPropertyNotFound()) { - log.warn( - "The setter on Job class " + obj.getClass() + - " for property '" + name + - "' expects a " + paramType + - " but was given a " + o.getClass(), e); - } - continue; + handleError( + "The setter on Job class " + obj.getClass().getName() + + " for property '" + name + + "' expects a " + paramType + + " but was given " + o.getClass().getName(), e); } catch (IllegalAccessException e) { - if(isThrowIfPropertyNotFound()) { - throw new SchedulerException( - "The setter on Job class " + obj.getClass() + - " for property '" + name + - "' could not be accessed.", e); - } - if(isWarnIfPropertyNotFound()) { - log.warn( - "The setter on Job class " + obj.getClass() + - " for property '" + name + - "' expects a " + paramType + - "' could not be accessed.", e); - } - continue; + handleError( + "The setter on Job class " + obj.getClass().getName() + + " for property '" + name + + "' could not be accessed.", e); } catch (InvocationTargetException e) { - if(isThrowIfPropertyNotFound()) { - throw new SchedulerException( - "The setter on Job class " + obj.getClass() + - " for property '" + name + - "' could not be accessed.", e); - } - if(isWarnIfPropertyNotFound()) { - log.warn( - "The setter on Job class " + obj.getClass() + - " for property '" + name + - "' expects a " + paramType + - "' could not be accessed.", e); - } - continue; + handleError( + "The setter on Job class " + obj.getClass().getName() + + " for property '" + name + + "' could not be invoked.", e); } } } + + private void handleError(String message) throws SchedulerException { + handleError(message, null); + } + + private void handleError(String message, Exception e) throws SchedulerException { + if (isThrowIfPropertyNotFound()) { + throw new SchedulerException(message, e); + } + if (isWarnIfPropertyNotFound()) { + if (e == null) { + getLog().warn(message); + } else { + getLog().warn(message, e); + } + } + } + private java.lang.reflect.Method getSetMethod(String name, PropertyDescriptor[] props) { for (int i = 0; i < props.length; i++) { java.lang.reflect.Method wMeth = props[i].getWriteMethod(); - if(wMeth == null) + if(wMeth == null) { continue; + } - if(wMeth.getParameterTypes().length != 1) + if(wMeth.getParameterTypes().length != 1) { continue; + } - if (wMeth.getName().equals(name)) return wMeth; + if (wMeth.getName().equals(name)) { + return wMeth; + } } return null; @@ -300,6 +300,4 @@ public void setWarnIfPropertyNotFound(boolean warnIfNotFound) { this.warnIfNotFound = warnIfNotFound; } - - } \ No newline at end of file Index: 3rdParty_sources/quartz/org/quartz/simpl/RAMJobStore.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/simpl/RAMJobStore.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/simpl/RAMJobStore.java 17 Aug 2012 15:10:16 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/simpl/RAMJobStore.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,35 +15,50 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.simpl; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicLong; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.quartz.Calendar; +import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobDetail; +import org.quartz.JobKey; import org.quartz.JobPersistenceException; import org.quartz.ObjectAlreadyExistsException; -import org.quartz.SchedulerException; import org.quartz.Trigger; -import org.quartz.core.SchedulingContext; +import org.quartz.TriggerKey; +import org.quartz.Trigger.CompletedExecutionInstruction; +import org.quartz.Trigger.TriggerState; +import org.quartz.Trigger.TriggerTimeComparator; +import org.quartz.impl.JobDetailImpl; +import org.quartz.impl.matchers.GroupMatcher; +import org.quartz.impl.matchers.StringMatcher; import org.quartz.spi.ClassLoadHelper; import org.quartz.spi.JobStore; +import org.quartz.spi.OperableTrigger; import org.quartz.spi.SchedulerSignaler; import org.quartz.spi.TriggerFiredBundle; +import org.quartz.spi.TriggerFiredResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import static org.quartz.impl.matchers.EverythingMatcher.allTriggers; + /** *

* This class implements a {@link org.quartz.spi.JobStore} that @@ -59,6 +74,7 @@ * * @author James House * @author Sharada Jambula + * @author Eric Mueller */ public class RAMJobStore implements JobStore { @@ -70,32 +86,34 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - protected HashMap jobsByFQN = new HashMap(1000); + protected HashMap jobsByKey = new HashMap(1000); - protected HashMap triggersByFQN = new HashMap(1000); + protected HashMap triggersByKey = new HashMap(1000); - protected HashMap jobsByGroup = new HashMap(25); + protected HashMap> jobsByGroup = new HashMap>(25); - protected HashMap triggersByGroup = new HashMap(25); + protected HashMap> triggersByGroup = new HashMap>(25); - protected TreeSet timeTriggers = new TreeSet(new TriggerComparator()); + protected TreeSet timeTriggers = new TreeSet(new TriggerWrapperComparator()); - protected HashMap calendarsByName = new HashMap(25); + protected HashMap calendarsByName = new HashMap(25); - protected ArrayList triggers = new ArrayList(1000); + protected ArrayList triggers = new ArrayList(1000); - protected Object jobLock = new Object(); + protected final Object lock = new Object(); - protected Object triggerLock = new Object(); + protected HashSet pausedTriggerGroups = new HashSet(); - protected HashSet pausedTriggerGroups = new HashSet(); + protected HashSet pausedJobGroups = new HashSet(); - protected HashSet blockedJobs = new HashSet(); + protected HashSet blockedJobs = new HashSet(); protected long misfireThreshold = 5000l; protected SchedulerSignaler signaler; + private final Logger log = LoggerFactory.getLogger(getClass()); + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -120,8 +138,8 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - protected Log getLog() { - return LogFactory.getLog(RAMJobStore.class); + protected Logger getLog() { + return log; } /** @@ -130,34 +148,41 @@ * used, in order to give the it a chance to initialize. *

*/ - public void initialize(ClassLoadHelper loadHelper, - SchedulerSignaler signaler) { + public void initialize(ClassLoadHelper loadHelper, SchedulerSignaler schedSignaler) { - this.signaler = signaler; + this.signaler = schedSignaler; getLog().info("RAMJobStore initialized."); } - public void schedulerStarted() throws SchedulerException - { + public void schedulerStarted() { // nothing to do } + public void schedulerPaused() { + // nothing to do + } + + public void schedulerResumed() { + // nothing to do + } + public long getMisfireThreshold() { return misfireThreshold; } /** - * The the number of milliseconds by which a trigger must have missed its + * The number of milliseconds by which a trigger must have missed its * next-fire-time, in order for it to be considered "misfired" and thus * have its misfire instruction applied. * - * @param misfireThreshold + * @param misfireThreshold the new misfire threshold */ + @SuppressWarnings("UnusedDeclaration") public void setMisfireThreshold(long misfireThreshold) { - if (misfireThreshold < 1) - throw new IllegalArgumentException( - "Misfirethreashold must be larger than 0"); + if (misfireThreshold < 1) { + throw new IllegalArgumentException("Misfire threshold must be larger than 0"); + } this.misfireThreshold = misfireThreshold; } @@ -176,6 +201,39 @@ } /** + * Clear (delete!) all scheduling data - all {@link Job}s, {@link Trigger}s + * {@link Calendar}s. + * + * @throws JobPersistenceException + */ + public void clearAllSchedulingData() throws JobPersistenceException { + + synchronized (lock) { + // unschedule jobs (delete triggers) + List lst = getTriggerGroupNames(); + for (String group: lst) { + Set keys = getTriggerKeys(GroupMatcher.triggerGroupEquals(group)); + for (TriggerKey key: keys) { + removeTrigger(key); + } + } + // delete jobs + lst = getJobGroupNames(); + for (String group: lst) { + Set keys = getJobKeys(GroupMatcher.jobGroupEquals(group)); + for (JobKey key: keys) { + removeJob(key); + } + } + // delete calendars + lst = getCalendarNames(); + for(String name: lst) { + removeCalendar(name); + } + } + } + + /** *

* Store the given {@link org.quartz.JobDetail} and {@link org.quartz.Trigger}. *

@@ -188,10 +246,10 @@ * if a Job with the same name/group already * exists. */ - public void storeJobAndTrigger(SchedulingContext ctxt, JobDetail newJob, - Trigger newTrigger) throws JobPersistenceException { - storeJob(ctxt, newJob, false); - storeTrigger(ctxt, newTrigger, false); + public void storeJobAndTrigger(JobDetail newJob, + OperableTrigger newTrigger) throws JobPersistenceException { + storeJob(newJob, false); + storeTrigger(newTrigger, false); } /** @@ -209,34 +267,35 @@ * if a Job with the same name/group already * exists, and replaceExisting is set to false. */ - public void storeJob(SchedulingContext ctxt, JobDetail newJob, + public void storeJob(JobDetail newJob, boolean replaceExisting) throws ObjectAlreadyExistsException { - JobWrapper jw = new JobWrapper(newJob); + JobWrapper jw = new JobWrapper((JobDetail)newJob.clone()); boolean repl = false; - if (jobsByFQN.get(jw.key) != null) { - if (!replaceExisting) + synchronized (lock) { + if (jobsByKey.get(jw.key) != null) { + if (!replaceExisting) { throw new ObjectAlreadyExistsException(newJob); - repl = true; - } + } + repl = true; + } - synchronized (jobLock) { if (!repl) { // get job group - HashMap grpMap = (HashMap) jobsByGroup.get(newJob.getGroup()); + HashMap grpMap = jobsByGroup.get(newJob.getKey().getGroup()); if (grpMap == null) { - grpMap = new HashMap(100); - jobsByGroup.put(newJob.getGroup(), grpMap); + grpMap = new HashMap(100); + jobsByGroup.put(newJob.getKey().getGroup(), grpMap); } // add to jobs by group - grpMap.put(newJob.getName(), jw); + grpMap.put(newJob.getKey(), jw); // add to jobs by FQN map - jobsByFQN.put(jw.key, jw); + jobsByKey.put(jw.key, jw); } else { // update job detail - JobWrapper orig = (JobWrapper) jobsByFQN.get(jw.key); - orig.jobDetail = newJob; + JobWrapper orig = jobsByKey.get(jw.key); + orig.jobDetail = jw.jobDetail; // already cloned } } } @@ -247,47 +306,93 @@ * name, and any {@link org.quartz.Trigger} s that reference * it. *

- * - * @param jobName - * The name of the Job to be removed. - * @param groupName - * The group name of the Job to be removed. + * * @return true if a Job with the given name & * group was found and removed from the store. */ - public boolean removeJob(SchedulingContext ctxt, String jobName, - String groupName) { - String key = JobWrapper.getJobNameKey(jobName, groupName); + public boolean removeJob(JobKey jobKey) { boolean found = false; - Trigger[] trigger = getTriggersForJob(ctxt, jobName, - groupName); - for (int i = 0; i < trigger.length; i++) { - Trigger trig = trigger[i]; - this.removeTrigger(ctxt, trig.getName(), trig.getGroup()); - found = true; - } - synchronized (jobLock) { - found = (jobsByFQN.remove(key) != null) | found; + synchronized (lock) { + List triggersOfJob = getTriggersForJob(jobKey); + for (OperableTrigger trig: triggersOfJob) { + this.removeTrigger(trig.getKey()); + found = true; + } + + found = (jobsByKey.remove(jobKey) != null) | found; if (found) { - HashMap grpMap = (HashMap) jobsByGroup.get(groupName); + HashMap grpMap = jobsByGroup.get(jobKey.getGroup()); if (grpMap != null) { - grpMap.remove(jobName); - if (grpMap.size() == 0) jobsByGroup.remove(groupName); + grpMap.remove(jobKey); + if (grpMap.size() == 0) { + jobsByGroup.remove(jobKey.getGroup()); + } } } } return found; } + public boolean removeJobs(List jobKeys) + throws JobPersistenceException { + boolean allFound = true; + + synchronized (lock) { + for(JobKey key: jobKeys) + allFound = removeJob(key) && allFound; + } + + return allFound; + } + + public boolean removeTriggers(List triggerKeys) + throws JobPersistenceException { + boolean allFound = true; + + synchronized (lock) { + for(TriggerKey key: triggerKeys) + allFound = removeTrigger(key) && allFound; + } + + return allFound; + } + + public void storeJobsAndTriggers( + Map> triggersAndJobs, boolean replace) + throws JobPersistenceException { + + synchronized (lock) { + // make sure there are no collisions... + if(!replace) { + for(Entry> e: triggersAndJobs.entrySet()) { + if(checkExists(e.getKey().getKey())) + throw new ObjectAlreadyExistsException(e.getKey()); + for(Trigger trigger: e.getValue()) { + if(checkExists(trigger.getKey())) + throw new ObjectAlreadyExistsException(trigger); + } + } + } + // do bulk add... + for(Entry> e: triggersAndJobs.entrySet()) { + storeJob(e.getKey(), true); + for(Trigger trigger: e.getValue()) { + storeTrigger((OperableTrigger) trigger, true); + } + } + } + + } + /** *

* Store the given {@link org.quartz.Trigger}. *

- * + * * @param newTrigger * The Trigger to be stored. * @param replaceExisting @@ -297,49 +402,50 @@ * @throws ObjectAlreadyExistsException * if a Trigger with the same name/group already * exists, and replaceExisting is set to false. - * - * @see #pauseTriggerGroup(SchedulingContext, String) + * + * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher) */ - public void storeTrigger(SchedulingContext ctxt, Trigger newTrigger, + public void storeTrigger(OperableTrigger newTrigger, boolean replaceExisting) throws JobPersistenceException { - TriggerWrapper tw = new TriggerWrapper(newTrigger); + TriggerWrapper tw = new TriggerWrapper((OperableTrigger)newTrigger.clone()); - if (triggersByFQN.get(tw.key) != null) { - if (!replaceExisting) + synchronized (lock) { + if (triggersByKey.get(tw.key) != null) { + if (!replaceExisting) { throw new ObjectAlreadyExistsException(newTrigger); - - removeTrigger(ctxt, newTrigger.getName(), newTrigger.getGroup()); - } - - if (retrieveJob(ctxt, newTrigger.getJobName(), newTrigger.getJobGroup()) == null) + } + + removeTrigger(newTrigger.getKey(), false); + } + + if (retrieveJob(newTrigger.getJobKey()) == null) { throw new JobPersistenceException("The job (" - + newTrigger.getFullJobName() + + newTrigger.getJobKey() + ") referenced by the trigger does not exist."); + } - synchronized (triggerLock) { // add to triggers array triggers.add(tw); // add to triggers by group - HashMap grpMap = (HashMap) triggersByGroup.get(newTrigger - .getGroup()); + HashMap grpMap = triggersByGroup.get(newTrigger.getKey().getGroup()); if (grpMap == null) { - grpMap = new HashMap(100); - triggersByGroup.put(newTrigger.getGroup(), grpMap); + grpMap = new HashMap(100); + triggersByGroup.put(newTrigger.getKey().getGroup(), grpMap); } - grpMap.put(newTrigger.getName(), tw); + grpMap.put(newTrigger.getKey(), tw); // add to triggers by FQN map - triggersByFQN.put(tw.key, tw); + triggersByKey.put(tw.key, tw); - synchronized (pausedTriggerGroups) { - if (pausedTriggerGroups.contains(newTrigger.getGroup())) { - tw.state = TriggerWrapper.STATE_PAUSED; - if (blockedJobs.contains(tw.jobKey)) - tw.state = TriggerWrapper.STATE_PAUSED_BLOCKED; + if (pausedTriggerGroups.contains(newTrigger.getKey().getGroup()) + || pausedJobGroups.contains(newTrigger.getJobKey().getGroup())) { + tw.state = TriggerWrapper.STATE_PAUSED; + if (blockedJobs.contains(tw.jobKey)) { + tw.state = TriggerWrapper.STATE_PAUSED_BLOCKED; } - else if (blockedJobs.contains(tw.jobKey)) - tw.state = TriggerWrapper.STATE_BLOCKED; - else - timeTriggers.add(tw); + } else if (blockedJobs.contains(tw.jobKey)) { + tw.state = TriggerWrapper.STATE_BLOCKED; + } else { + timeTriggers.add(tw); } } } @@ -349,191 +455,219 @@ * Remove (delete) the {@link org.quartz.Trigger} with the * given name. *

- * - * @param triggerName - * The name of the Trigger to be removed. - * @param groupName - * The group name of the Trigger to be removed. + * * @return true if a Trigger with the given * name & group was found and removed from the store. */ - public boolean removeTrigger(SchedulingContext ctxt, String triggerName, - String groupName) { - String key = TriggerWrapper.getTriggerNameKey(triggerName, groupName); + public boolean removeTrigger(TriggerKey triggerKey) { + return removeTrigger(triggerKey, true); + } + + private boolean removeTrigger(TriggerKey key, boolean removeOrphanedJob) { - boolean found = false; + boolean found; - synchronized (triggerLock) { + synchronized (lock) { // remove from triggers by FQN map - found = (triggersByFQN.remove(key) == null) ? false : true; + found = (triggersByKey.remove(key) != null); if (found) { TriggerWrapper tw = null; // remove from triggers by group - HashMap grpMap = (HashMap) triggersByGroup.get(groupName); + HashMap grpMap = triggersByGroup.get(key.getGroup()); if (grpMap != null) { - grpMap.remove(triggerName); - if (grpMap.size() == 0) triggersByGroup.remove(groupName); + grpMap.remove(key); + if (grpMap.size() == 0) { + triggersByGroup.remove(key.getGroup()); + } } // remove from triggers array - Iterator tgs = triggers.iterator(); + Iterator tgs = triggers.iterator(); while (tgs.hasNext()) { - tw = (TriggerWrapper) tgs.next(); + tw = tgs.next(); if (key.equals(tw.key)) { tgs.remove(); break; } } timeTriggers.remove(tw); - JobWrapper jw = (JobWrapper) jobsByFQN.get(JobWrapper - .getJobNameKey(tw.trigger.getJobName(), tw.trigger - .getJobGroup())); - Trigger[] trigs = getTriggersForJob(ctxt, tw.trigger - .getJobName(), tw.trigger.getJobGroup()); - if ((trigs == null || trigs.length == 0) - && !jw.jobDetail.isDurable()) - removeJob(ctxt, tw.trigger.getJobName(), tw.trigger - .getJobGroup()); + if (removeOrphanedJob) { + JobWrapper jw = jobsByKey.get(tw.jobKey); + List trigs = getTriggersForJob(tw.jobKey); + if ((trigs == null || trigs.size() == 0) && !jw.jobDetail.isDurable()) { + if (removeJob(jw.key)) { + signaler.notifySchedulerListenersJobDeleted(jw.key); + } + } + } } } return found; } - /** - * @see org.quartz.spi.JobStore#replaceTrigger(org.quartz.core.SchedulingContext, java.lang.String, java.lang.String, org.quartz.Trigger) + /** + * @see org.quartz.spi.JobStore#replaceTrigger(TriggerKey triggerKey, OperableTrigger newTrigger) */ - public boolean replaceTrigger(SchedulingContext ctxt, String triggerName, String groupName, Trigger newTrigger) throws JobPersistenceException { - String key = TriggerWrapper.getTriggerNameKey(triggerName, groupName); + public boolean replaceTrigger(TriggerKey triggerKey, OperableTrigger newTrigger) throws JobPersistenceException { - boolean found = false; + boolean found; - synchronized (triggerLock) { + synchronized (lock) { // remove from triggers by FQN map - TriggerWrapper tw = (TriggerWrapper) triggersByFQN.remove(key); - found = ( tw == null) ? false : true; - + TriggerWrapper tw = triggersByKey.remove(triggerKey); + found = (tw != null); + if (found) { - - if(!tw.getTrigger().getJobName().equals(newTrigger.getJobName()) || - !tw.getTrigger().getJobGroup().equals(newTrigger.getJobGroup())) + + if (!tw.getTrigger().getJobKey().equals(newTrigger.getJobKey())) { throw new JobPersistenceException("New trigger is not related to the same job as the old trigger."); - + } + tw = null; // remove from triggers by group - HashMap grpMap = (HashMap) triggersByGroup.get(groupName); + HashMap grpMap = triggersByGroup.get(triggerKey.getGroup()); if (grpMap != null) { - grpMap.remove(triggerName); - if (grpMap.size() == 0) triggersByGroup.remove(groupName); + grpMap.remove(triggerKey); + if (grpMap.size() == 0) { + triggersByGroup.remove(triggerKey.getGroup()); + } } // remove from triggers array - Iterator tgs = triggers.iterator(); + Iterator tgs = triggers.iterator(); while (tgs.hasNext()) { - tw = (TriggerWrapper) tgs.next(); - if (key.equals(tw.key)) { + tw = tgs.next(); + if (triggerKey.equals(tw.key)) { tgs.remove(); break; } } timeTriggers.remove(tw); try { - storeTrigger(ctxt, newTrigger, false); - } - catch(JobPersistenceException jpe) { - storeTrigger(ctxt, tw.getTrigger(), false); // put previous trigger back... + storeTrigger(newTrigger, false); + } catch(JobPersistenceException jpe) { + storeTrigger(tw.getTrigger(), false); // put previous trigger back... throw jpe; } } } return found; } - + /** *

* Retrieve the {@link org.quartz.JobDetail} for the given * {@link org.quartz.Job}. *

- * - * @param jobName - * The name of the Job to be retrieved. - * @param groupName - * The group name of the Job to be retrieved. + * * @return The desired Job, or null if there is no match. */ - public JobDetail retrieveJob(SchedulingContext ctxt, String jobName, - String groupName) { - JobWrapper jw = (JobWrapper) jobsByFQN.get(JobWrapper.getJobNameKey( - jobName, groupName)); - if (jw != null) return jw.jobDetail; - - return null; + public JobDetail retrieveJob(JobKey jobKey) { + synchronized(lock) { + JobWrapper jw = jobsByKey.get(jobKey); + return (jw != null) ? (JobDetail)jw.jobDetail.clone() : null; + } } /** *

* Retrieve the given {@link org.quartz.Trigger}. *

- * - * @param jobName - * The name of the Trigger to be retrieved. - * @param groupName - * The group name of the Trigger to be retrieved. + * * @return The desired Trigger, or null if there is no * match. */ - public Trigger retrieveTrigger(SchedulingContext ctxt, String triggerName, - String groupName) { - TriggerWrapper tw = (TriggerWrapper) triggersByFQN.get(TriggerWrapper - .getTriggerNameKey(triggerName, groupName)); - if (tw != null) return tw.getTrigger(); - - return null; + public OperableTrigger retrieveTrigger(TriggerKey triggerKey) { + synchronized(lock) { + TriggerWrapper tw = triggersByKey.get(triggerKey); + + return (tw != null) ? (OperableTrigger)tw.getTrigger().clone() : null; + } } - + /** + * Determine whether a {@link Job} with the given identifier already + * exists within the scheduler. + * + * @param jobKey the identifier to check for + * @return true if a Job exists with the given identifier + * @throws JobPersistenceException + */ + public boolean checkExists(JobKey jobKey) throws JobPersistenceException { + synchronized(lock) { + JobWrapper jw = jobsByKey.get(jobKey); + return (jw != null); + } + } + + /** + * Determine whether a {@link Trigger} with the given identifier already + * exists within the scheduler. + * + * @param triggerKey the identifier to check for + * @return true if a Trigger exists with the given identifier + * @throws JobPersistenceException + */ + public boolean checkExists(TriggerKey triggerKey) throws JobPersistenceException { + synchronized(lock) { + TriggerWrapper tw = triggersByKey.get(triggerKey); + + return (tw != null); + } + } + + /** *

* Get the current state of the identified {@link Trigger}. *

- * - * @see Trigger#STATE_NORMAL - * @see Trigger#STATE_PAUSED - * @see Trigger#STATE_COMPLETE - * @see Trigger#STATE_ERROR - * @see Trigger#STATE_BLOCKED - * @see Trigger#STATE_NONE + * + * @see TriggerState#NORMAL + * @see TriggerState#PAUSED + * @see TriggerState#COMPLETE + * @see TriggerState#ERROR + * @see TriggerState#BLOCKED + * @see TriggerState#NONE */ - public int getTriggerState(SchedulingContext ctxt, String triggerName, - String groupName) throws JobPersistenceException { - TriggerWrapper tw = (TriggerWrapper) triggersByFQN.get(TriggerWrapper - .getTriggerNameKey(triggerName, groupName)); - if (tw == null) return Trigger.STATE_NONE; - - if (tw.state == TriggerWrapper.STATE_COMPLETE) - return Trigger.STATE_COMPLETE; - - if (tw.state == TriggerWrapper.STATE_PAUSED) - return Trigger.STATE_PAUSED; - - if (tw.state == TriggerWrapper.STATE_PAUSED_BLOCKED) - return Trigger.STATE_PAUSED; - - if (tw.state == TriggerWrapper.STATE_BLOCKED) - return Trigger.STATE_BLOCKED; - - if (tw.state == TriggerWrapper.STATE_ERROR) - return Trigger.STATE_ERROR; - - return Trigger.STATE_NORMAL; + public TriggerState getTriggerState(TriggerKey triggerKey) throws JobPersistenceException { + synchronized(lock) { + TriggerWrapper tw = triggersByKey.get(triggerKey); + + if (tw == null) { + return TriggerState.NONE; + } + + if (tw.state == TriggerWrapper.STATE_COMPLETE) { + return TriggerState.COMPLETE; + } + + if (tw.state == TriggerWrapper.STATE_PAUSED) { + return TriggerState.PAUSED; + } + + if (tw.state == TriggerWrapper.STATE_PAUSED_BLOCKED) { + return TriggerState.PAUSED; + } + + if (tw.state == TriggerWrapper.STATE_BLOCKED) { + return TriggerState.BLOCKED; + } + + if (tw.state == TriggerWrapper.STATE_ERROR) { + return TriggerState.ERROR; + } + + return TriggerState.NORMAL; + } } /** *

* Store the given {@link org.quartz.Calendar}. *

- * + * * @param calendar * The Calendar to be stored. * @param replaceExisting @@ -542,36 +676,42 @@ * should be over-written. * @param updateTriggers * If true, any Triggers existing - * in the JobStore that reference an existing + * in the JobStore that reference an existing * Calendar with the same name with have their next fire time * re-computed with the new Calendar. * @throws ObjectAlreadyExistsException * if a Calendar with the same name already * exists, and replaceExisting is set to false. */ - public void storeCalendar(SchedulingContext ctxt, String name, + public void storeCalendar(String name, Calendar calendar, boolean replaceExisting, boolean updateTriggers) - throws ObjectAlreadyExistsException { - Object obj = calendarsByName.get(name); + throws ObjectAlreadyExistsException { - if (obj != null && replaceExisting == false) throw new ObjectAlreadyExistsException( - "Calendar with name '" + name + "' already exists."); - else if (obj != null) calendarsByName.remove(name); - - calendarsByName.put(name, calendar); - - if(obj != null && updateTriggers) { - synchronized (triggerLock) { - Iterator trigs = getTriggerWrappersForCalendar(name).iterator(); - while (trigs.hasNext()) { - TriggerWrapper tw = (TriggerWrapper) trigs.next(); - Trigger trig = tw.getTrigger(); + calendar = (Calendar) calendar.clone(); + + synchronized (lock) { + + Object obj = calendarsByName.get(name); + + if (obj != null && !replaceExisting) { + throw new ObjectAlreadyExistsException( + "Calendar with name '" + name + "' already exists."); + } else if (obj != null) { + calendarsByName.remove(name); + } + + calendarsByName.put(name, calendar); + + if(obj != null && updateTriggers) { + for (TriggerWrapper tw : getTriggerWrappersForCalendar(name)) { + OperableTrigger trig = tw.getTrigger(); boolean removed = timeTriggers.remove(tw); - + trig.updateWithNewCalendar(calendar, getMisfireThreshold()); - - if(removed) + + if (removed) { timeTriggers.add(tw); + } } } } @@ -582,32 +722,34 @@ * Remove (delete) the {@link org.quartz.Calendar} with the * given name. *

- * + * *

* If removal of the Calendar would result in - * s pointing to non-existent calendars, then a + * Triggers pointing to non-existent calendars, then a * JobPersistenceException will be thrown.

* * * @param calName The name of the Calendar to be removed. * @return true if a Calendar with the given name * was found and removed from the store. */ - public boolean removeCalendar(SchedulingContext ctxt, String calName) - throws JobPersistenceException { + public boolean removeCalendar(String calName) + throws JobPersistenceException { int numRefs = 0; - synchronized (triggerLock) { - Iterator itr = triggers.iterator(); - while (itr.hasNext()) { - Trigger trigg = ((TriggerWrapper) itr.next()).trigger; + synchronized (lock) { + for (TriggerWrapper trigger : triggers) { + OperableTrigger trigg = trigger.trigger; if (trigg.getCalendarName() != null - && trigg.getCalendarName().equals(calName)) numRefs++; + && trigg.getCalendarName().equals(calName)) { + numRefs++; + } } } - if (numRefs > 0) - throw new JobPersistenceException( - "Calender cannot be removed if it referenced by a Trigger!"); + if (numRefs > 0) { + throw new JobPersistenceException( + "Calender cannot be removed if it referenced by a Trigger!"); + } return (calendarsByName.remove(calName) != null); } @@ -616,14 +758,19 @@ *

* Retrieve the given {@link org.quartz.Trigger}. *

- * + * * @param calName * The name of the Calendar to be retrieved. * @return The desired Calendar, or null if there is no * match. */ - public Calendar retrieveCalendar(SchedulingContext ctxt, String calName) { - return (Calendar) calendarsByName.get(calName); + public Calendar retrieveCalendar(String calName) { + synchronized (lock) { + Calendar cal = calendarsByName.get(calName); + if(cal != null) + return (Calendar) cal.clone(); + return null; + } } /** @@ -632,8 +779,10 @@ * stored in the JobsStore. *

*/ - public int getNumberOfJobs(SchedulingContext ctxt) { - return jobsByFQN.size(); + public int getNumberOfJobs() { + synchronized (lock) { + return jobsByKey.size(); + } } /** @@ -642,8 +791,10 @@ * stored in the JobsStore. *

*/ - public int getNumberOfTriggers(SchedulingContext ctxt) { - return triggers.size(); + public int getNumberOfTriggers() { + synchronized (lock) { + return triggers.size(); + } } /** @@ -652,78 +803,121 @@ * stored in the JobsStore. *

*/ - public int getNumberOfCalendars(SchedulingContext ctxt) { - return calendarsByName.size(); + public int getNumberOfCalendars() { + synchronized (lock) { + return calendarsByName.size(); + } } /** *

* Get the names of all of the {@link org.quartz.Job} s that - * have the given group name. + * match the given groupMatcher. *

*/ - public String[] getJobNames(SchedulingContext ctxt, String groupName) { - String[] outList = null; - HashMap grpMap = (HashMap) jobsByGroup.get(groupName); - if (grpMap != null) { - synchronized (jobLock) { - outList = new String[grpMap.size()]; - int outListPos = 0; - Iterator keys = grpMap.keySet().iterator(); - while (keys.hasNext()) { - String key = (String) keys.next(); - JobWrapper jw = (JobWrapper) grpMap.get(key); - if (jw != null) - outList[outListPos++] = jw.jobDetail.getName(); - } + public Set getJobKeys(GroupMatcher matcher) { + Set outList = null; + synchronized (lock) { + + StringMatcher.StringOperatorName operator = matcher.getCompareWithOperator(); + String compareToValue = matcher.getCompareToValue(); + + switch(operator) { + case EQUALS: + HashMap grpMap = jobsByGroup.get(compareToValue); + if (grpMap != null) { + outList = new HashSet(); + + for (JobWrapper jw : grpMap.values()) { + + if (jw != null) { + outList.add(jw.jobDetail.getKey()); + } + } + } + break; + + default: + for (Map.Entry> entry : jobsByGroup.entrySet()) { + if(operator.evaluate(entry.getKey(), compareToValue) && entry.getValue() != null) { + if(outList == null) { + outList = new HashSet(); + } + for (JobWrapper jobWrapper : entry.getValue().values()) { + if(jobWrapper != null) { + outList.add(jobWrapper.jobDetail.getKey()); + } + } + } + } } - } else - outList = new String[0]; + } - return outList; + return outList == null ? java.util.Collections.emptySet() : outList; } /** *

* Get the names of all of the {@link org.quartz.Calendar} s * in the JobStore. *

- * + * *

* If there are no Calendars in the given group name, the result should be * a zero-length array (not null). *

*/ - public String[] getCalendarNames(SchedulingContext ctxt) { - Set names = calendarsByName.keySet(); - return (String[]) names.toArray(new String[names.size()]); + public List getCalendarNames() { + synchronized(lock) { + return new LinkedList(calendarsByName.keySet()); + } } /** *

* Get the names of all of the {@link org.quartz.Trigger} s - * that have the given group name. + * that match the given groupMatcher. *

*/ - public String[] getTriggerNames(SchedulingContext ctxt, String groupName) { - String[] outList = null; - HashMap grpMap = (HashMap) triggersByGroup.get(groupName); - if (grpMap != null) { - synchronized (triggerLock) { - outList = new String[grpMap.size()]; - int outListPos = 0; - Iterator keys = grpMap.keySet().iterator(); - while (keys.hasNext()) { - String key = (String) keys.next(); - TriggerWrapper tw = (TriggerWrapper) grpMap.get(key); - if (tw != null) - outList[outListPos++] = tw.trigger.getName(); - } + public Set getTriggerKeys(GroupMatcher matcher) { + Set outList = null; + synchronized (lock) { + + StringMatcher.StringOperatorName operator = matcher.getCompareWithOperator(); + String compareToValue = matcher.getCompareToValue(); + + switch(operator) { + case EQUALS: + HashMap grpMap = triggersByGroup.get(compareToValue); + if (grpMap != null) { + outList = new HashSet(); + + for (TriggerWrapper tw : grpMap.values()) { + + if (tw != null) { + outList.add(tw.trigger.getKey()); + } + } + } + break; + + default: + for (Map.Entry> entry : triggersByGroup.entrySet()) { + if(operator.evaluate(entry.getKey(), compareToValue) && entry.getValue() != null) { + if(outList == null) { + outList = new HashSet(); + } + for (TriggerWrapper triggerWrapper : entry.getValue().values()) { + if(triggerWrapper != null) { + outList.add(triggerWrapper.trigger.getKey()); + } + } + } + } } - } else - outList = new String[0]; + } - return outList; + return outList == null ? Collections.emptySet() : outList; } /** @@ -732,16 +926,11 @@ * groups. *

*/ - public String[] getJobGroupNames(SchedulingContext ctxt) { - String[] outList = null; + public List getJobGroupNames() { + List outList; - synchronized (jobLock) { - outList = new String[jobsByGroup.size()]; - int outListPos = 0; - Iterator keys = jobsByGroup.keySet().iterator(); - while (keys.hasNext()) { - outList[outListPos++] = (String) keys.next(); - } + synchronized (lock) { + outList = new LinkedList(jobsByGroup.keySet()); } return outList; @@ -753,16 +942,11 @@ * groups. *

*/ - public String[] getTriggerGroupNames(SchedulingContext ctxt) { - String[] outList = null; + public List getTriggerGroupNames() { + LinkedList outList; - synchronized (triggerLock) { - outList = new String[triggersByGroup.size()]; - int outListPos = 0; - Iterator keys = triggersByGroup.keySet().iterator(); - while (keys.hasNext()) { - outList[outListPos++] = (String) keys.next(); - } + synchronized (lock) { + outList = new LinkedList(triggersByGroup.keySet()); } return outList; @@ -772,119 +956,144 @@ *

* Get all of the Triggers that are associated to the given Job. *

- * + * *

* If there are no matches, a zero-length array should be returned. *

*/ - public Trigger[] getTriggersForJob(SchedulingContext ctxt, String jobName, - String groupName) { - ArrayList trigList = new ArrayList(); + public List getTriggersForJob(JobKey jobKey) { + ArrayList trigList = new ArrayList(); - String jobKey = JobWrapper.getJobNameKey(jobName, groupName); - synchronized (triggerLock) { - for (int i = 0; i < triggers.size(); i++) { - TriggerWrapper tw = (TriggerWrapper) triggers.get(i); - if (tw.jobKey.equals(jobKey)) trigList.add(tw.trigger.clone()); + synchronized (lock) { + for (TriggerWrapper tw : triggers) { + if (tw.jobKey.equals(jobKey)) { + trigList.add((OperableTrigger) tw.trigger.clone()); + } } } - return (Trigger[]) trigList.toArray(new Trigger[trigList.size()]); + return trigList; } - protected ArrayList getTriggerWrappersForJob(String jobName, String groupName) { - ArrayList trigList = new ArrayList(); + protected ArrayList getTriggerWrappersForJob(JobKey jobKey) { + ArrayList trigList = new ArrayList(); - String jobKey = JobWrapper.getJobNameKey(jobName, groupName); - synchronized (triggerLock) { - for (int i = 0; i < triggers.size(); i++) { - TriggerWrapper tw = (TriggerWrapper) triggers.get(i); - if (tw.jobKey.equals(jobKey)) trigList.add(tw); + synchronized (lock) { + for (TriggerWrapper trigger : triggers) { + if (trigger.jobKey.equals(jobKey)) { + trigList.add(trigger); + } } } return trigList; } - protected ArrayList getTriggerWrappersForCalendar(String calName) { - ArrayList trigList = new ArrayList(); + protected ArrayList getTriggerWrappersForCalendar(String calName) { + ArrayList trigList = new ArrayList(); - synchronized (triggerLock) { - for (int i = 0; i < triggers.size(); i++) { - TriggerWrapper tw = (TriggerWrapper) triggers.get(i); + synchronized (lock) { + for (TriggerWrapper tw : triggers) { String tcalName = tw.getTrigger().getCalendarName(); - if (tcalName != null && tcalName.equals(calName)) + if (tcalName != null && tcalName.equals(calName)) { trigList.add(tw); + } } } return trigList; } - + /** *

* Pause the {@link Trigger} with the given name. *

- * + * */ - public void pauseTrigger(SchedulingContext ctxt, String triggerName, - String groupName) { + public void pauseTrigger(TriggerKey triggerKey) { - TriggerWrapper tw = (TriggerWrapper) triggersByFQN.get(TriggerWrapper - .getTriggerNameKey(triggerName, groupName)); + synchronized (lock) { + TriggerWrapper tw = triggersByKey.get(triggerKey); + + // does the trigger exist? + if (tw == null || tw.trigger == null) { + return; + } + + // if the trigger is "complete" pausing it does not make sense... + if (tw.state == TriggerWrapper.STATE_COMPLETE) { + return; + } - // does the trigger exist? - if (tw == null || tw.trigger == null) return; - // if the trigger is "complete" pausing it does not make sense... - if (tw.state == TriggerWrapper.STATE_COMPLETE) return; - - synchronized (triggerLock) { - if(tw.state == TriggerWrapper.STATE_BLOCKED) + if(tw.state == TriggerWrapper.STATE_BLOCKED) { tw.state = TriggerWrapper.STATE_PAUSED_BLOCKED; - else + } else { tw.state = TriggerWrapper.STATE_PAUSED; + } + timeTriggers.remove(tw); } } /** *

- * Pause all of the {@link Trigger}s in the given group. + * Pause all of the known {@link Trigger}s matching. *

- * + * *

- * The JobStore should "remember" that the group is paused, and impose the - * pause on any new triggers that are added to the group while the group is + * The JobStore should "remember" the groups paused, and impose the + * pause on any new triggers that are added to one of these groups while the group is * paused. *

- * + * */ - public void pauseTriggerGroup(SchedulingContext ctxt, String groupName) { + public List pauseTriggers(GroupMatcher matcher) { - synchronized (pausedTriggerGroups) { - if (pausedTriggerGroups.contains(groupName)) return; - pausedTriggerGroups.add(groupName); - String[] names = getTriggerNames(ctxt, groupName); + List pausedGroups; + synchronized (lock) { + pausedGroups = new LinkedList(); - for (int i = 0; i < names.length; i++) { - pauseTrigger(ctxt, names[i], groupName); + StringMatcher.StringOperatorName operator = matcher.getCompareWithOperator(); + switch (operator) { + case EQUALS: + if(pausedTriggerGroups.add(matcher.getCompareToValue())) { + pausedGroups.add(matcher.getCompareToValue()); + } + break; + default : + for (String group : triggersByGroup.keySet()) { + if(operator.evaluate(group, matcher.getCompareToValue())) { + if(pausedTriggerGroups.add(matcher.getCompareToValue())) { + pausedGroups.add(group); + } + } + } } + + for (String pausedGroup : pausedGroups) { + Set keys = getTriggerKeys(GroupMatcher.triggerGroupEquals(pausedGroup)); + + for (TriggerKey key: keys) { + pauseTrigger(key); + } + } } + + return pausedGroups; } /** *

* Pause the {@link org.quartz.JobDetail} with the given * name - by pausing all of its current Triggers. *

- * + * */ - public void pauseJob(SchedulingContext ctxt, String jobName, - String groupName) { - synchronized (pausedTriggerGroups) { - Trigger[] triggers = getTriggersForJob(ctxt, jobName, groupName); - for (int j = 0; j < triggers.length; j++) { - pauseTrigger(ctxt, triggers[j].getName(), triggers[j].getGroup()); + public void pauseJob(JobKey jobKey) { + synchronized (lock) { + List triggersOfJob = getTriggersForJob(jobKey); + for (OperableTrigger trigger: triggersOfJob) { + pauseTrigger(trigger.getKey()); } } } @@ -894,65 +1103,89 @@ * Pause all of the {@link org.quartz.JobDetail}s in the * given group - by pausing all of their Triggers. *

- * - * + * + * *

* The JobStore should "remember" that the group is paused, and impose the * pause on any new jobs that are added to the group while the group is * paused. *

*/ - public void pauseJobGroup(SchedulingContext ctxt, String groupName) { - synchronized (pausedTriggerGroups) { - String[] jobNames = getJobNames(ctxt, groupName); + public List pauseJobs(GroupMatcher matcher) { + List pausedGroups = new LinkedList(); + synchronized (lock) { - for (int i = 0; i < jobNames.length; i++) { - Trigger[] triggers = getTriggersForJob(ctxt, jobNames[i], - groupName); - for (int j = 0; j < triggers.length; j++) { - pauseTrigger(ctxt, triggers[j].getName(), - triggers[j].getGroup()); + StringMatcher.StringOperatorName operator = matcher.getCompareWithOperator(); + switch (operator) { + case EQUALS: + if (pausedJobGroups.add(matcher.getCompareToValue())) { + pausedGroups.add(matcher.getCompareToValue()); + } + break; + default : + for (String group : jobsByGroup.keySet()) { + if(operator.evaluate(group, matcher.getCompareToValue())) { + if (pausedJobGroups.add(group)) { + pausedGroups.add(group); + } + } + } + } + + for (String groupName : pausedGroups) { + for (JobKey jobKey: getJobKeys(GroupMatcher.jobGroupEquals(groupName))) { + List triggersOfJob = getTriggersForJob(jobKey); + for (OperableTrigger trigger: triggersOfJob) { + pauseTrigger(trigger.getKey()); + } } } } + + return pausedGroups; } /** *

* Resume (un-pause) the {@link Trigger} with the given - * name. + * key. *

- * + * *

* If the Trigger missed one or more fire-times, then the * Trigger's misfire instruction will be applied. *

- * + * */ - public void resumeTrigger(SchedulingContext ctxt, String triggerName, - String groupName) { + public void resumeTrigger(TriggerKey triggerKey) { - TriggerWrapper tw = (TriggerWrapper) triggersByFQN.get(TriggerWrapper - .getTriggerNameKey(triggerName, groupName)); + synchronized (lock) { + TriggerWrapper tw = triggersByKey.get(triggerKey); + + // does the trigger exist? + if (tw == null || tw.trigger == null) { + return; + } + + OperableTrigger trig = tw.getTrigger(); + + // if the trigger is not paused resuming it does not make sense... + if (tw.state != TriggerWrapper.STATE_PAUSED && + tw.state != TriggerWrapper.STATE_PAUSED_BLOCKED) { + return; + } - Trigger trig = tw.getTrigger(); - - // does the trigger exist? - if (tw == null || tw.trigger == null) return; - // if the trigger is not paused resuming it does not make sense... - if (tw.state != TriggerWrapper.STATE_PAUSED && - tw.state != TriggerWrapper.STATE_PAUSED_BLOCKED) - return; - - synchronized (triggerLock) { - if(blockedJobs.contains( JobWrapper.getJobNameKey(trig.getJobName(), trig.getJobGroup()) )) + if(blockedJobs.contains( trig.getJobKey() )) { tw.state = TriggerWrapper.STATE_BLOCKED; - else + } else { tw.state = TriggerWrapper.STATE_WAITING; - + } + applyMisfire(tw); - - if (tw.state == TriggerWrapper.STATE_WAITING) timeTriggers.add(tw); + + if (tw.state == TriggerWrapper.STATE_WAITING) { + timeTriggers.add(tw); + } } } @@ -961,45 +1194,56 @@ * Resume (un-pause) all of the {@link Trigger}s in the * given group. *

- * + * *

* If any Trigger missed one or more fire-times, then the * Trigger's misfire instruction will be applied. *

- * + * */ - public void resumeTriggerGroup(SchedulingContext ctxt, String groupName) { + public List resumeTriggers(GroupMatcher matcher) { + Set groups = new HashSet(); - synchronized (pausedTriggerGroups) { - String[] names = getTriggerNames(ctxt, groupName); + synchronized (lock) { + Set keys = getTriggerKeys(matcher); - for (int i = 0; i < names.length; i++) { - resumeTrigger(ctxt, names[i], groupName); + for (TriggerKey triggerKey: keys) { + groups.add(triggerKey.getGroup()); + if(triggersByKey.get(triggerKey) != null) { + String jobGroup = triggersByKey.get(triggerKey).jobKey.getGroup(); + if(pausedJobGroups.contains(jobGroup)) { + continue; + } + } + resumeTrigger(triggerKey); } - pausedTriggerGroups.remove(groupName); + for (String group : groups) { + pausedTriggerGroups.remove(group); + } } + + return new ArrayList(groups); } /** *

* Resume (un-pause) the {@link org.quartz.JobDetail} with * the given name. *

- * + * *

* If any of the Job'sTrigger s missed one * or more fire-times, then the Trigger's misfire * instruction will be applied. *

- * + * */ - public void resumeJob(SchedulingContext ctxt, String jobName, - String groupName) { + public void resumeJob(JobKey jobKey) { - synchronized (pausedTriggerGroups) { - Trigger[] triggers = getTriggersForJob(ctxt, jobName, groupName); - for (int j = 0; j < triggers.length; j++) { - resumeTrigger(ctxt, triggers[j].getName(), triggers[j].getGroup()); + synchronized (lock) { + List triggersOfJob = getTriggersForJob(jobKey); + for (OperableTrigger trigger: triggersOfJob) { + resumeTrigger(trigger.getKey()); } } } @@ -1009,50 +1253,61 @@ * Resume (un-pause) all of the {@link org.quartz.JobDetail}s * in the given group. *

- * + * *

* If any of the Job s had Trigger s that * missed one or more fire-times, then the Trigger's * misfire instruction will be applied. *

- * + * */ - public void resumeJobGroup(SchedulingContext ctxt, String groupName) { - synchronized (pausedTriggerGroups) { - String[] jobNames = getJobNames(ctxt, groupName); + public Collection resumeJobs(GroupMatcher matcher) { + Set resumedGroups = new HashSet(); + synchronized (lock) { + Set keys = getJobKeys(matcher); - for (int i = 0; i < jobNames.length; i++) { - Trigger[] triggers = getTriggersForJob(ctxt, jobNames[i], - groupName); - for (int j = 0; j < triggers.length; j++) { - resumeTrigger(ctxt, triggers[j].getName(), - triggers[j].getGroup()); + for (String pausedJobGroup : pausedJobGroups) { + if(matcher.getCompareWithOperator().evaluate(pausedJobGroup, matcher.getCompareToValue())) { + resumedGroups.add(pausedJobGroup); } } + + for (String resumedGroup : resumedGroups) { + pausedJobGroups.remove(resumedGroup); + } + + for (JobKey key: keys) { + List triggersOfJob = getTriggersForJob(key); + for (OperableTrigger trigger: triggersOfJob) { + resumeTrigger(trigger.getKey()); + } + } } + return resumedGroups; } /** *

* Pause all triggers - equivalent of calling pauseTriggerGroup(group) * on every group. *

- * + * *

* When resumeAll() is called (to un-pause), trigger misfire * instructions WILL be applied. *

- * - * @see #resumeAll(SchedulingContext) - * @see #pauseTriggerGroup(SchedulingContext, String) + * + * @see #resumeAll() + * @see #pauseTrigger(org.quartz.TriggerKey) + * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher) */ - public void pauseAll(SchedulingContext ctxt) { + public void pauseAll() { - synchronized (pausedTriggerGroups) { - String[] names = getTriggerGroupNames(ctxt); + synchronized (lock) { + List names = getTriggerGroupNames(); - for (int i = 0; i < names.length; i++) { - pauseTriggerGroup(ctxt, names[i]); + for (String name: names) { + pauseTriggers(GroupMatcher.triggerGroupEquals(name)); } } } @@ -1062,108 +1317,139 @@ * Resume (un-pause) all triggers - equivalent of calling resumeTriggerGroup(group) * on every group. *

- * + * *

* If any Trigger missed one or more fire-times, then the * Trigger's misfire instruction will be applied. *

- * - * @see #pauseAll(SchedulingContext) + * + * @see #pauseAll() */ - public void resumeAll(SchedulingContext ctxt) { + public void resumeAll() { - synchronized (pausedTriggerGroups) { - String[] names = getTriggerGroupNames(ctxt); - - for (int i = 0; i < names.length; i++) { - resumeTriggerGroup(ctxt, names[i]); - } + synchronized (lock) { + pausedJobGroups.clear(); + resumeTriggers(GroupMatcher.anyTriggerGroup()); } } protected boolean applyMisfire(TriggerWrapper tw) { long misfireTime = System.currentTimeMillis(); - if (getMisfireThreshold() > 0) misfireTime -= getMisfireThreshold(); + if (getMisfireThreshold() > 0) { + misfireTime -= getMisfireThreshold(); + } - java.util.Date tnft = tw.trigger.getNextFireTime(); - if (tnft.getTime() > misfireTime) { return false; } + Date tnft = tw.trigger.getNextFireTime(); + if (tnft == null || tnft.getTime() > misfireTime + || tw.trigger.getMisfireInstruction() == Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) { + return false; + } Calendar cal = null; - if (tw.trigger.getCalendarName() != null) - cal = retrieveCalendar(null, tw.trigger.getCalendarName()); + if (tw.trigger.getCalendarName() != null) { + cal = retrieveCalendar(tw.trigger.getCalendarName()); + } - signaler.notifyTriggerListenersMisfired(tw.trigger); + signaler.notifyTriggerListenersMisfired((OperableTrigger)tw.trigger.clone()); tw.trigger.updateAfterMisfire(cal); if (tw.trigger.getNextFireTime() == null) { tw.state = TriggerWrapper.STATE_COMPLETE; - synchronized (triggerLock) { + signaler.notifySchedulerListenersFinalized(tw.trigger); + synchronized (lock) { timeTriggers.remove(tw); } - } else if (tnft.equals(tw.trigger.getNextFireTime())) return false; + } else if (tnft.equals(tw.trigger.getNextFireTime())) { + return false; + } return true; } - private static long ftrCtr = System.currentTimeMillis(); + private static final AtomicLong ftrCtr = new AtomicLong(System.currentTimeMillis()); - protected synchronized String getFiredTriggerRecordId() { - return String.valueOf(ftrCtr++); + protected String getFiredTriggerRecordId() { + return String.valueOf(ftrCtr.incrementAndGet()); } /** *

* Get a handle to the next trigger to be fired, and mark it as 'reserved' * by the calling scheduler. *

- * - * @see #releaseAcquiredTrigger(SchedulingContext, Trigger) + * + * @see #releaseAcquiredTrigger(OperableTrigger) */ - public Trigger acquireNextTrigger(SchedulingContext ctxt, long noLaterThan) { - TriggerWrapper tw = null; + public List acquireNextTriggers(long noLaterThan, int maxCount, long timeWindow) { + synchronized (lock) { + List result = new ArrayList(); + Set acquiredJobKeysForNoConcurrentExec = new HashSet(); + Set excludedTriggers = new HashSet(); + long firstAcquiredTriggerFireTime = 0; + + // return empty list if store has no triggers. + if (timeTriggers.size() == 0) + return result; + + while (true) { + TriggerWrapper tw; - synchronized (triggerLock) { - - while (tw == null) { try { - tw = (TriggerWrapper) timeTriggers.first(); + tw = timeTriggers.first(); + if (tw == null) + break; + timeTriggers.remove(tw); } catch (java.util.NoSuchElementException nsee) { - return null; + break; } - if (tw == null) return null; - if (tw.trigger.getNextFireTime() == null) { - timeTriggers.remove(tw); - tw = null; continue; } - timeTriggers.remove(tw); - if (applyMisfire(tw)) { - if (tw.trigger.getNextFireTime() != null) - timeTriggers.add(tw); - tw = null; + if (tw.trigger.getNextFireTime() != null) { + timeTriggers.add(tw); + } continue; } - if(tw.trigger.getNextFireTime().getTime() > noLaterThan) { + if (tw.getTrigger().getNextFireTime().getTime() > noLaterThan + timeWindow) { timeTriggers.add(tw); - return null; + break; } - tw.state = TriggerWrapper.STATE_ACQUIRED; + // If trigger's job is set as @DisallowConcurrentExecution, and it has already been added to result, then + // put it back into the timeTriggers set and continue to search for next trigger. + JobKey jobKey = tw.trigger.getJobKey(); + JobDetail job = jobsByKey.get(tw.trigger.getJobKey()).jobDetail; + if (job.isConcurrentExectionDisallowed()) { + if (acquiredJobKeysForNoConcurrentExec.contains(jobKey)) { + excludedTriggers.add(tw); + continue; // go to next trigger in store. + } else { + acquiredJobKeysForNoConcurrentExec.add(jobKey); + } + } + tw.state = TriggerWrapper.STATE_ACQUIRED; tw.trigger.setFireInstanceId(getFiredTriggerRecordId()); - Trigger trig = (Trigger) tw.trigger.clone(); - return trig; + OperableTrigger trig = (OperableTrigger) tw.trigger.clone(); + result.add(trig); + if(firstAcquiredTriggerFireTime == 0) + firstAcquiredTriggerFireTime = tw.trigger.getNextFireTime().getTime(); + + if (result.size() == maxCount) + break; } + + // If we did excluded triggers to prevent ACQUIRE state due to DisallowConcurrentExecution, we need to add them back to store. + if (excludedTriggers.size() > 0) + timeTriggers.addAll(excludedTriggers); + return result; } - - return null; } /** @@ -1173,12 +1459,11 @@ * (reserved). *

*/ - public void releaseAcquiredTrigger(SchedulingContext ctxt, Trigger trigger) { - synchronized (triggerLock) { - TriggerWrapper tw = (TriggerWrapper) triggersByFQN.get(TriggerWrapper - .getTriggerNameKey(trigger)); - if (tw != null && tw.state == TriggerWrapper.STATE_ACQUIRED) { - tw.state = TriggerWrapper.STATE_WAITING; + public void releaseAcquiredTrigger(OperableTrigger trigger) { + synchronized (lock) { + TriggerWrapper tw = triggersByKey.get(trigger.getKey()); + if (tw != null && tw.state == TriggerWrapper.STATE_ACQUIRED) { + tw.state = TriggerWrapper.STATE_WAITING; timeTriggers.add(tw); } } @@ -1191,62 +1476,67 @@ * that it had previously acquired (reserved). *

*/ - public TriggerFiredBundle triggerFired(SchedulingContext ctxt, - Trigger trigger) { + public List triggersFired(List firedTriggers) { - synchronized (triggerLock) { - TriggerWrapper tw = (TriggerWrapper) triggersByFQN.get(TriggerWrapper - .getTriggerNameKey(trigger)); - // was the trigger deleted since being acquired? - if (tw == null || tw.trigger == null) return null; - // was the trigger completed since being acquired? - if (tw.state == TriggerWrapper.STATE_COMPLETE) return null; - // was the trigger paused since being acquired? - if (tw.state == TriggerWrapper.STATE_PAUSED) return null; - // was the trigger blocked since being acquired? - if (tw.state == TriggerWrapper.STATE_BLOCKED) return null; - // was the trigger paused and blocked since being acquired? - if (tw.state == TriggerWrapper.STATE_PAUSED_BLOCKED) return null; - - Calendar cal = null; - if (tw.trigger.getCalendarName() != null) - cal = retrieveCalendar(ctxt, tw.trigger.getCalendarName()); - Date prevFireTime = trigger.getPreviousFireTime(); - // call triggered on our copy, and the scheduler's copy - tw.trigger.triggered(cal); - trigger.triggered(cal); - //tw.state = TriggerWrapper.STATE_EXECUTING; - tw.state = TriggerWrapper.STATE_WAITING; + synchronized (lock) { + List results = new ArrayList(); - TriggerFiredBundle bndle = new TriggerFiredBundle(retrieveJob(ctxt, - trigger.getJobName(), trigger.getJobGroup()), trigger, cal, - false, new Date(), trigger.getPreviousFireTime(), prevFireTime, - trigger.getNextFireTime()); + for (OperableTrigger trigger : firedTriggers) { + TriggerWrapper tw = triggersByKey.get(trigger.getKey()); + // was the trigger deleted since being acquired? + if (tw == null || tw.trigger == null) { + continue; + } + // was the trigger completed, paused, blocked, etc. since being acquired? + if (tw.state != TriggerWrapper.STATE_ACQUIRED) { + continue; + } - JobDetail job = bndle.getJobDetail(); + Calendar cal = null; + if (tw.trigger.getCalendarName() != null) { + cal = retrieveCalendar(tw.trigger.getCalendarName()); + if(cal == null) + continue; + } + Date prevFireTime = trigger.getPreviousFireTime(); + // in case trigger was replaced between acquiring and firing + timeTriggers.remove(tw); + // call triggered on our copy, and the scheduler's copy + tw.trigger.triggered(cal); + trigger.triggered(cal); + //tw.state = TriggerWrapper.STATE_EXECUTING; + tw.state = TriggerWrapper.STATE_WAITING; - if (job.isStateful()) { - ArrayList trigs = getTriggerWrappersForJob(job.getName(), job - .getGroup()); - Iterator itr = trigs.iterator(); - while (itr.hasNext()) { - TriggerWrapper ttw = (TriggerWrapper) itr.next(); - if(ttw.state == TriggerWrapper.STATE_WAITING) - ttw.state = TriggerWrapper.STATE_BLOCKED; - if(ttw.state == TriggerWrapper.STATE_PAUSED) - ttw.state = TriggerWrapper.STATE_PAUSED_BLOCKED; - timeTriggers.remove(ttw); + TriggerFiredBundle bndle = new TriggerFiredBundle(retrieveJob( + tw.jobKey), trigger, cal, + false, new Date(), trigger.getPreviousFireTime(), prevFireTime, + trigger.getNextFireTime()); + + JobDetail job = bndle.getJobDetail(); + + if (job.isConcurrentExectionDisallowed()) { + ArrayList trigs = getTriggerWrappersForJob(job.getKey()); + for (TriggerWrapper ttw : trigs) { + if (ttw.state == TriggerWrapper.STATE_WAITING) { + ttw.state = TriggerWrapper.STATE_BLOCKED; + } + if (ttw.state == TriggerWrapper.STATE_PAUSED) { + ttw.state = TriggerWrapper.STATE_PAUSED_BLOCKED; + } + timeTriggers.remove(ttw); + } + blockedJobs.add(job.getKey()); + } else if (tw.trigger.getNextFireTime() != null) { + synchronized (lock) { + timeTriggers.add(tw); + } } - blockedJobs.add(JobWrapper.getJobNameKey(job)); - } else if (tw.trigger.getNextFireTime() != null) { - synchronized (triggerLock) { - timeTriggers.add(tw); + + results.add(new TriggerFiredResult(bndle)); } + return results; } - - return bndle; } - } /** *

@@ -1257,118 +1547,108 @@ * is stateful. *

*/ - public void triggeredJobComplete(SchedulingContext ctxt, Trigger trigger, - JobDetail jobDetail, int triggerInstCode) { + public void triggeredJobComplete(OperableTrigger trigger, + JobDetail jobDetail, CompletedExecutionInstruction triggerInstCode) { - synchronized (triggerLock) { + synchronized (lock) { - String jobKey = JobWrapper.getJobNameKey(jobDetail.getName(), jobDetail - .getGroup()); - JobWrapper jw = (JobWrapper) jobsByFQN.get(jobKey); - TriggerWrapper tw = (TriggerWrapper) triggersByFQN.get(TriggerWrapper - .getTriggerNameKey(trigger)); - + JobWrapper jw = jobsByKey.get(jobDetail.getKey()); + TriggerWrapper tw = triggersByKey.get(trigger.getKey()); + // It's possible that the job is null if: // 1- it was deleted during execution // 2- RAMJobStore is being used only for volatile jobs / triggers // from the JDBC job store if (jw != null) { JobDetail jd = jw.jobDetail; - - if (jobDetail.isStateful()) { + + if (jd.isPersistJobDataAfterExecution()) { JobDataMap newData = jobDetail.getJobDataMap(); - if (newData != null) newData.clearDirtyFlag(); - jd.setJobDataMap(newData); - blockedJobs.remove(JobWrapper.getJobNameKey(jd)); - ArrayList trigs = getTriggerWrappersForJob(jd.getName(), jd - .getGroup()); - Iterator itr = trigs.iterator(); - while (itr.hasNext()) { - TriggerWrapper ttw = (TriggerWrapper) itr.next(); - if (ttw.state == TriggerWrapper.STATE_BLOCKED) { - ttw.state = TriggerWrapper.STATE_WAITING; - timeTriggers.add(ttw); - } - if (ttw.state == TriggerWrapper.STATE_PAUSED_BLOCKED) { - ttw.state = TriggerWrapper.STATE_PAUSED; - } + if (newData != null) { + newData = (JobDataMap)newData.clone(); + newData.clearDirtyFlag(); + } + jd = jd.getJobBuilder().setJobData(newData).build(); + jw.jobDetail = jd; + } + if (jd.isConcurrentExectionDisallowed()) { + blockedJobs.remove(jd.getKey()); + ArrayList trigs = getTriggerWrappersForJob(jd.getKey()); + for(TriggerWrapper ttw : trigs) { + if (ttw.state == TriggerWrapper.STATE_BLOCKED) { + ttw.state = TriggerWrapper.STATE_WAITING; + timeTriggers.add(ttw); } + if (ttw.state == TriggerWrapper.STATE_PAUSED_BLOCKED) { + ttw.state = TriggerWrapper.STATE_PAUSED; + } } + signaler.signalSchedulingChange(0L); } - else { // even if it was deleted, there may be cleanup to do - blockedJobs.remove(JobWrapper.getJobNameKey(jobDetail)); + } else { // even if it was deleted, there may be cleanup to do + blockedJobs.remove(jobDetail.getKey()); } // check for trigger deleted during execution... if (tw != null) { - if (triggerInstCode == Trigger.INSTRUCTION_DELETE_TRIGGER) { + if (triggerInstCode == CompletedExecutionInstruction.DELETE_TRIGGER) { if(trigger.getNextFireTime() == null) { // double check for possible reschedule within job // execution, which would cancel the need to delete... - if(tw.getTrigger().getNextFireTime() == null) - removeTrigger(ctxt, trigger.getName(), trigger.getGroup()); + if(tw.getTrigger().getNextFireTime() == null) { + removeTrigger(trigger.getKey()); + } + } else { + removeTrigger(trigger.getKey()); + signaler.signalSchedulingChange(0L); } - else - removeTrigger(ctxt, trigger.getName(), trigger.getGroup()); - } - else if (triggerInstCode == Trigger.INSTRUCTION_SET_TRIGGER_COMPLETE) { + } else if (triggerInstCode == CompletedExecutionInstruction.SET_TRIGGER_COMPLETE) { tw.state = TriggerWrapper.STATE_COMPLETE; - timeTriggers.remove(tw); - } - else if(triggerInstCode == Trigger.INSTRUCTION_SET_TRIGGER_ERROR) { - getLog().info("Trigger " + trigger.getFullName() + " set to ERROR state."); + timeTriggers.remove(tw); + signaler.signalSchedulingChange(0L); + } else if(triggerInstCode == CompletedExecutionInstruction.SET_TRIGGER_ERROR) { + getLog().info("Trigger " + trigger.getKey() + " set to ERROR state."); tw.state = TriggerWrapper.STATE_ERROR; - } - else if (triggerInstCode == Trigger.INSTRUCTION_SET_ALL_JOB_TRIGGERS_ERROR) { + signaler.signalSchedulingChange(0L); + } else if (triggerInstCode == CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_ERROR) { getLog().info("All triggers of Job " - + trigger.getFullJobName() + " set to ERROR state."); - setAllTriggersOfJobToState( - trigger.getJobName(), - trigger.getJobGroup(), - TriggerWrapper.STATE_ERROR); + + trigger.getJobKey() + " set to ERROR state."); + setAllTriggersOfJobToState(trigger.getJobKey(), TriggerWrapper.STATE_ERROR); + signaler.signalSchedulingChange(0L); + } else if (triggerInstCode == CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_COMPLETE) { + setAllTriggersOfJobToState(trigger.getJobKey(), TriggerWrapper.STATE_COMPLETE); + signaler.signalSchedulingChange(0L); } - else if (triggerInstCode == Trigger.INSTRUCTION_SET_ALL_JOB_TRIGGERS_COMPLETE) { - setAllTriggersOfJobToState( - trigger.getJobName(), - trigger.getJobGroup(), - TriggerWrapper.STATE_COMPLETE); - } } } } - protected void setAllTriggersOfJobToState(String jobName, String jobGroup, int state) { - ArrayList tws = getTriggerWrappersForJob(jobName, jobGroup); - Iterator itr = tws.iterator(); - while (itr.hasNext()) { - TriggerWrapper tw = (TriggerWrapper) itr.next(); + protected void setAllTriggersOfJobToState(JobKey jobKey, int state) { + ArrayList tws = getTriggerWrappersForJob(jobKey); + for (TriggerWrapper tw : tws) { tw.state = state; - if(state != TriggerWrapper.STATE_WAITING) + if (state != TriggerWrapper.STATE_WAITING) { timeTriggers.remove(tw); + } } } + @SuppressWarnings("UnusedDeclaration") protected String peekTriggers() { - StringBuffer str = new StringBuffer(); - TriggerWrapper tw = null; - - synchronized (triggerLock) { - Iterator itr = triggersByFQN.keySet().iterator(); - while (itr.hasNext()) { - tw = (TriggerWrapper) triggersByFQN.get(itr.next()); - str.append(tw.trigger.getName()); + StringBuilder str = new StringBuilder(); + synchronized (lock) { + for (TriggerWrapper triggerWrapper : triggersByKey.values()) { + str.append(triggerWrapper.trigger.getKey().getName()); str.append("/"); } } str.append(" | "); - synchronized (triggerLock) { - Iterator itr = timeTriggers.iterator(); - while (itr.hasNext()) { - tw = (TriggerWrapper) itr.next(); - str.append(tw.trigger.getName()); + synchronized (lock) { + for (TriggerWrapper timeTrigger : timeTriggers) { + str.append(timeTrigger.trigger.getKey().getName()); str.append("->"); } } @@ -1377,17 +1657,36 @@ } /** - * @see org.quartz.spi.JobStore#getPausedTriggerGroups(org.quartz.core.SchedulingContext) + * @see org.quartz.spi.JobStore#getPausedTriggerGroups() */ - public Set getPausedTriggerGroups(SchedulingContext ctxt) throws JobPersistenceException { - HashSet set = new HashSet(); + public Set getPausedTriggerGroups() throws JobPersistenceException { + HashSet set = new HashSet(); set.addAll(pausedTriggerGroups); return set; } + public void setInstanceId(String schedInstId) { + // + } + public void setInstanceName(String schedName) { + // + } + + public void setThreadPoolSize(final int poolSize) { + // + } + + public long getEstimatedTimeToReleaseAndAcquireTrigger() { + return 5; + } + + public boolean isClustered() { + return false; + } + } /******************************************************************************* @@ -1396,131 +1695,110 @@ * Helper Classes. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -class TriggerComparator implements Comparator { +class TriggerWrapperComparator implements Comparator, java.io.Serializable { + + private static final long serialVersionUID = 8809557142191514261L; - public int compare(Object obj1, Object obj2) { - TriggerWrapper trig1 = (TriggerWrapper) obj1; - TriggerWrapper trig2 = (TriggerWrapper) obj2; - - int comp = trig1.trigger.compareTo(trig2.trigger); - - if (comp == 0) - return trig1.trigger.getFullName().compareTo(trig2.trigger.getFullName()); - - return comp; + TriggerTimeComparator ttc = new TriggerTimeComparator(); + + public int compare(TriggerWrapper trig1, TriggerWrapper trig2) { + return ttc.compare(trig1.trigger, trig2.trigger); } + @Override public boolean equals(Object obj) { - if (obj instanceof TriggerComparator) return true; + return (obj instanceof TriggerWrapperComparator); + } - return false; + @Override + public int hashCode() { + return super.hashCode(); } } class JobWrapper { - public String key; + public JobKey key; public JobDetail jobDetail; JobWrapper(JobDetail jobDetail) { this.jobDetail = jobDetail; - key = getJobNameKey(jobDetail); + key = jobDetail.getKey(); } - JobWrapper(JobDetail jobDetail, String key) { - this.jobDetail = jobDetail; - this.key = key; - } - - static String getJobNameKey(JobDetail jobDetail) { - return jobDetail.getGroup() + "_$x$x$_" + jobDetail.getName(); - } - - static String getJobNameKey(String jobName, String groupName) { - return groupName + "_$x$x$_" + jobName; - } - + @Override public boolean equals(Object obj) { if (obj instanceof JobWrapper) { JobWrapper jw = (JobWrapper) obj; - if (jw.key.equals(this.key)) return true; + if (jw.key.equals(this.key)) { + return true; + } } return false; } + @Override public int hashCode() { return key.hashCode(); } - - } class TriggerWrapper { - public String key; + public final TriggerKey key; - public String jobKey; + public final JobKey jobKey; - public Trigger trigger; + public final OperableTrigger trigger; public int state = STATE_WAITING; - public final static int STATE_WAITING = 0; + public static final int STATE_WAITING = 0; - public final static int STATE_ACQUIRED = 1; + public static final int STATE_ACQUIRED = 1; - public final static int STATE_EXECUTING = 2; + @SuppressWarnings("UnusedDeclaration") + public static final int STATE_EXECUTING = 2; - public final static int STATE_COMPLETE = 3; + public static final int STATE_COMPLETE = 3; - public final static int STATE_PAUSED = 4; + public static final int STATE_PAUSED = 4; - public final static int STATE_BLOCKED = 5; + public static final int STATE_BLOCKED = 5; - public final static int STATE_PAUSED_BLOCKED = 6; + public static final int STATE_PAUSED_BLOCKED = 6; - public final static int STATE_ERROR = 7; + public static final int STATE_ERROR = 7; - TriggerWrapper(Trigger trigger) { + TriggerWrapper(OperableTrigger trigger) { + if(trigger == null) + throw new IllegalArgumentException("Trigger cannot be null!"); this.trigger = trigger; - key = getTriggerNameKey(trigger); - this.jobKey = JobWrapper.getJobNameKey(trigger.getJobName(), trigger - .getJobGroup()); + key = trigger.getKey(); + this.jobKey = trigger.getJobKey(); } - TriggerWrapper(Trigger trigger, String key) { - this.trigger = trigger; - this.key = key; - this.jobKey = JobWrapper.getJobNameKey(trigger.getJobName(), trigger - .getJobGroup()); - } - - static String getTriggerNameKey(Trigger trigger) { - return trigger.getGroup() + "_$x$x$_" + trigger.getName(); - } - - static String getTriggerNameKey(String triggerName, String groupName) { - return groupName + "_$x$x$_" + triggerName; - } - + @Override public boolean equals(Object obj) { if (obj instanceof TriggerWrapper) { TriggerWrapper tw = (TriggerWrapper) obj; - if (tw.key.equals(this.key)) return true; + if (tw.key.equals(this.key)) { + return true; + } } return false; } + @Override public int hashCode() { return key.hashCode(); } - public Trigger getTrigger() { + public OperableTrigger getTrigger() { return this.trigger; } - } Index: 3rdParty_sources/quartz/org/quartz/simpl/SimpleClassLoadHelper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/simpl/SimpleClassLoadHelper.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/simpl/SimpleClassLoadHelper.java 17 Aug 2012 15:10:16 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/simpl/SimpleClassLoadHelper.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.simpl; import org.quartz.spi.ClassLoadHelper; @@ -36,6 +33,7 @@ * @see org.quartz.simpl.LoadingLoaderClassLoadHelper * * @author jhouse + * @author pl47ypus */ public class SimpleClassLoadHelper implements ClassLoadHelper { @@ -49,7 +47,7 @@ /** * Called to give the ClassLoadHelper a chance to initialize itself, - * including the oportunity to "steal" the class loader off of the calling + * including the opportunity to "steal" the class loader off of the calling * thread, which is the thread that is initializing Quartz. */ public void initialize() { @@ -58,10 +56,16 @@ /** * Return the class with the given name. */ - public Class loadClass(String name) throws ClassNotFoundException { + public Class loadClass(String name) throws ClassNotFoundException { return Class.forName(name); } + @SuppressWarnings("unchecked") + public Class loadClass(String name, Class clazz) + throws ClassNotFoundException { + return (Class) loadClass(name); + } + /** * Finds a resource with a given name. This method returns null if no * resource with this name is found. @@ -82,22 +86,26 @@ return getClassLoader().getResourceAsStream(name); } - private ClassLoader getClassLoader() { + /** + * Enable sharing of the class-loader with 3rd party. + * + * @return the class-loader user be the helper. + */ + public ClassLoader getClassLoader() { // To follow the same behavior of Class.forName(...) I had to play // dirty (Supported by Sun, IBM & BEA JVMs) - // ToDo - Test it more. try { // Get a reference to this class' class-loader ClassLoader cl = this.getClass().getClassLoader(); - // Create a method instance represnting the protected + // Create a method instance representing the protected // getCallerClassLoader method of class ClassLoader Method mthd = ClassLoader.class.getDeclaredMethod( - "getCallerClassLoader", new Class[0]); + "getCallerClassLoader", new Class[0]); // Make the method accessible. AccessibleObject.setAccessible(new AccessibleObject[] {mthd}, true); // Try to get the caller's class-loader return (ClassLoader)mthd.invoke(cl, new Object[0]); - } catch (Exception all) { + } catch (Throwable all) { // Use this class' class-loader return this.getClass().getClassLoader(); } Index: 3rdParty_sources/quartz/org/quartz/simpl/SimpleInstanceIdGenerator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/simpl/SimpleInstanceIdGenerator.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/simpl/SimpleInstanceIdGenerator.java 17 Aug 2012 15:10:16 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/simpl/SimpleInstanceIdGenerator.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -28,13 +28,11 @@ * @see InstanceIdGenerator * @see HostnameInstanceIdGenerator */ -public class SimpleInstanceIdGenerator implements InstanceIdGenerator -{ +public class SimpleInstanceIdGenerator implements InstanceIdGenerator { public String generateInstanceId() throws SchedulerException { try { return InetAddress.getLocalHost().getHostName() + System.currentTimeMillis(); - } - catch (Exception e) { + } catch (Exception e) { throw new SchedulerException("Couldn't get host name!", e); } } Index: 3rdParty_sources/quartz/org/quartz/simpl/SimpleJobFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/simpl/SimpleJobFactory.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/simpl/SimpleJobFactory.java 17 Aug 2012 15:10:16 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/simpl/SimpleJobFactory.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -16,10 +16,11 @@ */ package org.quartz.simpl; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.quartz.Job; import org.quartz.JobDetail; +import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.spi.JobFactory; import org.quartz.spi.TriggerFiredBundle; @@ -35,24 +36,30 @@ */ public class SimpleJobFactory implements JobFactory { - private Log log = LogFactory.getLog(SimpleJobFactory.class); + private final Logger log = LoggerFactory.getLogger(getClass()); - public Job newJob(TriggerFiredBundle bundle) throws SchedulerException { + protected Logger getLog() { + return log; + } + + public Job newJob(TriggerFiredBundle bundle, Scheduler Scheduler) throws SchedulerException { JobDetail jobDetail = bundle.getJobDetail(); - Class jobClass = jobDetail.getJobClass(); + Class jobClass = jobDetail.getJobClass(); try { - if(log.isDebugEnabled()) + if(log.isDebugEnabled()) { log.debug( - "Producing instance of Job '" + jobDetail.getFullName() + + "Producing instance of Job '" + jobDetail.getKey() + "', class=" + jobClass.getName()); + } - return (Job) jobClass.newInstance(); + return jobClass.newInstance(); } catch (Exception e) { SchedulerException se = new SchedulerException( "Problem instantiating class '" + jobDetail.getJobClass().getName() + "'", e); throw se; } } -} \ No newline at end of file + +} Index: 3rdParty_sources/quartz/org/quartz/simpl/SimpleThreadPool.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/simpl/SimpleThreadPool.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/simpl/SimpleThreadPool.java 17 Aug 2012 15:10:16 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/simpl/SimpleThreadPool.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,16 +15,18 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.simpl; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.quartz.SchedulerConfigException; import org.quartz.spi.ThreadPool; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + /** *

* This is class is a simple implementation of a thread pool, based on the @@ -59,6 +61,7 @@ private int prio = Thread.NORM_PRIORITY; private boolean isShutdown = false; + private boolean handoffPending = false; private boolean inheritLoader = false; @@ -68,14 +71,18 @@ private ThreadGroup threadGroup; - private Runnable nextRunnable; + private final Object nextRunnableLock = new Object(); - private Object nextRunnableLock = new Object(); + private List workers; + private LinkedList availWorkers = new LinkedList(); + private LinkedList busyWorkers = new LinkedList(); - private WorkerThread[] workers; + private String threadNamePrefix; - private String threadNamePrefix = "SimpleThreadPoolWorker"; + private final Logger log = LoggerFactory.getLogger(getClass()); + private String schedulerInstanceName; + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -122,8 +129,8 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - public Log getLog() { - return LogFactory.getLog(SimpleThreadPool.class); + public Logger getLog() { + return log; } public int getPoolSize() { @@ -169,13 +176,13 @@ } public void setThreadNamePrefix(String prfx) { - this.threadNamePrefix = prfx; + this.threadNamePrefix = prfx; } - + public String getThreadNamePrefix() { - return threadNamePrefix; + return threadNamePrefix; } - + /** * @return Returns the * threadsInheritContextClassLoaderOfInitializingThread. @@ -203,7 +210,7 @@ this.inheritGroup = inheritGroup; } - + /** * @return Returns the value of makeThreadsDaemons. */ @@ -218,56 +225,78 @@ public void setMakeThreadsDaemons(boolean makeThreadsDaemons) { this.makeThreadsDaemons = makeThreadsDaemons; } + + public void setInstanceId(String schedInstId) { + } + public void setInstanceName(String schedName) { + schedulerInstanceName = schedName; + } + public void initialize() throws SchedulerConfigException { - if (count <= 0) - throw new SchedulerConfigException( - "Thread count must be > 0"); - if (prio <= 0 || prio > 9) - throw new SchedulerConfigException( - "Thread priority must be > 0 and <= 9"); + if(workers != null && workers.size() > 0) // already initialized... + return; + + if (count <= 0) { + throw new SchedulerConfigException( + "Thread count must be > 0"); + } + if (prio <= 0 || prio > 9) { + throw new SchedulerConfigException( + "Thread priority must be > 0 and <= 9"); + } - if(isThreadsInheritGroupOfInitializingThread()) + if(isThreadsInheritGroupOfInitializingThread()) { threadGroup = Thread.currentThread().getThreadGroup(); - else { + } else { // follow the threadGroup tree to the root thread group. threadGroup = Thread.currentThread().getThreadGroup(); ThreadGroup parent = threadGroup; - while ( !parent.getName().equals("main") ) - { + while ( !parent.getName().equals("main") ) { threadGroup = parent; parent = threadGroup.getParent(); } - threadGroup = new ThreadGroup(parent, "SimpleThreadPool"); + threadGroup = new ThreadGroup(parent, schedulerInstanceName + "-SimpleThreadPool"); + if (isMakeThreadsDaemons()) { + threadGroup.setDaemon(true); + } } - - if (isThreadsInheritContextClassLoaderOfInitializingThread()) - getLog().info( - "Job execution threads will use class loader of thread: " - + Thread.currentThread().getName()); + if (isThreadsInheritContextClassLoaderOfInitializingThread()) { + getLog().info( + "Job execution threads will use class loader of thread: " + + Thread.currentThread().getName()); + } + // create the worker threads and start them - workers = createWorkerThreads(count); - for (int i = 0; i < count; ++i) { - if (isThreadsInheritContextClassLoaderOfInitializingThread()) { - workers[i].setContextClassLoader(Thread.currentThread() - .getContextClassLoader()); - } + Iterator workerThreads = createWorkerThreads(count).iterator(); + while(workerThreads.hasNext()) { + WorkerThread wt = workerThreads.next(); + wt.start(); + availWorkers.add(wt); } } - protected WorkerThread[] createWorkerThreads(int count) - { - workers = new WorkerThread[count]; - for (int i = 0; i < count; ++i) { - workers[i] = new WorkerThread(this, threadGroup, - getThreadNamePrefix() + "-" + i, - getThreadPriority(), + protected List createWorkerThreads(int createCount) { + workers = new LinkedList(); + for (int i = 1; i<= createCount; ++i) { + String threadPrefix = getThreadNamePrefix(); + if (threadPrefix == null) { + threadPrefix = schedulerInstanceName + "_Worker"; + } + WorkerThread wt = new WorkerThread(this, threadGroup, + threadPrefix + "-" + i, + getThreadPriority(), isMakeThreadsDaemons()); + if (isThreadsInheritContextClassLoaderOfInitializingThread()) { + wt.setContextClassLoader(Thread.currentThread() + .getContextClassLoader()); + } + workers.add(wt); } - + return workers; } @@ -294,58 +323,76 @@ *

*/ public void shutdown(boolean waitForJobsToComplete) { - isShutdown = true; - // signal each worker thread to shut down - for (int i = 0; i < workers.length; i++) { - if (workers[i] != null) workers[i].shutdown(); - } - - // Give waiting (wait(1000)) worker threads a chance to shut down. - // Active worker threads will shut down after finishing their - // current job. synchronized (nextRunnableLock) { + getLog().debug("Shutting down threadpool..."); + + isShutdown = true; + + if(workers == null) // case where the pool wasn't even initialize()ed + return; + + // signal each worker thread to shut down + Iterator workerThreads = workers.iterator(); + while(workerThreads.hasNext()) { + WorkerThread wt = workerThreads.next(); + wt.shutdown(); + availWorkers.remove(wt); + } + + // Give waiting (wait(1000)) worker threads a chance to shut down. + // Active worker threads will shut down after finishing their + // current job. nextRunnableLock.notifyAll(); - } - if (waitForJobsToComplete == true) { - // Wait until all worker threads are shut down - int alive = workers.length; - while (alive > 0) { - alive = 0; - for (int i = 0; i < workers.length; i++) { - if (workers[i].isAlive()) { + if (waitForJobsToComplete == true) { + + boolean interrupted = false; + try { + // wait for hand-off in runInThread to complete... + while(handoffPending) { try { - //if (logger.isDebugEnabled()) + nextRunnableLock.wait(100); + } catch(InterruptedException _) { + interrupted = true; + } + } + + // Wait until all worker threads are shut down + while (busyWorkers.size() > 0) { + WorkerThread wt = (WorkerThread) busyWorkers.getFirst(); + try { getLog().debug( - "Waiting for thread no. " + i + "Waiting for thread " + wt.getName() + " to shut down"); - // note: with waiting infinite - join(0) - the - // application - // may appear to 'hang'. Waiting for a finite time - // however - // requires an additional loop (alive). - alive++; - workers[i].join(200); - } catch (InterruptedException ex) { + // note: with waiting infinite time the + // application may appear to 'hang'. + nextRunnableLock.wait(2000); + } catch (InterruptedException _) { + interrupted = true; } } + + workerThreads = workers.iterator(); + while(workerThreads.hasNext()) { + WorkerThread wt = (WorkerThread) workerThreads.next(); + try { + wt.join(); + workerThreads.remove(); + } catch (InterruptedException _) { + interrupted = true; + } + } + } finally { + if (interrupted) { + Thread.currentThread().interrupt(); + } } - } - //if (logger.isDebugEnabled()) { - int activeCount = threadGroup.activeCount(); - if (activeCount > 0) - getLog() - .info( - "There are still " - + activeCount - + " worker threads active." - + " See javadoc runInThread(Runnable) for a possible explanation"); - - getLog().debug("shutdown complete"); - //} + getLog().debug("No executing jobs remaining, all threads stopped."); + } + getLog().debug("Shutdown of threadpool complete."); } } @@ -361,80 +408,71 @@ * the Runnable to be added. */ public boolean runInThread(Runnable runnable) { - if (runnable == null) return false; - - if (isShutdown) { - try { - getLog() - .info( - "SimpleThreadPool.runInThread(): thread pool has been shutdown. Runnable will not be executed"); - } catch(Exception e) { - // ignore to help with a tomcat glitch - } - + if (runnable == null) { return false; } synchronized (nextRunnableLock) { - // Wait until a worker thread has taken the previous Runnable - // or until the thread pool is asked to shutdown. - while ((nextRunnable != null) && !isShutdown) { + handoffPending = true; + + // Wait until a worker thread is available + while ((availWorkers.size() < 1) && !isShutdown) { try { - nextRunnableLock.wait(1000); + nextRunnableLock.wait(500); } catch (InterruptedException ignore) { } } - // During normal operation, not shutdown, set the nextRunnable - // and notify the worker threads waiting (getNextRunnable()). if (!isShutdown) { - nextRunnable = runnable; - nextRunnableLock.notifyAll(); + WorkerThread wt = (WorkerThread)availWorkers.removeFirst(); + busyWorkers.add(wt); + wt.run(runnable); + } else { + // If the thread pool is going down, execute the Runnable + // within a new additional worker thread (no thread from the pool). + WorkerThread wt = new WorkerThread(this, threadGroup, + "WorkerThread-LastJob", prio, isMakeThreadsDaemons(), runnable); + busyWorkers.add(wt); + workers.add(wt); + wt.start(); } + nextRunnableLock.notifyAll(); + handoffPending = false; } - // If the thread pool is going down, execute the Runnable - // within a new additional worker thread (no thread from the pool). - // note: the synchronized section should be as short (time) as - // possible. Starting a new thread is not a quick action. - if (isShutdown) { - new WorkerThread(this, threadGroup, - "WorkerThread-LastJob", prio, false, runnable); - } - return true; } - /** - *

- * Dequeue the next pending Runnable. - *

- * - *

- * getNextRunnable() should return null if within a specific time no new - * Runnable is available. This gives the worker thread the chance to check - * its shutdown flag. In case the worker thread is asked to shut down it - * will notify on nextRunnableLock, hence interrupt the wait state. That - * is, the time used for waiting need not be short. - *

- */ - private Runnable getNextRunnable() throws InterruptedException { - Runnable toRun = null; + public int blockForAvailableThreads() { + synchronized(nextRunnableLock) { - // Wait for new Runnable (see runInThread()) and notify runInThread() - // in case the next Runnable is already waiting. - synchronized (nextRunnableLock) { - if (nextRunnable == null) nextRunnableLock.wait(1000); + while((availWorkers.size() < 1 || handoffPending) && !isShutdown) { + try { + nextRunnableLock.wait(500); + } catch (InterruptedException ignore) { + } + } - if (nextRunnable != null) { - toRun = nextRunnable; - nextRunnable = null; - nextRunnableLock.notifyAll(); + return availWorkers.size(); + } + } + + protected void makeAvailable(WorkerThread wt) { + synchronized(nextRunnableLock) { + if(!isShutdown) { + availWorkers.add(wt); } + busyWorkers.remove(wt); + nextRunnableLock.notifyAll(); } + } - return toRun; + protected void clearFromBusyWorkersList(WorkerThread wt) { + synchronized(nextRunnableLock) { + busyWorkers.remove(wt); + nextRunnableLock.notifyAll(); + } } /* @@ -452,12 +490,16 @@ */ class WorkerThread extends Thread { + private final Object lock = new Object(); + // A flag that signals the WorkerThread to terminate. - private boolean run = true; + private AtomicBoolean run = new AtomicBoolean(true); private SimpleThreadPool tp; private Runnable runnable = null; + + private boolean runOnce = false; /** *

@@ -467,7 +509,7 @@ *

*/ WorkerThread(SimpleThreadPool tp, ThreadGroup threadGroup, String name, - int prio, boolean isDaemon) { + int prio, boolean isDaemon) { this(tp, threadGroup, name, prio, isDaemon, null); } @@ -479,14 +521,15 @@ *

*/ WorkerThread(SimpleThreadPool tp, ThreadGroup threadGroup, String name, - int prio, boolean isDaemon, Runnable runnable) { + int prio, boolean isDaemon, Runnable runnable) { super(threadGroup, name); this.tp = tp; this.runnable = runnable; + if(runnable != null) + runOnce = true; setPriority(prio); setDaemon(isDaemon); - start(); } /** @@ -495,59 +538,81 @@ *

*/ void shutdown() { - run = false; + run.set(false); + } - // @todo I'm not really sure if we should interrupt the thread. - // Javadoc mentions that it interrupts blocked I/O operations as - // well. Hence the job will most likely fail. I think we should - // shut the work thread gracefully, by letting the job finish - // uninterrupted. See SimpleThreadPool.shutdown() - //interrupt(); + public void run(Runnable newRunnable) { + synchronized(lock) { + if(runnable != null) { + throw new IllegalStateException("Already running a Runnable!"); + } + + runnable = newRunnable; + lock.notifyAll(); + } } /** *

* Loop, executing targets as they are received. *

*/ + @Override public void run() { - boolean runOnce = (runnable != null); - - while (run) { + boolean ran = false; + + while (run.get()) { try { - if (runnable == null) runnable = tp.getNextRunnable(); + synchronized(lock) { + while (runnable == null && run.get()) { + lock.wait(500); + } - if (runnable != null) runnable.run(); + if (runnable != null) { + ran = true; + runnable.run(); + } + } } catch (InterruptedException unblock) { // do nothing (loop will terminate if shutdown() was called try { - getLog().error("worker threat got 'interrupt'ed.", unblock); - } catch(Exception e) { + getLog().error("Worker thread was interrupt()'ed.", unblock); + } catch(Exception e) { // ignore to help with a tomcat glitch } - } catch (Exception exceptionInRunnable) { + } catch (Throwable exceptionInRunnable) { try { getLog().error("Error while executing the Runnable: ", exceptionInRunnable); - } catch(Exception e) { + } catch(Exception e) { // ignore to help with a tomcat glitch } } finally { - if (runOnce) run = false; + synchronized(lock) { + runnable = null; + } + // repair the thread in case the runnable mucked it up... + if(getPriority() != tp.getThreadPriority()) { + setPriority(tp.getThreadPriority()); + } - runnable = null; + if (runOnce) { + run.set(false); + clearFromBusyWorkersList(this); + } else if(ran) { + ran = false; + makeAvailable(this); + } - // repair the thread in case the runnable mucked it up... - setPriority(tp.getThreadPriority()); } } //if (log.isDebugEnabled()) try { - getLog().debug("WorkerThread is shutting down"); - } catch(Exception e) { + getLog().debug("WorkerThread is shut down."); + } catch(Exception e) { // ignore to help with a tomcat glitch } -} + } } } Index: 3rdParty_sources/quartz/org/quartz/simpl/SimpleTimeBroker.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/simpl/SimpleTimeBroker.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/simpl/SimpleTimeBroker.java 17 Aug 2012 15:10:16 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/simpl/SimpleTimeBroker.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.simpl; import java.util.Date; @@ -46,6 +43,7 @@ * * @author James House */ +@SuppressWarnings("deprecation") public class SimpleTimeBroker implements TimeBroker { /* Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/simpl/SystemPropertyInstanceIdGenerator.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/simpl/ThreadContextClassLoadHelper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/simpl/ThreadContextClassLoadHelper.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/simpl/ThreadContextClassLoadHelper.java 17 Aug 2012 15:10:16 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/simpl/ThreadContextClassLoadHelper.java 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.simpl; import org.quartz.spi.ClassLoadHelper; @@ -36,6 +33,7 @@ * @see org.quartz.simpl.LoadingLoaderClassLoadHelper * * @author jhouse + * @author pl47ypus */ public class ThreadContextClassLoadHelper implements ClassLoadHelper { @@ -49,7 +47,7 @@ /** * Called to give the ClassLoadHelper a chance to initialize itself, - * including the oportunity to "steal" the class loader off of the calling + * including the opportunity to "steal" the class loader off of the calling * thread, which is the thread that is initializing Quartz. */ public void initialize() { @@ -58,10 +56,16 @@ /** * Return the class with the given name. */ - public Class loadClass(String name) throws ClassNotFoundException { + public Class loadClass(String name) throws ClassNotFoundException { return getClassLoader().loadClass(name); } + @SuppressWarnings("unchecked") + public Class loadClass(String name, Class clazz) + throws ClassNotFoundException { + return (Class) loadClass(name); + } + /** * Finds a resource with a given name. This method returns null if no * resource with this name is found. @@ -82,8 +86,13 @@ return getClassLoader().getResourceAsStream(name); } - - private ClassLoader getClassLoader() { + /** + * Enable sharing of the class-loader with 3rd party. + * + * @return the class-loader user be the helper. + */ + public ClassLoader getClassLoader() { return Thread.currentThread().getContextClassLoader(); } + } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/simpl/ZeroSizeThreadPool.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/simpl/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/simpl/package.html,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/simpl/package.html 17 Aug 2012 15:10:16 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/simpl/package.html 15 Dec 2014 10:09:48 -0000 1.1.2.1 @@ -10,8 +10,8 @@


-See the Quartz project - at Open Symphony for more information. +See the Quartz project + for more information. Index: 3rdParty_sources/quartz/org/quartz/spi/ClassLoadHelper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/spi/ClassLoadHelper.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/spi/ClassLoadHelper.java 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/spi/ClassLoadHelper.java 15 Dec 2014 10:09:49 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.spi; import java.net.URL; @@ -28,42 +25,57 @@ * and resources within the scheduler... * * @author jhouse + * @author pl47ypus */ public interface ClassLoadHelper { - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Interface. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - /** * Called to give the ClassLoadHelper a chance to initialize itself, - * including the oportunity to "steal" the class loader off of the calling + * including the opportunity to "steal" the class loader off of the calling * thread, which is the thread that is initializing Quartz. */ - public void initialize(); + void initialize(); /** * Return the class with the given name. + * + * @param name the fqcn of the class to load. + * @return the requested class. + * @throws ClassNotFoundException if the class can be found in the classpath. */ - public Class loadClass(String name) throws ClassNotFoundException; + Class loadClass(String name) throws ClassNotFoundException; /** + * Return the class of the given type with the given name. + * + * @param name the fqcn of the class to load. + * @return the requested class. + * @throws ClassNotFoundException if the class can be found in the classpath. + */ + Class loadClass(String name, Class clazz) throws ClassNotFoundException; + + /** * Finds a resource with a given name. This method returns null if no * resource with this name is found. + * * @param name name of the desired resource * @return a java.net.URL object */ - public URL getResource(String name); + URL getResource(String name); /** * Finds a resource with a given name. This method returns null if no * resource with this name is found. + * * @param name name of the desired resource * @return a java.io.InputStream object */ - public InputStream getResourceAsStream(String name); + InputStream getResourceAsStream(String name); + + /** + * Enable sharing of the class-loader with 3rd party (e.g. digester). + * + * @return the class-loader user be the helper. + */ + ClassLoader getClassLoader(); } Index: 3rdParty_sources/quartz/org/quartz/spi/InstanceIdGenerator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/spi/InstanceIdGenerator.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/spi/InstanceIdGenerator.java 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/spi/InstanceIdGenerator.java 15 Dec 2014 10:09:49 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -21,7 +21,7 @@ /** *

* An InstanceIdGenerator is responsible for generating the clusterwide unique - * instance id for a Scheduler nodde. + * instance id for a Scheduler node. *

* *

@@ -32,8 +32,7 @@ * * @see org.quartz.simpl.SimpleInstanceIdGenerator */ -public interface InstanceIdGenerator -{ +public interface InstanceIdGenerator { /** * Generate the instance id for a Scheduler * Index: 3rdParty_sources/quartz/org/quartz/spi/JobFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/spi/JobFactory.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/spi/JobFactory.java 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/spi/JobFactory.java 15 Dec 2014 10:09:49 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -17,6 +17,7 @@ package org.quartz.spi; import org.quartz.Job; +import org.quartz.Scheduler; import org.quartz.SchedulerException; /** @@ -56,9 +57,10 @@ * @param bundle * The TriggerFiredBundle from which the JobDetail * and other info relating to the trigger firing can be obtained. + * @param scheduler a handle to the scheduler that is about to execute the job. * @throws SchedulerException if there is a problem instantiating the Job. * @return the newly instantiated Job */ - public Job newJob(TriggerFiredBundle bundle) throws SchedulerException; + Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException; } Index: 3rdParty_sources/quartz/org/quartz/spi/JobStore.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/spi/JobStore.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/spi/JobStore.java 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/spi/JobStore.java 15 Dec 2014 10:09:49 -0000 1.1.2.1 @@ -1,94 +1,117 @@ -/* - * Copyright 2004-2005 OpenSymphony - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations +/* + * Copyright 2001-2009 Terracotta, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations * under the License. - * + * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.spi; +import java.util.Collection; +import java.util.List; +import java.util.Map; import java.util.Set; import org.quartz.Calendar; +import org.quartz.Job; import org.quartz.JobDetail; +import org.quartz.JobKey; import org.quartz.JobPersistenceException; import org.quartz.ObjectAlreadyExistsException; import org.quartz.SchedulerConfigException; import org.quartz.SchedulerException; import org.quartz.Trigger; -import org.quartz.core.SchedulingContext; +import org.quartz.TriggerKey; +import org.quartz.Trigger.CompletedExecutionInstruction; +import org.quartz.Trigger.TriggerState; +import org.quartz.impl.matchers.GroupMatcher; /** *

* The interface to be implemented by classes that want to provide a {@link org.quartz.Job} * and {@link org.quartz.Trigger} storage mechanism for the * {@link org.quartz.core.QuartzScheduler}'s use. *

- * + * *

* Storage of Job s and Trigger s should be keyed * on the combination of their name and group for uniqueness. *

- * + * * @see org.quartz.core.QuartzScheduler * @see org.quartz.Trigger * @see org.quartz.Job * @see org.quartz.JobDetail * @see org.quartz.JobDataMap * @see org.quartz.Calendar - * + * * @author James House + * @author Eric Mueller */ public interface JobStore { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Interface. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** - *

* Called by the QuartzScheduler before the JobStore is * used, in order to give the it a chance to initialize. - *

*/ - public void initialize(ClassLoadHelper loadHelper, - SchedulerSignaler signaler) throws SchedulerConfigException; + void initialize(ClassLoadHelper loadHelper, SchedulerSignaler signaler) + throws SchedulerConfigException; /** - *

* Called by the QuartzScheduler to inform the JobStore that * the scheduler has started. - *

*/ - public void schedulerStarted() throws SchedulerException ; - + void schedulerStarted() throws SchedulerException ; + /** - *

* Called by the QuartzScheduler to inform the JobStore that + * the scheduler has been paused. + */ + void schedulerPaused(); + + /** + * Called by the QuartzScheduler to inform the JobStore that + * the scheduler has resumed after being paused. + */ + void schedulerResumed(); + + /** + * Called by the QuartzScheduler to inform the JobStore that * it should free up all of it's resources because the scheduler is * shutting down. - *

*/ - public void shutdown(); + void shutdown(); - public boolean supportsPersistence(); + boolean supportsPersistence(); + + /** + * How long (in milliseconds) the JobStore implementation + * estimates that it will take to release a trigger and acquire a new one. + */ + long getEstimatedTimeToReleaseAndAcquireTrigger(); + + /** + * Whether or not the JobStore implementation is clustered. + */ + boolean isClustered(); ///////////////////////////////////////////////////////////////////////////// // @@ -97,10 +120,8 @@ ///////////////////////////////////////////////////////////////////////////// /** - *

* Store the given {@link org.quartz.JobDetail} and {@link org.quartz.Trigger}. - *

- * + * * @param newJob * The JobDetail to be stored. * @param newTrigger @@ -109,15 +130,12 @@ * if a Job with the same name/group already * exists. */ - public void storeJobAndTrigger(SchedulingContext ctxt, JobDetail newJob, - Trigger newTrigger) throws ObjectAlreadyExistsException, - JobPersistenceException; + void storeJobAndTrigger(JobDetail newJob, OperableTrigger newTrigger) + throws ObjectAlreadyExistsException, JobPersistenceException; /** - *

* Store the given {@link org.quartz.JobDetail}. - *

- * + * * @param newJob * The JobDetail to be stored. * @param replaceExisting @@ -128,53 +146,44 @@ * if a Job with the same name/group already * exists, and replaceExisting is set to false. */ - public void storeJob(SchedulingContext ctxt, JobDetail newJob, - boolean replaceExisting) throws ObjectAlreadyExistsException, - JobPersistenceException; + void storeJob(JobDetail newJob, boolean replaceExisting) + throws ObjectAlreadyExistsException, JobPersistenceException; + public void storeJobsAndTriggers(Map> triggersAndJobs, boolean replace) + throws ObjectAlreadyExistsException, JobPersistenceException; + /** - *

* Remove (delete) the {@link org.quartz.Job} with the given - * name, and any {@link org.quartz.Trigger} s that reference + * key, and any {@link org.quartz.Trigger} s that reference * it. - *

- * + * *

* If removal of the Job results in an empty group, the * group should be removed from the JobStore's list of * known group names. *

- * - * @param jobName - * The name of the Job to be removed. - * @param groupName - * The group name of the Job to be removed. + * * @return true if a Job with the given name & * group was found and removed from the store. */ - public boolean removeJob(SchedulingContext ctxt, String jobName, - String groupName) throws JobPersistenceException; - + boolean removeJob(JobKey jobKey) + throws JobPersistenceException; + + public boolean removeJobs(List jobKeys) + throws JobPersistenceException; + /** - *

* Retrieve the {@link org.quartz.JobDetail} for the given * {@link org.quartz.Job}. - *

- * - * @param jobName - * The name of the Job to be retrieved. - * @param groupName - * The group name of the Job to be retrieved. + * * @return The desired Job, or null if there is no match. */ - public JobDetail retrieveJob(SchedulingContext ctxt, String jobName, - String groupName) throws JobPersistenceException; + JobDetail retrieveJob(JobKey jobKey) + throws JobPersistenceException; /** - *

* Store the given {@link org.quartz.Trigger}. - *

- * + * * @param newTrigger * The Trigger to be stored. * @param replaceExisting @@ -184,81 +193,90 @@ * @throws ObjectAlreadyExistsException * if a Trigger with the same name/group already * exists, and replaceExisting is set to false. - * - * @see #pauseTriggerGroup(SchedulingContext, String) + * + * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher) */ - public void storeTrigger(SchedulingContext ctxt, Trigger newTrigger, - boolean replaceExisting) throws ObjectAlreadyExistsException, - JobPersistenceException; + void storeTrigger(OperableTrigger newTrigger, boolean replaceExisting) + throws ObjectAlreadyExistsException, JobPersistenceException; /** - *

* Remove (delete) the {@link org.quartz.Trigger} with the - * given name. - *

- * + * given key. + * *

* If removal of the Trigger results in an empty group, the * group should be removed from the JobStore's list of * known group names. *

- * + * *

* If removal of the Trigger results in an 'orphaned' Job * that is not 'durable', then the Job should be deleted * also. *

- * - * @param triggerName - * The name of the Trigger to be removed. - * @param groupName - * The group name of the Trigger to be removed. + * * @return true if a Trigger with the given * name & group was found and removed from the store. */ - public boolean removeTrigger(SchedulingContext ctxt, String triggerName, - String groupName) throws JobPersistenceException; + boolean removeTrigger(TriggerKey triggerKey) throws JobPersistenceException; + public boolean removeTriggers(List triggerKeys) + throws JobPersistenceException; + /** - *

* Remove (delete) the {@link org.quartz.Trigger} with the - * given name, and store the new given one - which must be associated + * given key, and store the new given one - which must be associated * with the same job. - *

* - * @param triggerName - * The name of the Trigger to be removed. - * @param groupName - * The group name of the Trigger to be removed. * @param newTrigger * The new Trigger to be stored. + * * @return true if a Trigger with the given * name & group was found and removed from the store. */ - public boolean replaceTrigger(SchedulingContext ctxt, String triggerName, - String groupName, Trigger newTrigger) throws JobPersistenceException; + boolean replaceTrigger(TriggerKey triggerKey, OperableTrigger newTrigger) + throws JobPersistenceException; - /** - *

* Retrieve the given {@link org.quartz.Trigger}. - *

- * - * @param triggerName - * The name of the Trigger to be retrieved. - * @param groupName - * The group name of the Trigger to be retrieved. + * * @return The desired Trigger, or null if there is no * match. */ - public Trigger retrieveTrigger(SchedulingContext ctxt, String triggerName, - String groupName) throws JobPersistenceException; + OperableTrigger retrieveTrigger(TriggerKey triggerKey) throws JobPersistenceException; + /** - *

- * Store the given {@link org.quartz.Calendar}. - *

+ * Determine whether a {@link Job} with the given identifier already + * exists within the scheduler. * + * @param jobKey the identifier to check for + * @return true if a Job exists with the given identifier + * @throws SchedulerException + */ + boolean checkExists(JobKey jobKey) throws JobPersistenceException; + + /** + * Determine whether a {@link Trigger} with the given identifier already + * exists within the scheduler. + * + * @param triggerKey the identifier to check for + * @return true if a Trigger exists with the given identifier + * @throws SchedulerException + */ + boolean checkExists(TriggerKey triggerKey) throws JobPersistenceException; + + /** + * Clear (delete!) all scheduling data - all {@link Job}s, {@link Trigger}s + * {@link Calendar}s. + * + * @throws JobPersistenceException + */ + void clearAllSchedulingData() throws JobPersistenceException; + + /** + * Store the given {@link org.quartz.Calendar}. + * * @param calendar * The Calendar to be stored. * @param replaceExisting @@ -267,47 +285,42 @@ * should be over-written. * @param updateTriggers * If true, any Triggers existing - * in the JobStore that reference an existing + * in the JobStore that reference an existing * Calendar with the same name with have their next fire time * re-computed with the new Calendar. * @throws ObjectAlreadyExistsException * if a Calendar with the same name already * exists, and replaceExisting is set to false. */ - public void storeCalendar(SchedulingContext ctxt, String name, - Calendar calendar, boolean replaceExisting, boolean updateTriggers) - throws ObjectAlreadyExistsException, JobPersistenceException; + void storeCalendar(String name, Calendar calendar, boolean replaceExisting, boolean updateTriggers) + throws ObjectAlreadyExistsException, JobPersistenceException; /** - *

* Remove (delete) the {@link org.quartz.Calendar} with the * given name. - *

- * + * *

* If removal of the Calendar would result in - * s pointing to non-existent calendars, then a + * Triggers pointing to non-existent calendars, then a * JobPersistenceException will be thrown.

* * * @param calName The name of the Calendar to be removed. * @return true if a Calendar with the given name * was found and removed from the store. */ - public boolean removeCalendar(SchedulingContext ctxt, String calName) - throws JobPersistenceException; + boolean removeCalendar(String calName) + throws JobPersistenceException; /** - *

* Retrieve the given {@link org.quartz.Trigger}. - *

- * + * * @param calName * The name of the Calendar to be retrieved. * @return The desired Calendar, or null if there is no * match. */ - public Calendar retrieveCalendar(SchedulingContext ctxt, String calName) - throws JobPersistenceException; + Calendar retrieveCalendar(String calName) + throws JobPersistenceException; ///////////////////////////////////////////////////////////////////////////// // @@ -316,127 +329,101 @@ ///////////////////////////////////////////////////////////////////////////// /** - *

* Get the number of {@link org.quartz.Job} s that are * stored in the JobsStore. - *

*/ - public int getNumberOfJobs(SchedulingContext ctxt) - throws JobPersistenceException; + int getNumberOfJobs() + throws JobPersistenceException; /** - *

* Get the number of {@link org.quartz.Trigger} s that are * stored in the JobsStore. - *

*/ - public int getNumberOfTriggers(SchedulingContext ctxt) - throws JobPersistenceException; + int getNumberOfTriggers() + throws JobPersistenceException; /** - *

* Get the number of {@link org.quartz.Calendar} s that are * stored in the JobsStore. - *

*/ - public int getNumberOfCalendars(SchedulingContext ctxt) - throws JobPersistenceException; + int getNumberOfCalendars() + throws JobPersistenceException; /** - *

- * Get the names of all of the {@link org.quartz.Job} s that + * Get the keys of all of the {@link org.quartz.Job} s that * have the given group name. - *

- * + * *

- * If there are no jobs in the given group name, the result should be a - * zero-length array (not null). + * If there are no jobs in the given group name, the result should be + * an empty collection (not null). *

*/ - public String[] getJobNames(SchedulingContext ctxt, String groupName) - throws JobPersistenceException; + Set getJobKeys(GroupMatcher matcher) + throws JobPersistenceException; /** - *

* Get the names of all of the {@link org.quartz.Trigger} s * that have the given group name. - *

- * + * *

* If there are no triggers in the given group name, the result should be a * zero-length array (not null). *

*/ - public String[] getTriggerNames(SchedulingContext ctxt, String groupName) - throws JobPersistenceException; + Set getTriggerKeys(GroupMatcher matcher) + throws JobPersistenceException; /** - *

* Get the names of all of the {@link org.quartz.Job} * groups. - *

- * + * *

* If there are no known group names, the result should be a zero-length * array (not null). *

*/ - public String[] getJobGroupNames(SchedulingContext ctxt) - throws JobPersistenceException; + List getJobGroupNames() + throws JobPersistenceException; /** - *

* Get the names of all of the {@link org.quartz.Trigger} * groups. - *

- * + * *

* If there are no known group names, the result should be a zero-length * array (not null). *

*/ - public String[] getTriggerGroupNames(SchedulingContext ctxt) - throws JobPersistenceException; + List getTriggerGroupNames() + throws JobPersistenceException; /** - *

* Get the names of all of the {@link org.quartz.Calendar} s * in the JobStore. - *

- * + * *

* If there are no Calendars in the given group name, the result should be * a zero-length array (not null). *

*/ - public String[] getCalendarNames(SchedulingContext ctxt) - throws JobPersistenceException; + List getCalendarNames() + throws JobPersistenceException; /** - *

* Get all of the Triggers that are associated to the given Job. - *

- * + * *

* If there are no matches, a zero-length array should be returned. *

*/ - public Trigger[] getTriggersForJob(SchedulingContext ctxt, String jobName, - String groupName) throws JobPersistenceException; + List getTriggersForJob(JobKey jobKey) throws JobPersistenceException; /** - *

* Get the current state of the identified {@link Trigger}. - *

- * - * @see Trigger#STATE_NORMAL - * @see Trigger#STATE_PAUSED - * @see Trigger#STATE_COMPLETE - * @see Trigger#STATE_ERROR - * @see Trigger#STATE_NONE + * + * @see Trigger.TriggerState */ - public int getTriggerState(SchedulingContext ctxt, String triggerName, - String triggerGroup) throws JobPersistenceException; + TriggerState getTriggerState(TriggerKey triggerKey) throws JobPersistenceException; ///////////////////////////////////////////////////////////////////////////// // @@ -445,162 +432,136 @@ ///////////////////////////////////////////////////////////////////////////// /** - *

- * Pause the {@link org.quartz.Trigger} with the given name. - *

- * - * @see #resumeTrigger(SchedulingContext, String, String) + * Pause the {@link org.quartz.Trigger} with the given key. + * + * @see #resumeTrigger(TriggerKey) */ - public void pauseTrigger(SchedulingContext ctxt, String triggerName, - String groupName) throws JobPersistenceException; + void pauseTrigger(TriggerKey triggerKey) throws JobPersistenceException; /** - *

* Pause all of the {@link org.quartz.Trigger}s in the * given group. - *

- * - * + * + * *

* The JobStore should "remember" that the group is paused, and impose the * pause on any new triggers that are added to the group while the group is * paused. *

- * - * @see #resumeTriggerGroup(SchedulingContext, String) + * + * @see #resumeTriggerGroup(String) */ - public void pauseTriggerGroup(SchedulingContext ctxt, String groupName) - throws JobPersistenceException; + Collection pauseTriggers(GroupMatcher matcher) throws JobPersistenceException; /** - *

* Pause the {@link org.quartz.Job} with the given name - by * pausing all of its current Triggers. - *

- * - * @see #resumeJob(SchedulingContext, String, String) + * + * @see #resumeJob(JobKey) */ - public void pauseJob(SchedulingContext ctxt, String jobName, - String groupName) throws JobPersistenceException; + void pauseJob(JobKey jobKey) throws JobPersistenceException; /** - *

* Pause all of the {@link org.quartz.Job}s in the given * group - by pausing all of their Triggers. - *

- * + * *

* The JobStore should "remember" that the group is paused, and impose the * pause on any new jobs that are added to the group while the group is * paused. *

- * - * @see #resumeJobGroup(SchedulingContext, String) + * + * @see #resumeJobGroup(String) */ - public void pauseJobGroup(SchedulingContext ctxt, String groupName) - throws JobPersistenceException; + Collection pauseJobs(GroupMatcher groupMatcher) + throws JobPersistenceException; /** - *

* Resume (un-pause) the {@link org.quartz.Trigger} with the - * given name. - *

- * + * given key. + * *

* If the Trigger missed one or more fire-times, then the * Trigger's misfire instruction will be applied. *

- * - * @see #pauseTrigger(SchedulingContext, String, String) + * + * @see #pauseTrigger(TriggerKey) */ - public void resumeTrigger(SchedulingContext ctxt, String triggerName, - String groupName) throws JobPersistenceException; + void resumeTrigger(TriggerKey triggerKey) throws JobPersistenceException; /** - *

* Resume (un-pause) all of the {@link org.quartz.Trigger}s * in the given group. - *

- * + * *

* If any Trigger missed one or more fire-times, then the * Trigger's misfire instruction will be applied. *

- * - * @see #pauseTriggerGroup(SchedulingContext, String) + * + * @see #pauseTriggers(String) */ - public void resumeTriggerGroup(SchedulingContext ctxt, String groupName) - throws JobPersistenceException; + Collection resumeTriggers(GroupMatcher matcher) + throws JobPersistenceException; - public Set getPausedTriggerGroups(SchedulingContext ctxt) + Set getPausedTriggerGroups() throws JobPersistenceException; - /** - *

* Resume (un-pause) the {@link org.quartz.Job} with the - * given name. - *

- * + * given key. + * *

* If any of the Job'sTrigger s missed one * or more fire-times, then the Trigger's misfire * instruction will be applied. *

- * - * @see #pauseJob(SchedulingContext, String, String) + * + * @see #pauseJob(JobKey) */ - public void resumeJob(SchedulingContext ctxt, String jobName, - String groupName) throws JobPersistenceException; + void resumeJob(JobKey jobKey) throws JobPersistenceException; /** - *

* Resume (un-pause) all of the {@link org.quartz.Job}s in * the given group. - *

- * + * *

* If any of the Job s had Trigger s that * missed one or more fire-times, then the Trigger's * misfire instruction will be applied. *

- * - * @see #pauseJobGroup(SchedulingContext, String) + * + * @see #pauseJobGroup(String) */ - public void resumeJobGroup(SchedulingContext ctxt, String groupName) - throws JobPersistenceException; + Collection resumeJobs(GroupMatcher matcher) + throws JobPersistenceException; /** - *

* Pause all triggers - equivalent of calling pauseTriggerGroup(group) * on every group. - *

- * + * *

* When resumeAll() is called (to un-pause), trigger misfire * instructions WILL be applied. *

- * - * @see #resumeAll(SchedulingContext) - * @see #pauseTriggerGroup(SchedulingContext, String) + * + * @see #resumeAll() + * @see #pauseTriggers(String) */ - public void pauseAll(SchedulingContext ctxt) throws JobPersistenceException; + void pauseAll() throws JobPersistenceException; /** - *

* Resume (un-pause) all triggers - equivalent of calling resumeTriggerGroup(group) * on every group. - *

- * + * *

* If any Trigger missed one or more fire-times, then the * Trigger's misfire instruction will be applied. *

- * - * @see #pauseAll(SchedulingContext) + * + * @see #pauseAll() */ - public void resumeAll(SchedulingContext ctxt) - throws JobPersistenceException; + void resumeAll() + throws JobPersistenceException; ///////////////////////////////////////////////////////////////////////////// // @@ -609,54 +570,66 @@ ///////////////////////////////////////////////////////////////////////////// /** - *

* Get a handle to the next trigger to be fired, and mark it as 'reserved' * by the calling scheduler. - *

* - * @param noLaterThan If > 0, the JobStore should only return a Trigger - * that will fire no later than the time represented in this value as + * @param noLaterThan If > 0, the JobStore should only return a Trigger + * that will fire no later than the time represented in this value as * milliseconds. - * @see #releaseAcquiredTrigger(SchedulingContext, Trigger) + * @see #releaseAcquiredTrigger(Trigger) */ - public Trigger acquireNextTrigger(SchedulingContext ctxt, long noLaterThan) - throws JobPersistenceException; + List acquireNextTriggers(long noLaterThan, int maxCount, long timeWindow) + throws JobPersistenceException; /** - *

* Inform the JobStore that the scheduler no longer plans to * fire the given Trigger, that it had previously acquired * (reserved). - *

*/ - public void releaseAcquiredTrigger(SchedulingContext ctxt, Trigger trigger) - throws JobPersistenceException; + void releaseAcquiredTrigger(OperableTrigger trigger); /** - *

* Inform the JobStore that the scheduler is now firing the * given Trigger (executing its associated Job), * that it had previously acquired (reserved). - *

- * - * @return null if the trigger or it's job or calendar no longer exist, or + * + * @return may return null if all the triggers or their calendars no longer exist, or * if the trigger was not successfully put into the 'executing' - * state. + * state. Preference is to return an empty list if none of the triggers + * could be fired. */ - public TriggerFiredBundle triggerFired(SchedulingContext ctxt, - Trigger trigger) throws JobPersistenceException; + List triggersFired(List triggers) throws JobPersistenceException; /** - *

* Inform the JobStore that the scheduler has completed the - * firing of the given Trigger (and the execution its - * associated Job), and that the {@link org.quartz.JobDataMap} + * firing of the given Trigger (and the execution of its + * associated Job completed, threw an exception, or was vetoed), + * and that the {@link org.quartz.JobDataMap} * in the given JobDetail should be updated if the Job * is stateful. - *

*/ - public void triggeredJobComplete(SchedulingContext ctxt, Trigger trigger, - JobDetail jobDetail, int triggerInstCode) - throws JobPersistenceException; + void triggeredJobComplete(OperableTrigger trigger, JobDetail jobDetail, CompletedExecutionInstruction triggerInstCode); + /** + * Inform the JobStore of the Scheduler instance's Id, + * prior to initialize being invoked. + * + * @since 1.7 + */ + void setInstanceId(String schedInstId); + + /** + * Inform the JobStore of the Scheduler instance's name, + * prior to initialize being invoked. + * + * @since 1.7 + */ + void setInstanceName(String schedName); + + /** + * Tells the JobStore the pool size used to execute jobs + * @param poolSize amount of threads allocated for job execution + * @since 2.0 + */ + void setThreadPoolSize(int poolSize); } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/spi/MutableTrigger.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/spi/OperableTrigger.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/spi/SchedulerPlugin.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/spi/SchedulerPlugin.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/spi/SchedulerPlugin.java 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/spi/SchedulerPlugin.java 15 Dec 2014 10:09:49 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.spi; import org.quartz.Scheduler; @@ -41,6 +38,13 @@ * look at the configuration docs for details. *

* + *

+ * If you need direct access your plugin, you can have it explicitly put a + * reference to itself in the Scheduler's + * SchedulerContext as part of its + * {@link #initialize(String, Scheduler)} method. + *

+ * * @author James House */ public interface SchedulerPlugin { @@ -64,16 +68,26 @@ * initialized. *

* + *

+ * If you need direct access your plugin, for example during Job + * execution, you can have this method explicitly put a + * reference to this plugin in the Scheduler's + * SchedulerContext. + *

+ * * @param name * The name by which the plugin is identified. * @param scheduler * The scheduler to which the plugin is registered. + * @param loadHelper + * The classLoadHelper the SchedulerFactory is + * actually using * - * @throws SchedulerConfigException + * @throws org.quartz.SchedulerConfigException * if there is an error initializing. */ - public void initialize(String name, Scheduler scheduler) - throws SchedulerException; + void initialize(String name, Scheduler scheduler, ClassLoadHelper loadHelper) + throws SchedulerException; /** *

@@ -82,7 +96,7 @@ * needs to. *

*/ - public void start(); + void start(); /** *

@@ -91,6 +105,6 @@ * down. *

*/ - public void shutdown(); + void shutdown(); } Index: 3rdParty_sources/quartz/org/quartz/spi/SchedulerSignaler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/spi/SchedulerSignaler.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/spi/SchedulerSignaler.java 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/spi/SchedulerSignaler.java 15 Dec 2014 10:09:49 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,11 +15,10 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.spi; +import org.quartz.JobKey; +import org.quartz.SchedulerException; import org.quartz.Trigger; /** @@ -38,8 +37,13 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - public void notifyTriggerListenersMisfired(Trigger trigger); + void notifyTriggerListenersMisfired(Trigger trigger); - public void signalSchedulingChange(); + void notifySchedulerListenersFinalized(Trigger trigger); + void notifySchedulerListenersJobDeleted(JobKey jobKey); + + void signalSchedulingChange(long candidateNewNextFireTime); + + void notifySchedulerListenersError(String string, SchedulerException jpe); } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/spi/ThreadExecutor.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/spi/ThreadPool.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/spi/ThreadPool.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/spi/ThreadPool.java 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/spi/ThreadPool.java 15 Dec 2014 10:09:49 -0000 1.1.2.1 @@ -1,23 +1,20 @@ -/* - * Copyright 2004-2005 OpenSymphony - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations +/* + * Copyright 2001-2009 Terracotta, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations * under the License. - * + * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.spi; import org.quartz.SchedulerConfigException; @@ -27,18 +24,29 @@ * The interface to be implemented by classes that want to provide a thread * pool for the {@link org.quartz.core.QuartzScheduler}'s use. *

- * + * + *

+ * ThreadPool implementation instances should ideally be made + * for the sole use of Quartz. Most importantly, when the method + * blockForAvailableThreads() returns a value of 1 or greater, + * there must still be at least one available thread in the pool when the + * method runInThread(Runnable) is called a few moments (or + * many moments) later. If this assumption does not hold true, it may + * result in extra JobStore queries and updates, and if clustering features + * are being used, it may result in greater imballance of load. + *

+ * * @see org.quartz.core.QuartzScheduler - * + * * @author James House */ public interface ThreadPool { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Interface. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -47,23 +55,41 @@ * Execute the given {@link java.lang.Runnable} in the next * available Thread. *

- * + * *

* The implementation of this interface should not throw exceptions unless * there is a serious problem (i.e. a serious misconfiguration). If there - * are no available threads, rather it should either queue the Runnable, or - * block until a thread is available, depending on the desired strategy. + * are no immediately available threads false should be returned. *

+ * + * @return true, if the runnable was assigned to run on a Thread. */ - public boolean runInThread(Runnable runnable); + boolean runInThread(Runnable runnable); /** *

- * Called by the QuartzScheduler before the ThreadPool is + * Determines the number of threads that are currently available in in + * the pool. Useful for determining the number of times + * runInThread(Runnable) can be called before returning + * false. + *

+ * + *

The implementation of this method should block until there is at + * least one available thread.

+ * + * @return the number of currently available threads + */ + int blockForAvailableThreads(); + + /** + *

+ * Must be called before the ThreadPool is * used, in order to give the it a chance to initialize. *

+ * + *

Typically called by the SchedulerFactory.

*/ - public void initialize() throws SchedulerConfigException; + void initialize() throws SchedulerConfigException; /** *

@@ -72,7 +98,27 @@ * shutting down. *

*/ - public void shutdown(boolean waitForJobsToComplete); + void shutdown(boolean waitForJobsToComplete); - public int getPoolSize(); + /** + *

Get the current number of threads in the ThreadPool.

+ */ + int getPoolSize(); + + /** + *

Inform the ThreadPool of the Scheduler instance's Id, + * prior to initialize being invoked.

+ * + * @since 1.7 + */ + void setInstanceId(String schedInstId); + + /** + *

Inform the ThreadPool of the Scheduler instance's name, + * prior to initialize being invoked.

+ * + * @since 1.7 + */ + void setInstanceName(String schedName); + } Index: 3rdParty_sources/quartz/org/quartz/spi/TimeBroker.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/spi/TimeBroker.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/spi/TimeBroker.java 17 Aug 2012 15:10:19 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/spi/TimeBroker.java 15 Dec 2014 10:09:49 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.spi; import java.util.Date; @@ -26,6 +23,8 @@ import org.quartz.SchedulerException; /** + *

NOTE: TimeBroker is not currently used in the Quartz code base.

+ * *

* The interface to be implemented by classes that want to provide a mechanism * by which the {@link org.quartz.core.QuartzScheduler} can @@ -36,14 +35,14 @@ * In general, the default implementation of this interface ({@link org.quartz.simpl.SimpleTimeBroker}- * which simply uses System.getCurrentTimeMillis() )is * sufficient. However situations may exist where this default scheme is - * lacking in its robustsness - especially when Quartz is used in a clustered + * lacking in its robustness - especially when Quartz is used in a clustered * configuration. For example, if one or more of the machines in the cluster * has a system time that varies by more than a few seconds from the clocks on * the other systems in the cluster, scheduling confusion will result. *

* * @see org.quartz.core.QuartzScheduler - * + * @deprecated TimeBroker is not currently used in the Quartz code base. * @author James House */ public interface TimeBroker { @@ -65,15 +64,15 @@ * with the error code set to * SchedulerException.ERR_TIME_BROKER_FAILURE */ - public Date getCurrentTime() throws SchedulerException; + Date getCurrentTime() throws SchedulerException; /** *

* Called by the QuartzScheduler before the TimeBroker is * used, in order to give the it a chance to initialize. *

*/ - public void initialize() throws SchedulerConfigException; + void initialize() throws SchedulerConfigException; /** *

@@ -82,6 +81,6 @@ * shutting down. *

*/ - public void shutdown(); + void shutdown(); } Index: 3rdParty_sources/quartz/org/quartz/spi/TriggerFiredBundle.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/spi/TriggerFiredBundle.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/spi/TriggerFiredBundle.java 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/spi/TriggerFiredBundle.java 15 Dec 2014 10:09:49 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,28 +15,26 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.spi; import java.util.Date; import org.quartz.Calendar; import org.quartz.JobDetail; -import org.quartz.Trigger; /** *

* A simple class (structure) used for returning execution-time data from the * JobStore to the QuartzSchedulerThread. *

* - * @see org.quartz.core.QuartzScheduler + * @see org.quartz.core.QuartzSchedulerThread * * @author James House */ public class TriggerFiredBundle implements java.io.Serializable { + + private static final long serialVersionUID = -6414106108306999265L; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -48,7 +46,7 @@ private JobDetail job; - private Trigger trigger; + private OperableTrigger trigger; private Calendar cal; @@ -70,7 +68,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - public TriggerFiredBundle(JobDetail job, Trigger trigger, Calendar cal, + public TriggerFiredBundle(JobDetail job, OperableTrigger trigger, Calendar cal, boolean jobIsRecovering, Date fireTime, Date scheduledFireTime, Date prevFireTime, Date nextFireTime) { this.job = job; @@ -95,7 +93,7 @@ return job; } - public Trigger getTrigger() { + public OperableTrigger getTrigger() { return trigger; } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/spi/TriggerFiredResult.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/spi/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/spi/package.html,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/spi/package.html 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/spi/package.html 15 Dec 2014 10:09:49 -0000 1.1.2.1 @@ -10,8 +10,8 @@


-See the Quartz project - at Open Symphony for more information. +See the Quartz project + for more information. Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/CircularLossyQueue.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/ClassUtils.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/utils/ConnectionProvider.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/utils/ConnectionProvider.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/utils/ConnectionProvider.java 17 Aug 2012 15:10:20 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/utils/ConnectionProvider.java 15 Dec 2014 10:09:51 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.utils; import java.sql.Connection; @@ -47,8 +44,10 @@ * @return connection managed by this provider * @throws SQLException */ - public Connection getConnection() throws SQLException; + Connection getConnection() throws SQLException; - public void shutdown() throws SQLException; + void shutdown() throws SQLException; + + void initialize() throws SQLException; } Index: 3rdParty_sources/quartz/org/quartz/utils/DBConnectionManager.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/utils/DBConnectionManager.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/utils/DBConnectionManager.java 17 Aug 2012 15:10:21 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/utils/DBConnectionManager.java 15 Dec 2014 10:09:51 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.utils; import java.sql.Connection; @@ -61,7 +58,7 @@ private static DBConnectionManager instance = new DBConnectionManager(); - private HashMap providers = new HashMap(); + private HashMap providers = new HashMap(); /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -102,11 +99,11 @@ * given name. */ public Connection getConnection(String dsName) throws SQLException { - ConnectionProvider provider = (ConnectionProvider) providers - .get(dsName); - if (provider == null) - throw new SQLException("There is no DataSource named '" - + dsName + "'"); + ConnectionProvider provider = providers.get(dsName); + if (provider == null) { + throw new SQLException("There is no DataSource named '" + + dsName + "'"); + } return provider.getConnection(); } @@ -126,7 +123,6 @@ * Shuts down database connections from the DataSource with the given name, * if applicable for the underlying provider. * - * @return a database connection * @exception SQLException * if an error occurs, or there is no DataSource with the * given name. @@ -135,9 +131,10 @@ ConnectionProvider provider = (ConnectionProvider) providers .get(dsName); - if (provider == null) + if (provider == null) { throw new SQLException("There is no DataSource named '" + dsName + "'"); + } provider.shutdown(); Index: 3rdParty_sources/quartz/org/quartz/utils/DirtyFlagMap.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/utils/DirtyFlagMap.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/utils/DirtyFlagMap.java 17 Aug 2012 15:10:21 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/utils/DirtyFlagMap.java 15 Dec 2014 10:09:51 -0000 1.1.2.1 @@ -1,28 +1,26 @@ -/* - * Copyright 2004-2005 OpenSymphony - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations +/* + * Copyright 2001-2009 Terracotta, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations * under the License. - * + * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.utils; +import java.lang.reflect.Array; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -31,101 +29,74 @@ * An implementation of Map that wraps another Map * and flags itself 'dirty' when it is modified. *

- * + * * @author James House */ -public class DirtyFlagMap implements Map, Cloneable, java.io.Serializable { +public class DirtyFlagMap implements Map, Cloneable, java.io.Serializable { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Data members. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ private static final long serialVersionUID = 1433884852607126222L; private boolean dirty = false; - private transient boolean locked = false; - private Map map; + private Map map; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Constructors. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** *

- * Create a DirtyFlagMap that 'wraps' the given Map. - *

- */ - public DirtyFlagMap(Map mapToWrap) { - if (mapToWrap == null) - throw new IllegalArgumentException("mapToWrap cannot be null!"); - - map = mapToWrap; - } - - /** - *

* Create a DirtyFlagMap that 'wraps' a HashMap. *

- * + * * @see java.util.HashMap */ public DirtyFlagMap() { - map = new HashMap(); + map = new HashMap(); } /** *

* Create a DirtyFlagMap that 'wraps' a HashMap that has the * given initial capacity. *

- * + * * @see java.util.HashMap */ - public DirtyFlagMap(int initialCapacity) { - map = new HashMap(initialCapacity); + public DirtyFlagMap(final int initialCapacity) { + map = new HashMap(initialCapacity); } /** *

* Create a DirtyFlagMap that 'wraps' a HashMap that has the * given initial capacity and load factor. *

- * + * * @see java.util.HashMap */ - public DirtyFlagMap(int initialCapacity, float loadFactor) { - map = new HashMap(initialCapacity, loadFactor); + public DirtyFlagMap(final int initialCapacity, final float loadFactor) { + map = new HashMap(initialCapacity, loadFactor); } /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * + * * Interface. - * + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - - public void setMutable(boolean mutable) { - this.locked = !mutable; - if(locked) - map = Collections.unmodifiableMap(map); - else - map = new HashMap(map); - } - - - public boolean isMutable() { - return !locked; - } - /** *

* Clear the 'dirty' flag (set dirty flag to false). @@ -149,62 +120,76 @@ * Get a direct handle to the underlying Map. *

*/ - public Map getWrappedMap() { + public Map getWrappedMap() { return map; } public void clear() { - dirty = true; - + if (!map.isEmpty()) { + dirty = true; + } map.clear(); } - public boolean containsKey(Object key) { + public boolean containsKey(final Object key) { return map.containsKey(key); } - public boolean containsValue(Object val) { + public boolean containsValue(final Object val) { return map.containsValue(val); } - public Set entrySet() { - return map.entrySet(); + public Set> entrySet() { + return new DirtyFlagMapEntrySet(map.entrySet()); } - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof DirtyFlagMap)) return false; + @Override + public boolean equals(final Object obj) { + if (obj == null || !(obj instanceof DirtyFlagMap)) { + return false; + } - return map.equals(((DirtyFlagMap) obj).getWrappedMap()); + return map.equals(((DirtyFlagMap) obj).getWrappedMap()); } - public Object get(Object key) { + @Override + public int hashCode() + { + return map.hashCode(); + } + + public V get(final Object key) { return map.get(key); } public boolean isEmpty() { return map.isEmpty(); } - public Set keySet() { - return map.keySet(); + public Set keySet() { + return new DirtyFlagSet(map.keySet()); } - public Object put(Object key, Object val) { + public V put(final K key, final V val) { dirty = true; return map.put(key, val); } - public void putAll(Map t) { - if (!t.isEmpty()) dirty = true; + public void putAll(final Map t) { + if (!t.isEmpty()) { + dirty = true; + } map.putAll(t); } - public Object remove(Object key) { - Object obj = map.remove(key); + public V remove(final Object key) { + V obj = map.remove(key); - if (obj != null) dirty = true; + if (obj != null) { + dirty = true; + } return obj; } @@ -213,21 +198,204 @@ return map.size(); } - public Collection values() { - return map.values(); + public Collection values() { + return new DirtyFlagCollection(map.values()); } + @Override + @SuppressWarnings("unchecked") // suppress warnings on generic cast of super.clone() and map.clone() lines. public Object clone() { - DirtyFlagMap copy; + DirtyFlagMap copy; try { - copy = (DirtyFlagMap) super.clone(); - if (map instanceof HashMap) - copy.map = (Map) ((HashMap) map).clone(); + copy = (DirtyFlagMap) super.clone(); + if (map instanceof HashMap) { + copy.map = (Map)((HashMap)map).clone(); + } } catch (CloneNotSupportedException ex) { throw new IncompatibleClassChangeError("Not Cloneable."); } return copy; } -} \ No newline at end of file + /** + * Wrap a Collection so we can mark the DirtyFlagMap as dirty if + * the underlying Collection is modified. + */ + private class DirtyFlagCollection implements Collection { + private Collection collection; + + public DirtyFlagCollection(final Collection c) { + collection = c; + } + + protected Collection getWrappedCollection() { + return collection; + } + + public Iterator iterator() { + return new DirtyFlagIterator(collection.iterator()); + } + + public boolean remove(final Object o) { + boolean removed = collection.remove(o); + if (removed) { + dirty = true; + } + return removed; + } + + public boolean removeAll(final Collection c) { + boolean changed = collection.removeAll(c); + if (changed) { + dirty = true; + } + return changed; + } + + public boolean retainAll(final Collection c) { + boolean changed = collection.retainAll(c); + if (changed) { + dirty = true; + } + return changed; + } + + public void clear() { + if (collection.isEmpty() == false) { + dirty = true; + } + collection.clear(); + } + + // Pure wrapper methods + public int size() { return collection.size(); } + public boolean isEmpty() { return collection.isEmpty(); } + public boolean contains(final Object o) { return collection.contains(o); } + public boolean add(final T o) { return collection.add(o); } // Not supported + public boolean addAll(final Collection c) { return collection.addAll(c); } // Not supported + public boolean containsAll(final Collection c) { return collection.containsAll(c); } + public Object[] toArray() { return collection.toArray(); } + public U[] toArray(final U[] array) { return collection.toArray(array); } + } + + /** + * Wrap a Set so we can mark the DirtyFlagMap as dirty if + * the underlying Collection is modified. + */ + private class DirtyFlagSet extends DirtyFlagCollection implements Set { + public DirtyFlagSet(final Set set) { + super(set); + } + + protected Set getWrappedSet() { + return (Set)getWrappedCollection(); + } + } + + /** + * Wrap an Iterator so that we can mark the DirtyFlagMap as dirty if an + * element is removed. + */ + private class DirtyFlagIterator implements Iterator { + private Iterator iterator; + + public DirtyFlagIterator(final Iterator iterator) { + this.iterator = iterator; + } + + public void remove() { + dirty = true; + iterator.remove(); + } + + // Pure wrapper methods + public boolean hasNext() { return iterator.hasNext(); } + public T next() { return iterator.next(); } + } + + /** + * Wrap a Map.Entry Set so we can mark the Map as dirty if + * the Set is modified, and return Map.Entry objects + * wrapped in the DirtyFlagMapEntry class. + */ + private class DirtyFlagMapEntrySet extends DirtyFlagSet> { + + public DirtyFlagMapEntrySet(final Set> set) { + super(set); + } + + @Override + public Iterator> iterator() { + return new DirtyFlagMapEntryIterator(getWrappedSet().iterator()); + } + + @Override + public Object[] toArray() { + return toArray(new Object[super.size()]); + } + + @SuppressWarnings("unchecked") // suppress warnings on both U[] and U casting. + @Override + public U[] toArray(final U[] array) { + if (array.getClass().getComponentType().isAssignableFrom(Map.Entry.class) == false) { + throw new IllegalArgumentException("Array must be of type assignable from Map.Entry"); + } + + int size = super.size(); + + U[] result = + array.length < size ? + (U[])Array.newInstance(array.getClass().getComponentType(), size) : array; + + Iterator> entryIter = iterator(); // Will return DirtyFlagMapEntry objects + for (int i = 0; i < size; i++) { + result[i] = ( U ) entryIter.next(); + } + + if (result.length > size) { + result[size] = null; + } + + return result; + } + } + + /** + * Wrap an Iterator over Map.Entry objects so that we can + * mark the Map as dirty if an element is removed or modified. + */ + private class DirtyFlagMapEntryIterator extends DirtyFlagIterator> { + public DirtyFlagMapEntryIterator(final Iterator> iterator) { + super(iterator); + } + + @Override + public DirtyFlagMapEntry next() { + return new DirtyFlagMapEntry(super.next()); + } + } + + /** + * Wrap a Map.Entry so we can mark the Map as dirty if + * a value is set. + */ + private class DirtyFlagMapEntry implements Map.Entry { + private Map.Entry entry; + + public DirtyFlagMapEntry(final Map.Entry entry) { + this.entry = entry; + } + + public V setValue(final V o) { + dirty = true; + return entry.setValue(o); + } + + // Pure wrapper methods + public K getKey() { return entry.getKey(); } + public V getValue() { return entry.getValue(); } + public boolean equals(Object o) { return entry.equals(o); } + } +} + Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/FindbugsSuppressWarnings.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/utils/JNDIConnectionProvider.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/utils/JNDIConnectionProvider.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/utils/JNDIConnectionProvider.java 17 Aug 2012 15:10:21 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/utils/JNDIConnectionProvider.java 15 Dec 2014 10:09:51 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.utils; import java.sql.Connection; @@ -29,8 +26,8 @@ import javax.sql.DataSource; import javax.sql.XADataSource; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** *

@@ -66,6 +63,8 @@ private boolean alwaysLookup = false; + private final Logger log = LoggerFactory.getLogger(getClass()); + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -111,27 +110,25 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - Log getLog() { - return LogFactory.getLog(getClass()); + protected Logger getLog() { + return log; } private void init() { if (!isAlwaysLookup()) { Context ctx = null; try { - if (props != null) ctx = new InitialContext(props); - else - ctx = new InitialContext(); + ctx = (props != null) ? new InitialContext(props) : new InitialContext(); datasource = (DataSource) ctx.lookup(url); } catch (Exception e) { getLog().error( "Error looking up datasource: " + e.getMessage(), e); - } - finally { - if(ctx != null) + } finally { + if (ctx != null) { try { ctx.close(); } catch(Exception ignore) {} + } } } } @@ -142,34 +139,34 @@ Object ds = this.datasource; if (ds == null || isAlwaysLookup()) { - if (props != null) ctx = new InitialContext(props); - else - ctx = new InitialContext(); + ctx = (props != null) ? new InitialContext(props): new InitialContext(); ds = ctx.lookup(url); - if (!isAlwaysLookup()) this.datasource = ds; + if (!isAlwaysLookup()) { + this.datasource = ds; + } } - if (ds == null) - throw new SQLException( - "There is no object at the JNDI URL '" + url + "'"); + if (ds == null) { + throw new SQLException( "There is no object at the JNDI URL '" + url + "'"); + } - if (ds instanceof XADataSource) return (((XADataSource) ds) - .getXAConnection().getConnection()); - else if (ds instanceof DataSource) return ((DataSource) ds) - .getConnection(); - else - throw new SQLException("Object at JNDI URL '" + url - + "' is not a DataSource."); + if (ds instanceof XADataSource) { + return (((XADataSource) ds).getXAConnection().getConnection()); + } else if (ds instanceof DataSource) { + return ((DataSource) ds).getConnection(); + } else { + throw new SQLException("Object at JNDI URL '" + url + "' is not a DataSource."); + } } catch (Exception e) { this.datasource = null; throw new SQLException( "Could not retrieve datasource via JNDI url '" + url + "' " + e.getClass().getName() + ": " + e.getMessage()); - } - finally { - if(ctx != null) + } finally { + if (ctx != null) { try { ctx.close(); } catch(Exception ignore) {} + } } } @@ -188,4 +185,7 @@ // do nothing } + public void initialize() throws SQLException { + // do nothing, already initialized during constructor call + } } Index: 3rdParty_sources/quartz/org/quartz/utils/Key.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/utils/Key.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/utils/Key.java 17 Aug 2012 15:10:21 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/utils/Key.java 15 Dec 2014 10:09:51 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,20 +15,32 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.utils; +import java.io.Serializable; +import java.util.UUID; + + /** *

* Object representing a job or trigger key. *

* * @author Jeffrey Wescott */ -public class Key extends Pair { +public class Key implements Serializable, Comparable> { + + private static final long serialVersionUID = -7141167957642391350L; + /** + * The default group for scheduling entities, with the value "DEFAULT". + */ + public static final String DEFAULT_GROUP = "DEFAULT"; + + private final String name; + private final String group; + + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -46,9 +58,13 @@ * the group */ public Key(String name, String group) { - super(); - super.setFirst(name); - super.setSecond(group); + if(name == null) + throw new IllegalArgumentException("Name cannot be null."); + this.name = name; + if(group != null) + this.group = group; + else + this.group = DEFAULT_GROUP; } /* @@ -67,7 +83,7 @@ * @return the name */ public String getName() { - return (String) getFirst(); + return name; } /** @@ -78,7 +94,7 @@ * @return the group */ public String getGroup() { - return (String) getSecond(); + return group; } /** @@ -89,9 +105,64 @@ * * @return the string representation of the key */ + @Override public String toString() { return getGroup() + '.' + getName(); } -} -// EOF + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((group == null) ? 0 : group.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + @SuppressWarnings("unchecked") + Key other = (Key) obj; + if (group == null) { + if (other.group != null) + return false; + } else if (!group.equals(other.group)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + + public int compareTo(Key o) { + + if(group.equals(DEFAULT_GROUP) && !o.group.equals(DEFAULT_GROUP)) + return -1; + if(!group.equals(DEFAULT_GROUP) && o.group.equals(DEFAULT_GROUP)) + return 1; + + int r = group.compareTo(o.getGroup()); + if(r != 0) + return r; + + return name.compareTo(o.getName()); + } + + public static String createUniqueName(String group) { + if(group == null) + group = DEFAULT_GROUP; + + String n1 = UUID.randomUUID().toString(); + String n2 = UUID.nameUUIDFromBytes(group.getBytes()).toString(); + + return String.format("%s-%s", n2.substring(24), n1); + } +} Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/Pair.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/utils/PoolingConnectionProvider.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/utils/PoolingConnectionProvider.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/utils/PoolingConnectionProvider.java 17 Aug 2012 15:10:21 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/utils/PoolingConnectionProvider.java 15 Dec 2014 10:09:51 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,27 +15,26 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.utils; +import java.beans.PropertyVetoException; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; -import org.apache.commons.dbcp.BasicDataSource; +import org.quartz.SchedulerException; +import com.mchange.v2.c3p0.ComboPooledDataSource; + /** *

- * A ConnectionProvider implementation that creates it's own + * A ConnectionProvider implementation that creates its own * pool of connections. *

* *

- * This class uses DBCP - * , an Apache-Jakarta-Commons product. - *

+ * This class uses C3PO (http://www.mchange.com/projects/c3p0/index.html) as + * the underlying pool implementation.

* * @see DBConnectionManager * @see ConnectionProvider @@ -54,26 +53,58 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - public static final String DB_PROPS_PREFIX = "org.quartz.db."; - - public static final String DB_JNDI_DATASOURCE_URL = "jndiURL"; - - // The JDBC database driver + /** The JDBC database driver. */ public static final String DB_DRIVER = "driver"; - // The JDBC database URL + /** The JDBC database URL. */ public static final String DB_URL = "URL"; - // The database user name + /** The database user name. */ public static final String DB_USER = "user"; - // The database user password + /** The database user password. */ public static final String DB_PASSWORD = "password"; + /** The maximum number of database connections to have in the pool. Default is 10. */ public static final String DB_MAX_CONNECTIONS = "maxConnections"; + /** + * The maximum number of prepared statements that will be cached per connection in the pool. + * Depending upon your JDBC Driver this may significantly help performance, or may slightly + * hinder performance. + * Default is 120, as Quartz uses over 100 unique statements. 0 disables the feature. + */ + public static final String DB_MAX_CACHED_STATEMENTS_PER_CONNECTION = "maxCachedStatementsPerConnection"; + + /** + * The database sql query to execute every time a connection is returned + * to the pool to ensure that it is still valid. + */ public static final String DB_VALIDATION_QUERY = "validationQuery"; + /** + * The number of seconds between tests of idle connections - only enabled + * if the validation query property is set. Default is 50 seconds. + */ + public static final String DB_IDLE_VALIDATION_SECONDS = "idleConnectionValidationSeconds"; + + /** + * Whether the database sql query to validate connections should be executed every time + * a connection is retrieved from the pool to ensure that it is still valid. If false, + * then validation will occur on check-in. Default is false. + */ + public static final String DB_VALIDATE_ON_CHECKOUT = "validateOnCheckout"; + + /** Discard connections after they have been idle this many seconds. 0 disables the feature. Default is 0.*/ + private static final String DB_DISCARD_IDLE_CONNECTIONS_SECONDS = "discardIdleConnectionsSeconds"; + + /** Default maximum number of database connections in the pool. */ + public static final int DEFAULT_DB_MAX_CONNECTIONS = 10; + + /** Default maximum number of database connections in the pool. */ + public static final int DEFAULT_DB_MAX_CACHED_STATEMENTS_PER_CONNECTION = 120; + + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -82,7 +113,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - private BasicDataSource datasource; + private ComboPooledDataSource datasource; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -94,85 +125,133 @@ public PoolingConnectionProvider(String dbDriver, String dbURL, String dbUser, String dbPassword, int maxConnections, - String dbValidationQuery) throws SQLException { - - initialize(dbDriver, dbURL, dbUser, dbPassword, maxConnections, - dbValidationQuery); - + String dbValidationQuery) throws SQLException, SchedulerException { + initialize( + dbDriver, dbURL, dbUser, dbPassword, + maxConnections, DEFAULT_DB_MAX_CACHED_STATEMENTS_PER_CONNECTION, dbValidationQuery, false, 50, 0); } - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Interface. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - private void initialize(String dbDriver, String dbURL, String dbUser, - String dbPassword, int maxConnections, String dbValidationQuery) - throws SQLException { - if (dbDriver == null) - throw new SQLException("DB driver class name cannot be null!"); - if (dbURL == null) throw new SQLException("DB URL cannot be null!"); - if (maxConnections < 0) - throw new SQLException( - "Max connections must be greater than zero!"); - - datasource = new BasicDataSource(); - datasource.setDriverClassName(dbDriver); - datasource.setUrl(dbURL); - datasource.setUsername(dbUser); - datasource.setPassword(dbPassword); - datasource.setMaxActive(maxConnections); - if (dbValidationQuery != null) - datasource.setValidationQuery(dbValidationQuery); - } - /** - *

* Create a connection pool using the given properties. - *

* *

- * The properties passed should contain either + * The properties passed should contain: *

    - *
  • JNDI DataSource URL {@link #DB_JNDI_DATASOURCE_URL} - *
- * or - *
    *
  • {@link #DB_DRIVER}- The database driver class name *
  • {@link #DB_URL}- The database URL *
  • {@link #DB_USER}- The database user *
  • {@link #DB_PASSWORD}- The database password - *
  • {@link #DB_MAX_CONNECTIONS}- The maximum # connections in the pool + *
  • {@link #DB_MAX_CONNECTIONS}- The maximum # connections in the pool, + * optional + *
  • {@link #DB_VALIDATION_QUERY}- The sql validation query, optional *
- *

+ *

* * @param config - * configuration properties - * @exception SQLException - * if an error occurs + * configuration properties */ - public PoolingConnectionProvider(Properties config) throws SQLException { + public PoolingConnectionProvider(Properties config) throws SchedulerException, SQLException { PropertiesParser cfg = new PropertiesParser(config); - String url = config.getProperty(DB_URL); + initialize( + cfg.getStringProperty(DB_DRIVER), + cfg.getStringProperty(DB_URL), + cfg.getStringProperty(DB_USER, ""), + cfg.getStringProperty(DB_PASSWORD, ""), + cfg.getIntProperty(DB_MAX_CONNECTIONS, DEFAULT_DB_MAX_CONNECTIONS), + cfg.getIntProperty(DB_MAX_CACHED_STATEMENTS_PER_CONNECTION, DEFAULT_DB_MAX_CACHED_STATEMENTS_PER_CONNECTION), + cfg.getStringProperty(DB_VALIDATION_QUERY), + cfg.getBooleanProperty(DB_VALIDATE_ON_CHECKOUT, false), + cfg.getIntProperty(DB_IDLE_VALIDATION_SECONDS, 50), + cfg.getIntProperty(DB_DISCARD_IDLE_CONNECTIONS_SECONDS, 0)); + } + + /* + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Interface. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + + /** + * Create the underlying C3PO ComboPooledDataSource with the + * default supported properties. + * @throws SchedulerException + */ + private void initialize( + String dbDriver, + String dbURL, + String dbUser, + String dbPassword, + int maxConnections, + int maxStatementsPerConnection, + String dbValidationQuery, + boolean validateOnCheckout, + int idleValidationSeconds, + int maxIdleSeconds) throws SQLException, SchedulerException { + if (dbURL == null) { + throw new SQLException( + "DBPool could not be created: DB URL cannot be null"); + } + + if (dbDriver == null) { + throw new SQLException( + "DBPool '" + dbURL + "' could not be created: " + + "DB driver class name cannot be null!"); + } + + if (maxConnections < 0) { + throw new SQLException( + "DBPool '" + dbURL + "' could not be created: " + + "Max connections must be greater than zero!"); + } + + + datasource = new ComboPooledDataSource(); try { - initialize(config.getProperty(DB_DRIVER), url, config - .getProperty(DB_USER), config.getProperty(DB_PASSWORD), cfg - .getIntProperty(DB_MAX_CONNECTIONS, 3), cfg - .getStringProperty(DB_VALIDATION_QUERY)); - } catch (Exception e) { - throw new SQLException("DBPool '" + url - + "' could not be created: " + e.toString()); + datasource.setDriverClass(dbDriver); + } catch (PropertyVetoException e) { + throw new SchedulerException("Problem setting driver class name on datasource: " + e.getMessage(), e); + } + datasource.setJdbcUrl(dbURL); + datasource.setUser(dbUser); + datasource.setPassword(dbPassword); + datasource.setMaxPoolSize(maxConnections); + datasource.setMinPoolSize(1); + datasource.setMaxIdleTime(maxIdleSeconds); + datasource.setMaxStatementsPerConnection(maxStatementsPerConnection); + + if (dbValidationQuery != null) { + datasource.setPreferredTestQuery(dbValidationQuery); + if(!validateOnCheckout) + datasource.setTestConnectionOnCheckin(true); + else + datasource.setTestConnectionOnCheckout(true); + datasource.setIdleConnectionTestPeriod(idleValidationSeconds); } } + + /** + * Get the C3PO ComboPooledDataSource created during initialization. + * + *

+ * This can be used to set additional data source properties in a + * subclass's constructor. + *

+ */ + protected ComboPooledDataSource getDataSource() { + return datasource; + } public Connection getConnection() throws SQLException { - return this.datasource.getConnection(); + return datasource.getConnection(); } public void shutdown() throws SQLException { - this.datasource.close(); + datasource.close(); } + + public void initialize() throws SQLException { + // do nothing, already initialized during constructor call + } } Index: 3rdParty_sources/quartz/org/quartz/utils/PropertiesParser.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/utils/PropertiesParser.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/utils/PropertiesParser.java 17 Aug 2012 15:10:21 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/utils/PropertiesParser.java 15 Dec 2014 10:09:51 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,16 +15,13 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.utils; +import java.util.ArrayList; import java.util.Enumeration; -import java.util.HashMap; +import java.util.HashSet; import java.util.Properties; import java.util.StringTokenizer; -import java.util.Vector; /** *

@@ -69,18 +66,29 @@ return props; } + /** + * Get the trimmed String value of the property with the given + * name. If the value the empty String (after + * trimming), then it returns null. + */ public String getStringProperty(String name) { - String val = props.getProperty(name); - if (val == null) return null; - return val.trim(); + return getStringProperty(name, null); } + /** + * Get the trimmed String value of the property with the given + * name or the given default value if the value is + * null or empty after trimming. + */ public String getStringProperty(String name, String def) { String val = props.getProperty(name, def); - if (val == null) return def; + if (val == null) { + return def; + } + val = val.trim(); - if (val.length() == 0) return def; - return val; + + return (val.length() == 0) ? def : val; } public String[] getStringArrayProperty(String name) { @@ -89,44 +97,38 @@ public String[] getStringArrayProperty(String name, String[] def) { String vals = getStringProperty(name); - if (vals == null) return def; + if (vals == null) { + return def; + } - if (vals != null && !vals.trim().equals("")) { - StringTokenizer stok = new StringTokenizer(vals, ","); - Vector strs = new Vector(); - try { - while (stok.hasMoreTokens()) { - strs.addElement(stok.nextToken()); - } - String[] outStrs = new String[strs.size()]; - for (int i = 0; i < strs.size(); i++) - outStrs[i] = (String) strs.elementAt(i); - return outStrs; - } catch (Exception e) { - return def; + StringTokenizer stok = new StringTokenizer(vals, ","); + ArrayList strs = new ArrayList(); + try { + while (stok.hasMoreTokens()) { + strs.add(stok.nextToken().trim()); } + + return (String[])strs.toArray(new String[strs.size()]); + } catch (Exception e) { + return def; } - - return def; } public boolean getBooleanProperty(String name) { - String val = getStringProperty(name); - if (val == null) return false; - - return new Boolean(val).booleanValue(); + return getBooleanProperty(name, false); } public boolean getBooleanProperty(String name, boolean def) { String val = getStringProperty(name); - if (val == null) return def; - - return new Boolean(val).booleanValue(); + + return (val == null) ? def : Boolean.valueOf(val).booleanValue(); } public byte getByteProperty(String name) throws NumberFormatException { String val = getStringProperty(name); - if (val == null) throw new NumberFormatException(" null string"); + if (val == null) { + throw new NumberFormatException(" null string"); + } try { return Byte.parseByte(val); @@ -136,9 +138,11 @@ } public byte getByteProperty(String name, byte def) - throws NumberFormatException { + throws NumberFormatException { String val = getStringProperty(name); - if (val == null) return def; + if (val == null) { + return def; + } try { return Byte.parseByte(val); @@ -148,26 +152,19 @@ } public char getCharProperty(String name) { - String param = getStringProperty(name); - if (param == null) return '\0'; - - if (param.length() == 0) return '\0'; - - return param.charAt(0); + return getCharProperty(name, '\0'); } public char getCharProperty(String name, char def) { String param = getStringProperty(name); - if (param == null) return def; - - if (param.length() == 0) return def; - - return param.charAt(0); + return (param == null) ? def : param.charAt(0); } public double getDoubleProperty(String name) throws NumberFormatException { String val = getStringProperty(name); - if (val == null) throw new NumberFormatException(" null string"); + if (val == null) { + throw new NumberFormatException(" null string"); + } try { return Double.parseDouble(val); @@ -177,9 +174,11 @@ } public double getDoubleProperty(String name, double def) - throws NumberFormatException { + throws NumberFormatException { String val = getStringProperty(name); - if (val == null) return def; + if (val == null) { + return def; + } try { return Double.parseDouble(val); @@ -190,7 +189,9 @@ public float getFloatProperty(String name) throws NumberFormatException { String val = getStringProperty(name); - if (val == null) throw new NumberFormatException(" null string"); + if (val == null) { + throw new NumberFormatException(" null string"); + } try { return Float.parseFloat(val); @@ -200,9 +201,11 @@ } public float getFloatProperty(String name, float def) - throws NumberFormatException { + throws NumberFormatException { String val = getStringProperty(name); - if (val == null) return def; + if (val == null) { + return def; + } try { return Float.parseFloat(val); @@ -213,7 +216,9 @@ public int getIntProperty(String name) throws NumberFormatException { String val = getStringProperty(name); - if (val == null) throw new NumberFormatException(" null string"); + if (val == null) { + throw new NumberFormatException(" null string"); + } try { return Integer.parseInt(val); @@ -223,9 +228,11 @@ } public int getIntProperty(String name, int def) - throws NumberFormatException { + throws NumberFormatException { String val = getStringProperty(name); - if (val == null) return def; + if (val == null) { + return def; + } try { return Integer.parseInt(val); @@ -239,36 +246,38 @@ } public int[] getIntArrayProperty(String name, int[] def) - throws NumberFormatException { + throws NumberFormatException { String vals = getStringProperty(name); - if (vals == null) return def; + if (vals == null) { + return def; + } - if (vals != null && !vals.trim().equals("")) { - StringTokenizer stok = new StringTokenizer(vals, ","); - Vector ints = new Vector(); - try { - while (stok.hasMoreTokens()) { - try { - ints.addElement(new Integer(stok.nextToken())); - } catch (NumberFormatException nfe) { - throw new NumberFormatException(" '" + vals + "'"); - } + StringTokenizer stok = new StringTokenizer(vals, ","); + ArrayList ints = new ArrayList(); + try { + while (stok.hasMoreTokens()) { + try { + ints.add(new Integer(stok.nextToken().trim())); + } catch (NumberFormatException nfe) { + throw new NumberFormatException(" '" + vals + "'"); } - int[] outInts = new int[ints.size()]; - for (int i = 0; i < ints.size(); i++) - outInts[i] = ((Integer) ints.elementAt(i)).intValue(); - return outInts; - } catch (Exception e) { - return def; } + + int[] outInts = new int[ints.size()]; + for (int i = 0; i < ints.size(); i++) { + outInts[i] = ((Integer)ints.get(i)).intValue(); + } + return outInts; + } catch (Exception e) { + return def; } - - return def; } public long getLongProperty(String name) throws NumberFormatException { String val = getStringProperty(name); - if (val == null) throw new NumberFormatException(" null string"); + if (val == null) { + throw new NumberFormatException(" null string"); + } try { return Long.parseLong(val); @@ -278,9 +287,11 @@ } public long getLongProperty(String name, long def) - throws NumberFormatException { + throws NumberFormatException { String val = getStringProperty(name); - if (val == null) return def; + if (val == null) { + return def; + } try { return Long.parseLong(val); @@ -291,7 +302,9 @@ public short getShortProperty(String name) throws NumberFormatException { String val = getStringProperty(name); - if (val == null) throw new NumberFormatException(" null string"); + if (val == null) { + throw new NumberFormatException(" null string"); + } try { return Short.parseShort(val); @@ -301,9 +314,11 @@ } public short getShortProperty(String name, short def) - throws NumberFormatException { + throws NumberFormatException { String val = getStringProperty(name); - if (val == null) return def; + if (val == null) { + return def; + } try { return Short.parseShort(val); @@ -313,40 +328,76 @@ } public String[] getPropertyGroups(String prefix) { - Enumeration keys = props.propertyNames(); - HashMap groups = new HashMap(10); + Enumeration keys = props.propertyNames(); + HashSet groups = new HashSet(10); - if (!prefix.endsWith(".")) prefix += "."; + if (!prefix.endsWith(".")) { + prefix += "."; + } while (keys.hasMoreElements()) { String key = (String) keys.nextElement(); if (key.startsWith(prefix)) { String groupName = key.substring(prefix.length(), key.indexOf( '.', prefix.length())); - groups.put(groupName, groupName); + groups.add(groupName); } } - return (String[]) groups.values().toArray(new String[groups.size()]); + return (String[]) groups.toArray(new String[groups.size()]); } public Properties getPropertyGroup(String prefix) { - return getPropertyGroup(prefix, false); + return getPropertyGroup(prefix, false, null); } public Properties getPropertyGroup(String prefix, boolean stripPrefix) { - Enumeration keys = props.propertyNames(); + return getPropertyGroup(prefix, stripPrefix, null); + } + + /** + * Get all properties that start with the given prefix. + * + * @param prefix The prefix for which to search. If it does not end in + * a "." then one will be added to it for search purposes. + * @param stripPrefix Whether to strip off the given prefix + * in the result's keys. + * @param excludedPrefixes Optional array of fully qualified prefixes to + * exclude. For example if prefix is "a.b.c", then + * excludedPrefixes might be "a.b.c.ignore". + * + * @return Group of Properties that start with the given prefix, + * optionally have that prefix removed, and do not include properties + * that start with one of the given excluded prefixes. + */ + public Properties getPropertyGroup(String prefix, boolean stripPrefix, String[] excludedPrefixes) { + Enumeration keys = props.propertyNames(); Properties group = new Properties(); - if (!prefix.endsWith(".")) prefix += "."; + if (!prefix.endsWith(".")) { + prefix += "."; + } while (keys.hasMoreElements()) { String key = (String) keys.nextElement(); if (key.startsWith(prefix)) { - if (stripPrefix) group.put(key.substring(prefix.length()), - props.getProperty(key)); - else - group.put(key, props.getProperty(key)); + + boolean exclude = false; + if (excludedPrefixes != null) { + for (int i = 0; (i < excludedPrefixes.length) && (exclude == false); i++) { + exclude = key.startsWith(excludedPrefixes[i]); + } + } + + if (exclude == false) { + String value = getStringProperty(key, ""); + + if (stripPrefix) { + group.put(key.substring(prefix.length()), value); + } else { + group.put(key, value); + } + } } } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/StringKeyDirtyFlagMap.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/TriggerStatus.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/UpdateChecker.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/counter/Counter.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/counter/CounterConfig.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/counter/CounterImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/counter/CounterManager.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/counter/CounterManagerImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/counter/sampled/SampledCounter.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/counter/sampled/SampledCounterConfig.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/counter/sampled/SampledCounterImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/counter/sampled/SampledRateCounter.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/counter/sampled/SampledRateCounterConfig.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/counter/sampled/SampledRateCounterImpl.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/counter/sampled/TimeStampedCounterValue.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/utils/weblogic/WeblogicConnectionProvider.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/xml/CalendarBundle.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/xml/JobSchedulingBundle.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/xml/JobSchedulingDataProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/quartz/org/quartz/xml/ValidationException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/quartz/org/quartz/xml/ValidationException.java,v diff -u -r1.1 -r1.1.2.1 --- 3rdParty_sources/quartz/org/quartz/xml/ValidationException.java 17 Aug 2012 15:10:21 -0000 1.1 +++ 3rdParty_sources/quartz/org/quartz/xml/ValidationException.java 15 Dec 2014 10:09:52 -0000 1.1.2.1 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 OpenSymphony + * Copyright 2001-2009 Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -15,9 +15,6 @@ * */ -/* - * Previously Copyright (c) 2001-2004 James House - */ package org.quartz.xml; import java.util.ArrayList; @@ -26,11 +23,14 @@ import java.util.Iterator; /** - * Reports QuartzMetaDataProcessor validation exceptions. + * Reports JobSchedulingDataLoader validation exceptions. * * @author Chris Bonham */ public class ValidationException extends Exception { + + private static final long serialVersionUID = -1697832087051681357L; + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -39,7 +39,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - private Collection validationExceptions = new ArrayList(); + private Collection validationExceptions = new ArrayList(); /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -69,15 +69,32 @@ /** * Constructor for ValidationException. * - * @param validationExceptions + * @param errors * collection of validation exceptions. */ - public ValidationException(Collection errors) { + public ValidationException(Collection errors) { this(); this.validationExceptions = Collections .unmodifiableCollection(validationExceptions); + initCause(errors.iterator().next()); } + + /** + * Constructor for ValidationException. + * + * @param message + * exception message. + * @param errors + * collection of validation exceptions. + */ + public ValidationException(String message, Collection errors) { + this(message); + this.validationExceptions = Collections + .unmodifiableCollection(validationExceptions); + initCause(errors.iterator().next()); + } + /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -91,7 +108,7 @@ * * @return collection of errors. */ - public Collection getValidationExceptions() { + public Collection getValidationExceptions() { return validationExceptions; } @@ -100,16 +117,17 @@ * * @return the detail message string. */ + @Override public String getMessage() { if (getValidationExceptions().size() == 0) { return super.getMessage(); } StringBuffer sb = new StringBuffer(); boolean first = true; - for (Iterator iter = getValidationExceptions().iterator(); iter + for (Iterator iter = getValidationExceptions().iterator(); iter .hasNext(); ) { - Exception e = (Exception) iter.next(); + Exception e = iter.next(); if (!first) { sb.append('\n'); @@ -121,4 +139,6 @@ return sb.toString(); } + + } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/xml/XMLSchedulingDataProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/xml/job_scheduling_data_1_5.dtd'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/xml/job_scheduling_data_1_5.xsd'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/xml/job_scheduling_data_1_8.xsd'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/quartz/xml/job_scheduling_data_2_0.xsd'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/AbstractTerracottaJobStore.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/ClusteredJobStore.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/DefaultClusteredJobStore.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/PlainTerracottaJobStore.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/TerracottaJobStore.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/TerracottaJobStoreExtensions.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/TerracottaToolkitBuilder.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/TransactionControllingLock.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/UpdateChecker.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/collections/SerializationHelper.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/collections/SerializedToolkitStore.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/collections/TimeTrigger.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/collections/TimeTriggerSet.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/collections/ToolkitDSHolder.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/wrappers/DefaultWrapperFactory.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/wrappers/FiredTrigger.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/wrappers/JobFacade.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/wrappers/JobWrapper.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/wrappers/TriggerFacade.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/wrappers/TriggerWrapper.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/quartz/org/terracotta/quartz/wrappers/WrapperFactory.java'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_admin/src/java/org/lamsfoundation/lams/admin/web/ScheduledJobListAction.java =================================================================== RCS file: /usr/local/cvsroot/lams_admin/src/java/org/lamsfoundation/lams/admin/web/ScheduledJobListAction.java,v diff -u -r1.7 -r1.7.18.1 --- lams_admin/src/java/org/lamsfoundation/lams/admin/web/ScheduledJobListAction.java 17 Sep 2006 06:10:13 -0000 1.7 +++ lams_admin/src/java/org/lamsfoundation/lams/admin/web/ScheduledJobListAction.java 15 Dec 2014 10:09:41 -0000 1.7.18.1 @@ -25,6 +25,8 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.List; +import java.util.Set; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -36,65 +38,74 @@ import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.quartz.JobDetail; +import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.Trigger; +import org.quartz.impl.matchers.GroupMatcher; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; + /** * * @author Steve.Ni * @version $Revision$ * - * @struts:action path="/joblist" - * validate="false" + * @struts:action path="/joblist" validate="false" * * @struts:action-forward name="list" path=".joblist" */ -public class ScheduledJobListAction extends Action{ +public class ScheduledJobListAction extends Action { - private static final Logger log = Logger.getLogger(ScheduledJobListAction.class); - /** - * Get all waitting queue jobs scheduled in Quartz table and display job name, job start time and - * description. The description will be in format "Lesson Name":"the lesson creator", or - * "The gate name":"The relatived lesson name". + private static final Logger log = Logger.getLogger(ScheduledJobListAction.class); + + /** + * Get all waitting queue jobs scheduled in Quartz table and display job name, job start time and description. The + * description will be in format "Lesson Name":"the lesson creator", or "The gate name":"The relatived lesson name". * - * @param mapping The ActionMapping used to select this instance - * @param actionForm The optional ActionForm bean for this request (if any) - * @param request The HTTP request we are processing - * @param response The HTTP response we are creating + * @param mapping + * The ActionMapping used to select this instance + * @param actionForm + * The optional ActionForm bean for this request (if any) + * @param request + * The HTTP request we are processing + * @param response + * The HTTP response we are creating * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet exception occurs + * @exception IOException + * if an input/output error occurs + * @exception ServletException + * if a servlet exception occurs * */ - public ActionForward execute(ActionMapping mapping, - ActionForm form, - HttpServletRequest request, - HttpServletResponse response) throws Exception{ - - WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(this.getServlet().getServletContext()); - Scheduler scheduler = (Scheduler) ctx.getBean("scheduler"); - ArrayList jobList = new ArrayList(); - try { - String[] jobNames = scheduler.getJobNames(Scheduler.DEFAULT_GROUP); - for (String name : jobNames) { - ScheduledJobDTO jobDto = new ScheduledJobDTO(); - JobDetail detail = scheduler.getJobDetail(name,Scheduler.DEFAULT_GROUP); - jobDto.setName(name); - jobDto.setDescription(detail.getDescription()); - Trigger[] triggers = scheduler.getTriggersOfJob(name,Scheduler.DEFAULT_GROUP); - for (Trigger trigger : triggers) { - jobDto.setStartDate(trigger.getStartTime()); - jobList.add(jobDto); - } - } - } catch (SchedulerException e) { - log.equals("Failed get job names:" + e.getMessage()); + @SuppressWarnings("unchecked") + @Override + public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws Exception { + + WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(this.getServlet() + .getServletContext()); + Scheduler scheduler = (Scheduler) ctx.getBean("scheduler"); + ArrayList jobList = new ArrayList(); + try { + Set jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(Scheduler.DEFAULT_GROUP)); + for (JobKey jobKey : jobKeys) { + ScheduledJobDTO jobDto = new ScheduledJobDTO(); + JobDetail detail = scheduler.getJobDetail(jobKey); + jobDto.setName(jobKey.getName()); + jobDto.setDescription(detail.getDescription()); + List triggers = (List) scheduler.getTriggersOfJob(jobKey); + for (Trigger trigger : triggers) { + jobDto.setStartDate(trigger.getStartTime()); + jobList.add(jobDto); } - - request.setAttribute("jobList",jobList); - return mapping.findForward("list"); + } + } catch (SchedulerException e) { + ScheduledJobListAction.log.equals("Failed get job names:" + e.getMessage()); + } + + request.setAttribute("jobList", jobList); + return mapping.findForward("list"); } - + } Index: lams_build/3rdParty.userlibraries =================================================================== RCS file: /usr/local/cvsroot/lams_build/3rdParty.userlibraries,v diff -u -r1.71.2.15 -r1.71.2.16 --- lams_build/3rdParty.userlibraries 10 Nov 2014 12:07:45 -0000 1.71.2.15 +++ lams_build/3rdParty.userlibraries 15 Dec 2014 10:09:31 -0000 1.71.2.16 @@ -31,7 +31,6 @@ - @@ -43,5 +42,6 @@ + Index: lams_build/build.xml =================================================================== RCS file: /usr/local/cvsroot/lams_build/build.xml,v diff -u -r1.120.2.51 -r1.120.2.52 --- lams_build/build.xml 25 Nov 2014 20:50:25 -0000 1.120.2.51 +++ lams_build/build.xml 15 Dec 2014 10:09:31 -0000 1.120.2.52 @@ -619,7 +619,7 @@ - + - + - + \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/commonContext.xml =================================================================== RCS file: /usr/local/cvsroot/lams_common/src/java/org/lamsfoundation/lams/commonContext.xml,v diff -u -r1.100.2.12 -r1.100.2.13 --- lams_common/src/java/org/lamsfoundation/lams/commonContext.xml 8 Dec 2014 21:50:14 -0000 1.100.2.12 +++ lams_common/src/java/org/lamsfoundation/lams/commonContext.xml 15 Dec 2014 10:09:24 -0000 1.100.2.13 @@ -227,6 +227,7 @@ + org.springframework.scheduling.quartz.LocalDataSourceJobStore @@ -278,14 +279,13 @@ - + + class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean"> - Fisheye: Tag 1.1 refers to a dead (removed) revision in file `lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch02040038.sql'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_common/src/java/org/lamsfoundation/lams/util/Configuration.java =================================================================== RCS file: /usr/local/cvsroot/lams_common/src/java/org/lamsfoundation/lams/util/Configuration.java,v diff -u -r1.24.2.1 -r1.24.2.2 --- lams_common/src/java/org/lamsfoundation/lams/util/Configuration.java 27 Nov 2014 21:31:51 -0000 1.24.2.1 +++ lams_common/src/java/org/lamsfoundation/lams/util/Configuration.java 15 Dec 2014 10:09:24 -0000 1.24.2.2 @@ -39,10 +39,13 @@ import org.lamsfoundation.lams.config.dao.IConfigurationDAO; import org.lamsfoundation.lams.config.dao.IRegistrationDAO; import org.lamsfoundation.lams.usermanagement.WorkspaceFolder; +import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; -import org.quartz.SimpleTrigger; +import org.quartz.SimpleScheduleBuilder; +import org.quartz.Trigger; +import org.quartz.TriggerBuilder; import org.springframework.beans.factory.InitializingBean; /** @@ -188,18 +191,14 @@ } String refreshCacheIntervalString = Configuration.get(ConfigurationKeys.CONFIGURATION_CACHE_REFRESH_INTERVAL); - Long refreshCacheInterval = StringUtils.isBlank(refreshCacheIntervalString) ? null : Long + Integer refreshCacheInterval = StringUtils.isBlank(refreshCacheIntervalString) ? null : Integer .valueOf(refreshCacheIntervalString); if ((refreshCacheInterval != null) && (refreshCacheInterval > 0)) { - SimpleTrigger trigger = new SimpleTrigger("configurationCacheRefreshTrigger", null); - trigger.setVolatility(true); - trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY); - trigger.setRepeatInterval(Long.valueOf(refreshCacheInterval) * 60 * 1000); + JobDetail jobDetail = JobBuilder.newJob(ConfigurationRefreshCacheJob.class) + .withIdentity("configurationCacheRefresh").build(); + Trigger trigger = TriggerBuilder.newTrigger().withIdentity("configurationCacheRefreshTrigger") + .withSchedule(SimpleScheduleBuilder.repeatMinutelyForever(refreshCacheInterval)).build(); - JobDetail jobDetail = new JobDetail("configurationCacheRefresh", null, ConfigurationRefreshCacheJob.class); - // do not store in DB as the job will be recreated after LAMS restart anyway - jobDetail.setVolatility(true); - try { Configuration.scheduler.scheduleJob(jobDetail, trigger); } catch (SchedulerException e) { @@ -290,7 +289,7 @@ Configuration.setSystemProperty(ConfigurationKeys.TRUSTSTORE_PASSWORD, Configuration.get(ConfigurationKeys.TRUSTSTORE_PASSWORD)); updatePublicFolderName(); - configurationDAO.insertOrUpdateAll(Configuration.items.values()); + Configuration.configurationDAO.insertOrUpdateAll(Configuration.items.values()); } /** @@ -322,7 +321,7 @@ private void updatePublicFolderName() { // LDEV-2430 update public folder name according to default server locale WorkspaceFolder publicFolder = null; - List list = configurationDAO.findByProperty(WorkspaceFolder.class, + List list = Configuration.configurationDAO.findByProperty(WorkspaceFolder.class, "workspaceFolderType", WorkspaceFolder.PUBLIC_SEQUENCES); if ((list != null) && (list.size() > 0)) { @@ -331,7 +330,7 @@ Locale locale = new Locale(langCountry[0], langCountry[1]); publicFolder.setName(Configuration.messageService.getMessageSource().getMessage("public.folder.name", null, locale)); - configurationDAO.update(publicFolder); + Configuration.configurationDAO.update(publicFolder); } } } \ No newline at end of file Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/MonitoringConstants.java =================================================================== RCS file: /usr/local/cvsroot/lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/MonitoringConstants.java,v diff -u -r1.20.2.1 -r1.20.2.2 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/MonitoringConstants.java 2 Sep 2014 22:24:07 -0000 1.20.2.1 +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/MonitoringConstants.java 15 Dec 2014 10:09:25 -0000 1.20.2.2 @@ -36,9 +36,6 @@ public static final String KEY_USER_ID = "userID"; public static final String KEY_STAFF = "staff"; public static final String KEY_LEARNER = "learners"; - public static final String JOB_START_LESSON = "startScheduleLessonJob"; - public static final String JOB_FINISH_LESSON = "finishScheduleLessonJob"; - public static final String JOB_EMAIL_MESSAGE = "emailScheduleMessageJob"; public static final String PARAM_LESSON_START_DATE = "lessonStartDate"; public static final String PARAM_SCHEDULED_NUMBER_DAYS_TO_LESSON_FINISH = "scheduledNumberDaysToLessonFinish"; public static final String PARAM_LEARNER_ID = "learnerID"; Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/monitoringApplicationContext.xml =================================================================== RCS file: /usr/local/cvsroot/lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/monitoringApplicationContext.xml,v diff -u -r1.36.2.5 -r1.36.2.6 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/monitoringApplicationContext.xml 21 Oct 2014 10:27:47 -0000 1.36.2.5 +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/monitoringApplicationContext.xml 15 Dec 2014 10:09:25 -0000 1.36.2.6 @@ -74,32 +74,4 @@ - - - - org.lamsfoundation.lams.monitoring.quartz.job.OpenScheduleGateJob - - - - - - org.lamsfoundation.lams.monitoring.quartz.job.CloseScheduleGateJob - - - - - org.lamsfoundation.lams.monitoring.quartz.job.StartScheduleLessonJob - - - - - org.lamsfoundation.lams.monitoring.quartz.job.FinishScheduleLessonJob - - - - - org.lamsfoundation.lams.monitoring.quartz.job.EmailScheduleMessageJob - - - \ No newline at end of file Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java =================================================================== RCS file: /usr/local/cvsroot/lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java,v diff -u -r1.195.2.9 -r1.195.2.10 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java 31 Oct 2014 16:32:23 -0000 1.195.2.9 +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java 15 Dec 2014 10:09:25 -0000 1.195.2.10 @@ -83,6 +83,10 @@ import org.lamsfoundation.lams.logevent.service.ILogEventService; import org.lamsfoundation.lams.monitoring.MonitoringConstants; import org.lamsfoundation.lams.monitoring.dto.ContributeActivityDTO; +import org.lamsfoundation.lams.monitoring.quartz.job.CloseScheduleGateJob; +import org.lamsfoundation.lams.monitoring.quartz.job.FinishScheduleLessonJob; +import org.lamsfoundation.lams.monitoring.quartz.job.OpenScheduleGateJob; +import org.lamsfoundation.lams.monitoring.quartz.job.StartScheduleLessonJob; import org.lamsfoundation.lams.security.ISecurityService; import org.lamsfoundation.lams.tool.ToolSession; import org.lamsfoundation.lams.tool.exception.LamsToolServiceException; @@ -105,11 +109,13 @@ import org.lamsfoundation.lams.util.wddx.WDDXTAGS; import org.lamsfoundation.lams.web.session.SessionManager; import org.lamsfoundation.lams.web.util.AttributeNames; +import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; -import org.quartz.SimpleTrigger; import org.quartz.Trigger; +import org.quartz.TriggerBuilder; +import org.quartz.TriggerKey; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @@ -585,18 +591,20 @@ TimeZone userTimeZone = TimeZone.getTimeZone(user.getTimeZone()); Date tzStartLessonDate = DateUtil.convertFromTimeZoneToDefault(userTimeZone, startDate); - JobDetail startLessonJob = getStartScheduleLessonJob(); // setup the message for scheduling job - startLessonJob.setName("startLessonOnSchedule:" + lessonId); + JobDetail startLessonJob = JobBuilder + .newJob(StartScheduleLessonJob.class) + .withIdentity("startLessonOnSchedule:" + lessonId) + .withDescription( + requestedLesson.getLessonName() + ":" + + (requestedLesson.getUser() == null ? "" : requestedLesson.getUser().getFullName())) + .usingJobData(MonitoringConstants.KEY_LESSON_ID, new Long(lessonId)) + .usingJobData(MonitoringConstants.KEY_USER_ID, new Integer(userId)).build(); - startLessonJob.setDescription(requestedLesson.getLessonName() + ":" - + (requestedLesson.getUser() == null ? "" : requestedLesson.getUser().getFullName())); - startLessonJob.getJobDataMap().put(MonitoringConstants.KEY_LESSON_ID, new Long(lessonId)); - startLessonJob.getJobDataMap().put(MonitoringConstants.KEY_USER_ID, new Integer(userId)); - // create customized triggers - Trigger startLessonTrigger = new SimpleTrigger("startLessonOnScheduleTrigger:" + lessonId, - Scheduler.DEFAULT_GROUP, tzStartLessonDate); + Trigger startLessonTrigger = TriggerBuilder.newTrigger() + .withIdentity("startLessonOnScheduleTrigger:" + lessonId).startAt(tzStartLessonDate).build(); + // start the scheduling job try { requestedLesson.setScheduleStartDate(tzStartLessonDate); @@ -619,19 +627,17 @@ // we get the lesson want to finish Lesson requestedLesson = lessonDAO.getLesson(new Long(lessonId)); String triggerName = "finishLessonOnScheduleTrigger:" + lessonId; + Trigger finishLessonTrigger = null; + JobDetail finishLessonJob = null; boolean alreadyScheduled = false; try { - // if trigger exists, the job was already scheduled and we need to (re)move the trigger - alreadyScheduled = scheduler.getTrigger(triggerName, Scheduler.DEFAULT_GROUP) != null; + finishLessonTrigger = scheduler.getTrigger(TriggerKey.triggerKey(triggerName)); + alreadyScheduled = finishLessonTrigger != null; } catch (SchedulerException e) { - MonitoringService.log.error(e); + MonitoringService.log.error("Error while fetching Quartz trigger \"" + triggerName + "\"", e); } - Trigger finishLessonTrigger = null; - String finishLessonJobName = "finishLessonOnSchedule:" + lessonId; - JobDetail finishLessonJob = null; Date endDate = null; - if (scheduledNumberDaysToLessonFinish > 0) { // calculate finish date Date startDate = (requestedLesson.getStartDateTime() != null) ? requestedLesson.getStartDateTime() @@ -649,19 +655,23 @@ throw new IllegalArgumentException("Lesson scheduled finish date is already in the past"); } - if (!alreadyScheduled) { - finishLessonJob = getFinishScheduleLessonJob(); + if (alreadyScheduled) { + finishLessonTrigger = finishLessonTrigger.getTriggerBuilder().startAt(endDate).build(); + } else { // setup the message for scheduling job - finishLessonJob.setName(finishLessonJobName); - finishLessonJob.setDescription(requestedLesson.getLessonName() + ":" - + (requestedLesson.getUser() == null ? "" : requestedLesson.getUser().getFullName())); - finishLessonJob.getJobDataMap().put(MonitoringConstants.KEY_LESSON_ID, new Long(lessonId)); - finishLessonJob.getJobDataMap().put(MonitoringConstants.KEY_USER_ID, new Integer(userId)); - } + finishLessonJob = JobBuilder + .newJob(FinishScheduleLessonJob.class) + .withIdentity("finishLessonOnSchedule:" + lessonId) + .withDescription( + requestedLesson.getLessonName() + + ":" + + (requestedLesson.getUser() == null ? "" : requestedLesson.getUser() + .getFullName())) + .usingJobData(MonitoringConstants.KEY_LESSON_ID, new Long(lessonId)) + .usingJobData(MonitoringConstants.KEY_USER_ID, new Integer(userId)).build(); - // create customized triggers - finishLessonTrigger = new SimpleTrigger(triggerName, Scheduler.DEFAULT_GROUP, endDate); - finishLessonTrigger.setJobName(finishLessonJobName); + finishLessonTrigger = TriggerBuilder.newTrigger().withIdentity(triggerName).startAt(endDate).build(); + } } // start the scheduling job @@ -670,13 +680,13 @@ lessonDAO.updateLesson(requestedLesson); if (alreadyScheduled) { if (scheduledNumberDaysToLessonFinish > 0) { - scheduler.rescheduleJob(triggerName, Scheduler.DEFAULT_GROUP, finishLessonTrigger); + scheduler.rescheduleJob(finishLessonTrigger.getKey(), finishLessonTrigger); if (MonitoringService.log.isDebugEnabled()) { MonitoringService.log.debug("Finish lesson [" + lessonId + "] job has been rescheduled to " + endDate); } } else { - scheduler.deleteJob(finishLessonJobName, Scheduler.DEFAULT_GROUP); + scheduler.deleteJob(finishLessonTrigger.getJobKey()); if (MonitoringService.log.isDebugEnabled()) { MonitoringService.log.debug("Finish lesson [" + lessonId + "] job has been removed"); } @@ -784,26 +794,28 @@ @Override public ScheduleGateActivity runGateScheduler(ScheduleGateActivity scheduleGate, Date schedulingStartTime, String lessonName) { - if (MonitoringService.log.isDebugEnabled()) { MonitoringService.log.debug("Running scheduler for gate " + scheduleGate.getActivityId() + "..."); } - JobDetail openScheduleGateJob = getOpenScheduleGateJob(); - JobDetail closeScheduleGateJob = getCloseScheduleGateJob(); + // setup the message for scheduling job - openScheduleGateJob.setName("openGate:" + scheduleGate.getActivityId()); - openScheduleGateJob.setDescription(scheduleGate.getTitle() + ":" + lessonName); - openScheduleGateJob.getJobDataMap().put("gateId", scheduleGate.getActivityId()); - closeScheduleGateJob.setName("closeGate:" + scheduleGate.getActivityId()); - closeScheduleGateJob.getJobDataMap().put("gateId", scheduleGate.getActivityId()); - closeScheduleGateJob.setDescription(scheduleGate.getTitle() + ":" + lessonName); + JobDetail openScheduleGateJob = JobBuilder.newJob(OpenScheduleGateJob.class) + .withIdentity("openGate:" + scheduleGate.getActivityId()) + .withDescription(scheduleGate.getTitle() + ":" + lessonName) + .usingJobData("gateId", scheduleGate.getActivityId()).build(); + JobDetail closeScheduleGateJob = JobBuilder.newJob(CloseScheduleGateJob.class) + .withIdentity("closeGate:" + scheduleGate.getActivityId()) + .withDescription(scheduleGate.getTitle() + ":" + lessonName) + .usingJobData("gateId", scheduleGate.getActivityId()).build(); // create customized triggers - Trigger openGateTrigger = new SimpleTrigger("openGateTrigger:" + scheduleGate.getActivityId(), - Scheduler.DEFAULT_GROUP, scheduleGate.getGateOpenTime(schedulingStartTime)); + Trigger openGateTrigger = TriggerBuilder.newTrigger() + .withIdentity("openGateTrigger:" + scheduleGate.getActivityId()) + .startAt(scheduleGate.getGateOpenTime(schedulingStartTime)).build(); - Trigger closeGateTrigger = new SimpleTrigger("closeGateTrigger:" + scheduleGate.getActivityId(), - Scheduler.DEFAULT_GROUP, scheduleGate.getGateCloseTime(schedulingStartTime)); + Trigger closeGateTrigger = TriggerBuilder.newTrigger() + .withIdentity("closeGateTrigger:" + scheduleGate.getActivityId()) + .startAt(scheduleGate.getGateCloseTime(schedulingStartTime)).build(); // start the scheduling job try { @@ -816,8 +828,7 @@ } } catch (SchedulerException e) { - throw new MonitoringServiceException("Error occurred at " + "[runGateScheduler]- fail to start scheduling", - e); + throw new MonitoringServiceException("Error occurred at [runGateScheduler] - fail to start scheduling", e); } if (MonitoringService.log.isDebugEnabled()) { @@ -985,17 +996,14 @@ // we un-schedule the gate from the scheduler if it's of a scheduled // gate (LDEV-1271) if (gate.isScheduleGate()) { - try { - scheduler.unscheduleJob("openGateTrigger:" + gate.getActivityId(), Scheduler.DEFAULT_GROUP); + scheduler.unscheduleJob(TriggerKey.triggerKey("openGateTrigger:" + gate.getActivityId())); } catch (SchedulerException e) { MonitoringService.log.error( "Error unscheduling trigger for gate activity id:" + gate.getActivityId(), e); throw new MonitoringServiceException("Error unscheduling trigger for gate activity id:" + gate.getActivityId(), e); - } - } activityDAO.update(gate); @@ -1921,40 +1929,6 @@ } // --------------------------------------------------------------------- - // Helper Methods - scheduling - // --------------------------------------------------------------------- - - /** - * Returns the bean that defines the open schedule gate job. - */ - private JobDetail getOpenScheduleGateJob() { - return (JobDetail) applicationContext.getBean("openScheduleGateJob"); - } - - /** - * - * @return the bean that defines start lesson on schedule job. - */ - private JobDetail getStartScheduleLessonJob() { - return (JobDetail) applicationContext.getBean(MonitoringConstants.JOB_START_LESSON); - } - - /** - * - * @return the bean that defines start lesson on schedule job. - */ - private JobDetail getFinishScheduleLessonJob() { - return (JobDetail) applicationContext.getBean(MonitoringConstants.JOB_FINISH_LESSON); - } - - /** - * Returns the bean that defines the close schdule gate job. - */ - private JobDetail getCloseScheduleGateJob() { - return (JobDetail) applicationContext.getBean("closeScheduleGateJob"); - } - - // --------------------------------------------------------------------- // Preview related methods // --------------------------------------------------------------------- Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/EmailNotificationsAction.java =================================================================== RCS file: /usr/local/cvsroot/lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/EmailNotificationsAction.java,v diff -u -r1.10.2.1 -r1.10.2.2 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/EmailNotificationsAction.java 3 Nov 2014 14:11:49 -0000 1.10.2.1 +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/EmailNotificationsAction.java 15 Dec 2014 10:09:25 -0000 1.10.2.2 @@ -52,6 +52,7 @@ import org.lamsfoundation.lams.lesson.util.LessonComparator; import org.lamsfoundation.lams.monitoring.MonitoringConstants; import org.lamsfoundation.lams.monitoring.dto.EmailScheduleMessageJobDTO; +import org.lamsfoundation.lams.monitoring.quartz.job.EmailScheduleMessageJob; import org.lamsfoundation.lams.monitoring.service.IMonitoringService; import org.lamsfoundation.lams.monitoring.service.MonitoringServiceProxy; import org.lamsfoundation.lams.security.ISecurityService; @@ -65,12 +66,15 @@ import org.lamsfoundation.lams.web.action.LamsDispatchAction; import org.lamsfoundation.lams.web.session.SessionManager; import org.lamsfoundation.lams.web.util.AttributeNames; +import org.quartz.JobBuilder; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; -import org.quartz.SimpleTrigger; import org.quartz.Trigger; +import org.quartz.TriggerBuilder; +import org.quartz.TriggerKey; +import org.quartz.impl.matchers.GroupMatcher; import org.springframework.util.Assert; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; @@ -99,6 +103,8 @@ // --------------------------------------------------------------------- private static final String TRIGGER_PREFIX_NAME = "emailMessageOnScheduleTrigger:"; + private static final String JOB_PREFIX_NAME = "emailScheduleMessageJob:"; + private static IEventNotificationService eventNotificationService; private static IUserManagementService userManagementService; private static IAuditService auditService; @@ -200,11 +206,13 @@ } } - String[] triggerNames = scheduler.getTriggerNames(Scheduler.DEFAULT_GROUP); - for (String triggerName : triggerNames) { + Set triggerKeys = scheduler + .getTriggerKeys(GroupMatcher.triggerGroupEquals(Scheduler.DEFAULT_GROUP)); + for (TriggerKey triggerKey : triggerKeys) { + String triggerName = triggerKey.getName(); if (triggerName.startsWith(EmailNotificationsAction.TRIGGER_PREFIX_NAME)) { - Trigger trigger = scheduler.getTrigger(triggerName, Scheduler.DEFAULT_GROUP); - JobDetail jobDetail = scheduler.getJobDetail(trigger.getJobName(), Scheduler.DEFAULT_GROUP); + Trigger trigger = scheduler.getTrigger(triggerKey); + JobDetail jobDetail = scheduler.getJobDetail(trigger.getJobKey()); JobDataMap jobDataMap = jobDetail.getJobDataMap(); // filter triggers @@ -258,10 +266,12 @@ for (String userIdStr : userIdStrs) { int userId = Integer.parseInt(userIdStr); boolean isHtmlFormat = false; - isSuccessfullySent &= getEventNotificationService().sendMessage(null, userId, - IEventNotificationService.DELIVERY_METHOD_MAIL, monitoringService.getMessageService() - .getMessage("event.emailnotifications.email.subject", new Object[] {}), emailBody, - isHtmlFormat); + isSuccessfullySent &= getEventNotificationService().sendMessage( + null, + userId, + IEventNotificationService.DELIVERY_METHOD_MAIL, + monitoringService.getMessageService().getMessage("event.emailnotifications.email.subject", + new Object[] {}), emailBody, isHtmlFormat); } JSONObject.put("isSuccessfullySent", isSuccessfullySent); @@ -276,16 +286,17 @@ TimeZone teacherTimeZone = teacher.getTimeZone(); Date scheduleDate = DateUtil.convertFromTimeZoneToDefault(teacherTimeZone, scheduleDateTeacherTimezone); - JobDetail emailScheduleMessageJob = getEmailScheduleMessageJob(); - emailScheduleMessageJob.setName("emailScheduleMessageJob:" + now.getTimeInMillis()); - emailScheduleMessageJob.setDescription("schedule email message to user(s)"); - emailScheduleMessageJob.getJobDataMap().put("emailBody", emailBody); - + // build job detail based on the bean class + JobDetail emailScheduleMessageJob = JobBuilder.newJob(EmailScheduleMessageJob.class) + .withIdentity(EmailNotificationsAction.JOB_PREFIX_NAME + now.getTimeInMillis()) + .withDescription("schedule email message to user(s)").usingJobData("emailBody", emailBody) + .build(); copySearchParametersFromRequestToMap(request, emailScheduleMessageJob.getJobDataMap()); // create customized triggers - Trigger startLessonTrigger = new SimpleTrigger(EmailNotificationsAction.TRIGGER_PREFIX_NAME - + now.getTimeInMillis(), Scheduler.DEFAULT_GROUP, scheduleDate); + Trigger startLessonTrigger = TriggerBuilder.newTrigger() + .withIdentity(EmailNotificationsAction.TRIGGER_PREFIX_NAME + now.getTimeInMillis()) + .startAt(scheduleDate).build(); // start the scheduling job Scheduler scheduler = getScheduler(); scheduler.scheduleJob(emailScheduleMessageJob, startLessonTrigger); @@ -326,7 +337,7 @@ return null; } } - + IMonitoringService monitoringService = MonitoringServiceProxy.getMonitoringService(getServlet() .getServletContext()); ICoreLearnerService learnerService = MonitoringServiceProxy.getLearnerService(getServlet().getServletContext()); @@ -472,16 +483,6 @@ /** * - * @return the bean that defines emailScheduleMessageJob. - */ - private JobDetail getEmailScheduleMessageJob() { - WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServlet() - .getServletContext()); - return (JobDetail) ctx.getBean(MonitoringConstants.JOB_EMAIL_MESSAGE); - } - - /** - * * @return the bean that defines Scheduler. */ private Scheduler getScheduler() {