spring注解配置quartz应用

原文地址:https://www.cnblogs.com/jedjia/p/quartz.html

项目中会经常用到定时器,因此,其quartz的使用,我们必须要掌握。下面就以例子来讲解如何在spring中整合quartz,

使用注解配置的方式来实现定时执行任务。

一、引入jar包

项目中需引入quartz的jar包,由于整合到spring中,肯定也引入了spring的相关jar包。

例子中引用的是quartz-2.1.1版本,使用maven管理项目,pom文件需引入quartz依赖

二、spring配置文件中配置 (applicationContext.xml)

1)      xmlns和 xsi:schemaLocation配置

xmlns:task="http://www.springframework.org/schema/task"

xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd "

2)task任务扫描注解   

  <!-- 加载定时任务 -->
  <task:annotation-driven/>

3)扫描的位置

       <!-- 自动扫描 -->

<context:component-scan base-package="com.hik.quartz"/>

4)写任务实现类及配置任务定时执行方式

使用spring注解配置quartz,非常方便实用。

下面给出配置spring配置文件配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns:p="http://www.springframework.org/schema/p"  xmlns:aop="http://www.springframework.org/schema/aop"   xmlns:context="http://www.springframework.org/schema/context"  xmlns:jee="http://www.springframework.org/schema/jee"  xmlns:tx="http://www.springframework.org/schema/tx"  xmlns:task="http://www.springframework.org/schema/task"xsi:schemaLocation="    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd  http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsdhttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd ">    <!-- 自动扫描 --><context:component-scan base-package="com.hik.service" /><context:component-scan base-package="com.hik.quartz"/><!-- 加载定时任务 --><task:annotation-driven/><!-- 配置数据源 --><bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/db_crm"/><property name="username" value="root"/><property name="password" value="passwd"/></bean><!-- 配置mybatis的sqlSessionFactory --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource" /><!-- 自动扫描mappers.xml文件 --><property name="mapperLocations" value="classpath:com/hik/mappers/*.xml"></property><!-- mybatis配置文件 --><property name="configLocation" value="classpath:mybatis-config.xml"></property></bean><!-- DAO接口所在包名,Spring会自动查找其下的类 --><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.hik.dao" /><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property></bean><!-- (事务管理)transaction manager, use JtaTransactionManager for global tx --><bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean><!-- 配置事务通知属性 -->  <tx:advice id="txAdvice" transaction-manager="transactionManager">  <!-- 定义事务传播属性 -->  <tx:attributes>  <tx:method name="insert*" propagation="REQUIRED" />  <tx:method name="update*" propagation="REQUIRED" />  <tx:method name="edit*" propagation="REQUIRED" />  <tx:method name="save*" propagation="REQUIRED" />  <tx:method name="add*" propagation="REQUIRED" />  <tx:method name="new*" propagation="REQUIRED" />  <tx:method name="set*" propagation="REQUIRED" />  <tx:method name="remove*" propagation="REQUIRED" />  <tx:method name="delete*" propagation="REQUIRED" />  <tx:method name="change*" propagation="REQUIRED" />  <tx:method name="check*" propagation="REQUIRED" />  <tx:method name="get*" propagation="REQUIRED" read-only="true" />  <tx:method name="find*" propagation="REQUIRED" read-only="true" />  <tx:method name="load*" propagation="REQUIRED" read-only="true" />  <tx:method name="*" propagation="REQUIRED" read-only="true" />  </tx:attributes>  </tx:advice>  <!-- 配置事务切面 -->  <aop:config>  <aop:pointcut id="serviceOperation"  expression="execution(* com.hik.service.*.*(..))" />  <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />  </aop:config>  </beans>

同时给出quartz的CronExpression类的源码,可以知道并理解怎样去配置自己想要的定时执行任务方式

/** 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;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.SortedSet;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.TreeSet;/*** Provides a parser and evaluator for unix-like cron expressions. Cron * expressions provide the ability to specify complex time combinations such as* &quot;At 8:00am every Monday through Friday&quot; or &quot;At 1:30am every * last Friday of the month&quot;. * <P>* Cron expressions are comprised of 6 required fields and one optional field* separated by white space. The fields respectively are described as follows:* * <table cellspacing="8">* <tr>* <th align="left">Field Name</th>* <th align="left">&nbsp;</th>* <th align="left">Allowed Values</th>* <th align="left">&nbsp;</th>* <th align="left">Allowed Special Characters</th>* </tr>* <tr>* <td align="left"><code>Seconds</code></td>* <td align="left">&nbsp;</th>* <td align="left"><code>0-59</code></td>* <td align="left">&nbsp;</th>* <td align="left"><code>, - * /</code></td>* </tr>* <tr>* <td align="left"><code>Minutes</code></td>* <td align="left">&nbsp;</th>* <td align="left"><code>0-59</code></td>* <td align="left">&nbsp;</th>* <td align="left"><code>, - * /</code></td>* </tr>* <tr>* <td align="left"><code>Hours</code></td>* <td align="left">&nbsp;</th>* <td align="left"><code>0-23</code></td>* <td align="left">&nbsp;</th>* <td align="left"><code>, - * /</code></td>* </tr>* <tr>* <td align="left"><code>Day-of-month</code></td>* <td align="left">&nbsp;</th>* <td align="left"><code>1-31</code></td>* <td align="left">&nbsp;</th>* <td align="left"><code>, - * ? / L W</code></td>* </tr>* <tr>* <td align="left"><code>Month</code></td>* <td align="left">&nbsp;</th>* <td align="left"><code>1-12 or JAN-DEC</code></td>* <td align="left">&nbsp;</th>* <td align="left"><code>, - * /</code></td>* </tr>* <tr>* <td align="left"><code>Day-of-Week</code></td>* <td align="left">&nbsp;</th>* <td align="left"><code>1-7 or SUN-SAT</code></td>* <td align="left">&nbsp;</th>* <td align="left"><code>, - * ? / L #</code></td>* </tr>* <tr>* <td align="left"><code>Year (Optional)</code></td>* <td align="left">&nbsp;</th>* <td align="left"><code>empty, 1970-2199</code></td>* <td align="left">&nbsp;</th>* <td align="left"><code>, - * /</code></td>* </tr>* </table>* <P>* The '*' character is used to specify all values. For example, &quot;*&quot; * in the minute field means &quot;every minute&quot;.* <P>* 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 fields, but not the other.* <P>* The '-' character is used to specify ranges For example &quot;10-12&quot; in* the hour field means &quot;the hours 10, 11 and 12&quot;.* <P>* The ',' character is used to specify additional values. For example* &quot;MON,WED,FRI&quot; in the day-of-week field means &quot;the days Monday,* Wednesday, and Friday&quot;.* <P>* The '/' character is used to specify increments. For example &quot;0/15&quot;* in the seconds field means &quot;the seconds 0, 15, 30, and 45&quot;. And * &quot;5/15&quot; in the seconds field means &quot;the seconds 5, 20, 35, and* 50&quot;.  Specifying '*' before the  '/' is equivalent to specifying 0 is* the value to start with. Essentially, for each field in the expression, there* is a set of numbers that can be turned on or off. For seconds and minutes, * the numbers range from 0 to 59. For hours 0 to 23, for days of the month 0 to* 31, and for months 1 to 12. The &quot;/&quot; character simply helps you turn* on every &quot;nth&quot; value in the given set. Thus &quot;7/6&quot; in the* month field only turns on month &quot;7&quot;, it does NOT mean every 6th * month, please note that subtlety.  * <P>* The 'L' character is allowed for the day-of-month and day-of-week fields.* This character is short-hand for &quot;last&quot;, but it has different * meaning in each of the two fields. For example, the value &quot;L&quot; in * the day-of-month field means &quot;the last day of the month&quot; - day 31 * for January, day 28 for February on non-leap years. If used in the * day-of-week field by itself, it simply means &quot;7&quot; or * &quot;SAT&quot;. But if used in the day-of-week field after another value, it* means &quot;the last xxx day of the month&quot; - for example &quot;6L&quot;* means &quot;the last friday of the month&quot;. 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. <i>When using the 'L' option, it is important not to * specify lists, or ranges of values, as you'll get confusing/unexpected results.</i>* <P>* 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 * example, if you were to specify &quot;15W&quot; as the value for the * day-of-month field, the meaning is: &quot;the nearest weekday to the 15th of* the month&quot;. So if the 15th is a Saturday, the trigger will fire on * Friday the 14th. If the 15th is a Sunday, the trigger will fire on Monday the* 16th. If the 15th is a Tuesday, then it will fire on Tuesday the 15th. * However if you specify &quot;1W&quot; as the value for day-of-month, and the* 1st is a Saturday, the trigger will fire on Monday the 3rd, as it will not * 'jump' over the boundary of a month's days.  The 'W' character can only be * specified when the day-of-month is a single day, not a range or list of days.* <P>* The 'L' and 'W' characters can also be combined for the day-of-month * expression to yield 'LW', which translates to &quot;last weekday of the * month&quot;.* <P>* The '#' character is allowed for the day-of-week field. This character is* used to specify &quot;the nth&quot; XXX day of the month. For example, the * value of &quot;6#3&quot; in the day-of-week field means the third Friday of * the month (day 6 = Friday and &quot;#3&quot; = the 3rd one in the month). * Other examples: &quot;2#1&quot; = the first Monday of the month and * &quot;4#5&quot; = the fifth Wednesday of the month. Note that if you specify* &quot;#5&quot; and there is not 5 of the given day-of-week in the month, then* no firing will occur that month.  If the '#' character is used, there can* only be one expression in the day-of-week field (&quot;3#1,6#3&quot; is * not valid, since there are two expressions).* <P>* <!--The 'C' character is allowed for the day-of-month and day-of-week fields.* This character is short-hand for "calendar". This means values are* calculated against the associated calendar, if any. If no calendar is* associated, then it is equivalent to having an all-inclusive calendar. A* value of "5C" in the day-of-month field means "the first day included by the* calendar on or after the 5th". A value of "1C" in the day-of-week field* means "the first day included by the calendar on or after Sunday".-->* <P>* The legal characters and the names of months and days of the week are not* case sensitive.* * <p>* <b>NOTES:</b>* <ul>* <li>Support for specifying both a day-of-week and a day-of-month value is* not complete (you'll need to use the '?' character in one of these fields).* </li>* <li>Overflowing ranges is supported - that is, having a larger number on * the left hand side than the right. You might do 22-2 to catch 10 o'clock * at night until 2 o'clock in the morning, or you might have NOV-FEB. It is * very important to note that overuse of overflowing ranges creates ranges * that don't make sense and no effort has been made to determine which * interpretation CronExpression chooses. An example would be * "0 0 14-6 ? * FRI-MON". </li>* </ul>* </p>* * * @author Sharada Jambula, James House* @author Contributions from Mads Henderson* @author Refactoring from CronTrigger to CronExpression by Aaron Craven*/
public final class CronExpression implements Serializable, Cloneable {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;protected static final int MONTH = 4;protected static final int DAY_OF_WEEK = 5;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 = ALL_SPEC_INT;protected static final Integer NO_SPEC = NO_SPEC_INT;protected static final Map<String, Integer> monthMap = new HashMap<String, Integer>(20);protected static final Map<String, Integer> dayMap = new HashMap<String, Integer>(60);static {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", 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 final String cronExpression;private TimeZone timeZone = null;protected transient TreeSet<Integer> seconds;protected transient TreeSet<Integer> minutes;protected transient TreeSet<Integer> hours;protected transient TreeSet<Integer> daysOfMonth;protected transient TreeSet<Integer> months;protected transient TreeSet<Integer> daysOfWeek;protected transient TreeSet<Integer> years;protected transient boolean lastdayOfWeek = false;protected transient int nthdayOfWeek = 0;protected transient boolean lastdayOfMonth = false;protected transient boolean nearestWeekday = 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 <CODE>CronExpression</CODE> 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 *         <CODE>CronExpression</CODE>*/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);}/*** 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 <I>after</I> 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 <I>after</I> the given date/time which does* <I>not</I> 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 accurateCalendar 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 <code>CronExpression</code> * will be resolved.*/public TimeZone getTimeZone() {if (timeZone == null) {timeZone = TimeZone.getDefault();}return timeZone;}/*** Sets the time zone for which  this <code>CronExpression</code> * will be resolved.*/public void setTimeZone(TimeZone timeZone) {this.timeZone = timeZone;}/*** Returns the string representation of the <CODE>CronExpression</CODE>* * @return a string representation of the <CODE>CronExpression</CODE>*/@Overridepublic 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//protected void buildExpression(String expression) throws ParseException {expressionParsed = true;try {if (seconds == null) {seconds = new TreeSet<Integer>();}if (minutes == null) {minutes = new TreeSet<Integer>();}if (hours == null) {hours = new TreeSet<Integer>();}if (daysOfMonth == null) {daysOfMonth = new TreeSet<Integer>();}if (months == null) {months = new TreeSet<Integer>();}if (daysOfWeek == null) {daysOfWeek = new TreeSet<Integer>();}if (years == null) {years = new TreeSet<Integer>();}int exprOn = SECOND;StringTokenizer exprsTok = new StringTokenizer(expression, " \t",false);while (exprsTok.hasMoreTokens() && exprOn <= YEAR) {String expr = exprsTok.nextToken().trim();// throw an exception if L is used with other days of the monthif(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 weekif(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();storeExpressionVals(0, v, exprOn);}exprOn++;}if (exprOn <= DAY_OF_WEEK) {throw new ParseException("Unexpected end of expression.",expression.length());}if (exprOn <= YEAR) {storeExpressionVals(0, "*", YEAR);}TreeSet<Integer> dow = getSet(DAY_OF_WEEK);TreeSet<Integer> dom = getSet(DAY_OF_MONTH);// Copying the logic from the UnsupportedOperationException belowboolean 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) {throw new ParseException("Illegal cron expression format ("+ e.toString() + ")", 0);}}protected int storeExpressionVals(int pos, String s, int type)throws ParseException {int incr = 0;int i = skipWhiteSpace(pos, s);if (i >= s.length()) {return i;}char c = s.charAt(i);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 (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);}}}} else if (type == DAY_OF_WEEK) {sval = getDayOfWeekNumber(sub);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) {throw new ParseException("Invalid Day-of-Week value: '" + sub+ "'", i);}} else if (c == '#') {try {i += 4;nthdayOfWeek = Integer.parseInt(s.substring(i));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);}} else if (c == 'L') {lastdayOfWeek = true;i++;}}} else {throw new ParseException("Illegal characters for this position: '" + sub + "'",i);}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 '?': "+ s.charAt(i), i);}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 = 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);return i;}if (c == '*' || c == '/') {if (c == '*' && (i + 1) >= s.length()) {addToSet(ALL_SPEC_INT, -1, incr, type);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++;}c = s.charAt(i);if (c == '/') { // is an increment specified?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 {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 && s.length() > i) {c = s.charAt(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 {c = s.charAt(i);if (c >= '0' && c <= '9') {ValueSet vs = getValue(val, s, i);val = vs.value;i = vs.pos;}i = checkNext(i, s, val, type);return i;}} else {throw new ParseException("Unexpected character: " + c, i);}return i;}protected int checkNext(int pos, String s, int val, int type)throws ParseException {int end = -1;int i = pos;if (i >= s.length()) {addToSet(val, end, -1, type);return i;}char c = s.charAt(pos);if (c == 'L') {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<Integer> 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);}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<Integer> 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);}i++;try {nthdayOfWeek = Integer.parseInt(s.substring(i));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<Integer> set = getSet(type);set.add(val);i++;return i;}if (c == '-') {i++;c = s.charAt(i);int v = Integer.parseInt(String.valueOf(c));end = v;i++;if (i >= s.length()) {addToSet(val, end, 1, type);return i;}c = s.charAt(i);if (c >= '0' && c <= '9') {ValueSet vs = getValue(v, s, i);end = vs.value;i = vs.pos;}if (i < s.length() && ((c = s.charAt(i)) == '/')) {i++;c = s.charAt(i);int v2 = Integer.parseInt(String.valueOf(c));i++;if (i >= s.length()) {addToSet(val, end, v2, type);return i;}c = s.charAt(i);if (c >= '0' && c <= '9') {ValueSet vs = getValue(v2, s, i);int v3 = vs.value;addToSet(val, end, v3, type);i = vs.pos;return i;} else {addToSet(val, end, v2, type);return i;}} else {addToSet(val, end, 1, type);return i;}}if (c == '/') {i++;c = s.charAt(i);int v2 = Integer.parseInt(String.valueOf(c));i++;if (i >= s.length()) {addToSet(val, end, v2, type);return i;}c = s.charAt(i);if (c >= '0' && c <= '9') {ValueSet vs = getValue(v2, s, i);int v3 = vs.value;addToSet(val, end, v3, type);i = vs.pos;return i;} else {throw new ParseException("Unexpected character '" + c + "' after '/'", i);}}addToSet(val, end, 0, type);i++;return i;}public String getCronExpression() {return cronExpression;}public String getExpressionSummary() {StringBuilder buf = new StringBuilder();buf.append("seconds: ");buf.append(getExpressionSetSummary(seconds));buf.append("\n");buf.append("minutes: ");buf.append(getExpressionSetSummary(minutes));buf.append("\n");buf.append("hours: ");buf.append(getExpressionSetSummary(hours));buf.append("\n");buf.append("daysOfMonth: ");buf.append(getExpressionSetSummary(daysOfMonth));buf.append("\n");buf.append("months: ");buf.append(getExpressionSetSummary(months));buf.append("\n");buf.append("daysOfWeek: ");buf.append(getExpressionSetSummary(daysOfWeek));buf.append("\n");buf.append("lastdayOfWeek: ");buf.append(lastdayOfWeek);buf.append("\n");buf.append("nearestWeekday: ");buf.append(nearestWeekday);buf.append("\n");buf.append("NthDayOfWeek: ");buf.append(nthdayOfWeek);buf.append("\n");buf.append("lastdayOfMonth: ");buf.append(lastdayOfMonth);buf.append("\n");buf.append("years: ");buf.append(getExpressionSetSummary(years));buf.append("\n");return buf.toString();}protected String getExpressionSetSummary(java.util.Set<Integer> set) {if (set.contains(NO_SPEC)) {return "?";}if (set.contains(ALL_SPEC)) {return "*";}StringBuilder buf = new StringBuilder();Iterator<Integer> itr = set.iterator();boolean first = true;while (itr.hasNext()) {Integer iVal = itr.next();String val = iVal.toString();if (!first) {buf.append(",");}buf.append(val);first = false;}return buf.toString();}protected String getExpressionSetSummary(java.util.ArrayList<Integer> list) {if (list.contains(NO_SPEC)) {return "?";}if (list.contains(ALL_SPEC)) {return "*";}StringBuilder buf = new StringBuilder();Iterator<Integer> itr = list.iterator();boolean first = true;while (itr.hasNext()) {Integer iVal = itr.next();String val = iVal.toString();if (!first) {buf.append(",");}buf.append(val);first = false;}return buf.toString();}protected int skipWhiteSpace(int i, String s) {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++) {;}return i;}protected void addToSet(int val, int end, int incr, int type)throws ParseException {TreeSet<Integer> 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);}} 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);}} 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);}} 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);}} 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);}}if ((incr == 0 || incr == -1) && val != ALL_SPEC_INT) {if (val != -1) {set.add(val);} else {set.add(NO_SPEC);}return;}int startAt = val;int stopAt = end;if (val == ALL_SPEC_INT && incr <= 0) {incr = 1;set.add(ALL_SPEC); // put in a marker, but also fill values}if (type == SECOND || type == MINUTE) {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;}} else if (type == DAY_OF_MONTH) {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;}} else if (type == DAY_OF_WEEK) {if (stopAt == -1) {stopAt = 7;}if (startAt == -1 || startAt == ALL_SPEC_INT) {startAt = 1;}} else if (type == YEAR) {if (stopAt == -1) {stopAt = MAX_YEAR;}if (startAt == -1 || startAt == ALL_SPEC_INT) {startAt = 1970;}}// 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 overset.add(i);} else {// take the modulus to get the real valueint i2 = i % max;// 1-indexed ranges should not include 0, and should include their maxif (i2 == 0 && (type == MONTH || type == DAY_OF_WEEK || type == DAY_OF_MONTH) ) {i2 = max;}set.add(i2);}}}TreeSet<Integer> 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;}}protected ValueSet getValue(int v, String s, int i) {char c = s.charAt(i);StringBuilder s1 = new StringBuilder(String.valueOf(v));while (c >= '0' && c <= '9') {s1.append(c);i++;if (i >= s.length()) {break;}c = s.charAt(i);}ValueSet val = new ValueSet();val.pos = (i < s.length()) ? i : i + 1;val.value = Integer.parseInt(s1.toString());return val;}protected int getNumericValue(String s, int i) {int endOfVal = findNextWhiteSpace(i, s);String val = s.substring(i, endOfVal);return Integer.parseInt(val);}protected int getMonthNumber(String s) {Integer integer = monthMap.get(s);if (integer == null) {return -1;}return integer;}protected int getDayOfWeekNumber(String s) {Integer integer = dayMap.get(s);if (integer == null) {return -1;}return integer;}//// Computation Functions//public Date getTimeAfter(Date afterTime) {// 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 timeafterTime = new Date(afterTime.getTime() + 1000);// CronTrigger does not deal with millisecondscl.setTime(afterTime);cl.set(Calendar.MILLISECOND, 0);boolean gotOne = false;// loop until we've computed the next time, or we've past the endTimewhile (!gotOne) {//if (endTime != null && cl.getTime().after(endTime)) return null;if(cl.get(Calendar.YEAR) > 2999) { // prevent endless loop...return null;}SortedSet<Integer> st = null;int t = 0;int sec = cl.get(Calendar.SECOND);int min = cl.get(Calendar.MINUTE);// get second.................................................st = seconds.tailSet(sec);if (st != null && st.size() != 0) {sec = st.first();} else {sec = seconds.first();min++;cl.set(Calendar.MINUTE, min);}cl.set(Calendar.SECOND, sec);min = cl.get(Calendar.MINUTE);int hr = cl.get(Calendar.HOUR_OF_DAY);t = -1;// get minute.................................................st = minutes.tailSet(min);if (st != null && st.size() != 0) {t = min;min = st.first();} else {min = minutes.first();hr++;}if (min != t) {cl.set(Calendar.SECOND, 0);cl.set(Calendar.MINUTE, min);setCalendarHour(cl, hr);continue;}cl.set(Calendar.MINUTE, min);hr = cl.get(Calendar.HOUR_OF_DAY);int day = cl.get(Calendar.DAY_OF_MONTH);t = -1;// get hour...................................................st = hours.tailSet(hr);if (st != null && st.size() != 0) {t = hr;hr = st.first();} else {hr = hours.first();day++;}if (hr != t) {cl.set(Calendar.SECOND, 0);cl.set(Calendar.MINUTE, 0);cl.set(Calendar.DAY_OF_MONTH, day);setCalendarHour(cl, hr);continue;}cl.set(Calendar.HOUR_OF_DAY, hr);day = cl.get(Calendar.DAY_OF_MONTH);int mon = cl.get(Calendar.MONTH) + 1;// '+ 1' because calendar is 0-based for this field, and we are// 1-basedt = -1;int tmon = mon;// get day...................................................boolean dayOfMSpec = !daysOfMonth.contains(NO_SPEC);boolean dayOfWSpec = !daysOfWeek.contains(NO_SPEC);if (dayOfMSpec && !dayOfWSpec) { // get day by day of month rulest = daysOfMonth.tailSet(day);if (lastdayOfMonth) {if(!nearestWeekday) {t = day;day = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));day -= lastdayOffset;if(t > day) {mon++;if(mon > 12) { mon = 1;tmon = 3333; // ensure test of mon != tmon further below failscl.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(getTimeZone());tcal.set(Calendar.SECOND, 0);tcal.set(Calendar.MINUTE, 0);tcal.set(Calendar.HOUR_OF_DAY, 0);tcal.set(Calendar.DAY_OF_MONTH, day);tcal.set(Calendar.MONTH, mon - 1);tcal.set(Calendar.YEAR, cl.get(Calendar.YEAR));int ldom = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));int dow = tcal.get(Calendar.DAY_OF_WEEK);if(dow == Calendar.SATURDAY && day == 1) {day += 2;} else if(dow == Calendar.SATURDAY) {day -= 1;} else if(dow == Calendar.SUNDAY && day == ldom) { day -= 2;} else if(dow == Calendar.SUNDAY) { day += 1;}tcal.set(Calendar.SECOND, sec);tcal.set(Calendar.MINUTE, min);tcal.set(Calendar.HOUR_OF_DAY, hr);tcal.set(Calendar.DAY_OF_MONTH, day);tcal.set(Calendar.MONTH, mon - 1);Date nTime = tcal.getTime();if(nTime.before(afterTime)) {day = 1;mon++;}}} else if(nearestWeekday) {t = day;day = daysOfMonth.first();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);tcal.set(Calendar.DAY_OF_MONTH, day);tcal.set(Calendar.MONTH, mon - 1);tcal.set(Calendar.YEAR, cl.get(Calendar.YEAR));int ldom = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));int dow = tcal.get(Calendar.DAY_OF_WEEK);if(dow == Calendar.SATURDAY && day == 1) {day += 2;} else if(dow == Calendar.SATURDAY) {day -= 1;} else if(dow == Calendar.SUNDAY && day == ldom) { day -= 2;} else if(dow == Calendar.SUNDAY) { day += 1;}tcal.set(Calendar.SECOND, sec);tcal.set(Calendar.MINUTE, min);tcal.set(Calendar.HOUR_OF_DAY, hr);tcal.set(Calendar.DAY_OF_MONTH, day);tcal.set(Calendar.MONTH, mon - 1);Date nTime = tcal.getTime();if(nTime.before(afterTime)) {day = daysOfMonth.first();mon++;}} else if (st != null && st.size() != 0) {t = day;day = st.first();// make sure we don't over-run a short month, such as februaryint lastDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));if (day > lastDay) {day = daysOfMonth.first();mon++;}} else {day = daysOfMonth.first();mon++;}if (day != t || mon != tmon) {cl.set(Calendar.SECOND, 0);cl.set(Calendar.MINUTE, 0);cl.set(Calendar.HOUR_OF_DAY, 0);cl.set(Calendar.DAY_OF_MONTH, day);cl.set(Calendar.MONTH, mon - 1);// '- 1' because calendar is 0-based for this field, and we// are 1-basedcontinue;}} else if (dayOfWSpec && !dayOfMSpec) { // get day by day of week ruleif (lastdayOfWeek) { // are we looking for the last XXX day of// the month?int dow = daysOfWeek.first(); // desired// d-o-wint cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-wint daysToAdd = 0;if (cDow < dow) {daysToAdd = dow - cDow;}if (cDow > dow) {daysToAdd = dow + (7 - cDow);}int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));if (day + daysToAdd > lDay) { // did we already miss the// last one?cl.set(Calendar.SECOND, 0);cl.set(Calendar.MINUTE, 0);cl.set(Calendar.HOUR_OF_DAY, 0);cl.set(Calendar.DAY_OF_MONTH, 1);cl.set(Calendar.MONTH, mon);// no '- 1' here because we are promoting the monthcontinue;}// find date of last occurrence of this day in this month...while ((day + daysToAdd + 7) <= lDay) {daysToAdd += 7;}day += daysToAdd;if (daysToAdd > 0) {cl.set(Calendar.SECOND, 0);cl.set(Calendar.MINUTE, 0);cl.set(Calendar.HOUR_OF_DAY, 0);cl.set(Calendar.DAY_OF_MONTH, day);cl.set(Calendar.MONTH, mon - 1);// '- 1' here because we are not promoting the monthcontinue;}} else if (nthdayOfWeek != 0) {// are we looking for the Nth XXX day in the month?int dow = daysOfWeek.first(); // desired// d-o-wint cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-wint daysToAdd = 0;if (cDow < dow) {daysToAdd = dow - cDow;} else if (cDow > dow) {daysToAdd = dow + (7 - cDow);}boolean dayShifted = false;if (daysToAdd > 0) {dayShifted = true;}day += daysToAdd;int weekOfMonth = day / 7;if (day % 7 > 0) {weekOfMonth++;}daysToAdd = (nthdayOfWeek - weekOfMonth) * 7;day += daysToAdd;if (daysToAdd < 0|| day > getLastDayOfMonth(mon, cl.get(Calendar.YEAR))) {cl.set(Calendar.SECOND, 0);cl.set(Calendar.MINUTE, 0);cl.set(Calendar.HOUR_OF_DAY, 0);cl.set(Calendar.DAY_OF_MONTH, 1);cl.set(Calendar.MONTH, mon);// no '- 1' here because we are promoting the monthcontinue;} else if (daysToAdd > 0 || dayShifted) {cl.set(Calendar.SECOND, 0);cl.set(Calendar.MINUTE, 0);cl.set(Calendar.HOUR_OF_DAY, 0);cl.set(Calendar.DAY_OF_MONTH, day);cl.set(Calendar.MONTH, mon - 1);// '- 1' here because we are NOT promoting the monthcontinue;}} else {int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-wint dow = daysOfWeek.first(); // desired// d-o-wst = daysOfWeek.tailSet(cDow);if (st != null && st.size() > 0) {dow = st.first();}int daysToAdd = 0;if (cDow < dow) {daysToAdd = dow - cDow;}if (cDow > dow) {daysToAdd = dow + (7 - cDow);}int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));if (day + daysToAdd > lDay) { // will we pass the end of// the month?cl.set(Calendar.SECOND, 0);cl.set(Calendar.MINUTE, 0);cl.set(Calendar.HOUR_OF_DAY, 0);cl.set(Calendar.DAY_OF_MONTH, 1);cl.set(Calendar.MONTH, mon);// no '- 1' here because we are promoting the monthcontinue;} else if (daysToAdd > 0) { // are we swithing days?cl.set(Calendar.SECOND, 0);cl.set(Calendar.MINUTE, 0);cl.set(Calendar.HOUR_OF_DAY, 0);cl.set(Calendar.DAY_OF_MONTH, day + daysToAdd);cl.set(Calendar.MONTH, mon - 1);// '- 1' because calendar is 0-based for this field,// and we are 1-basedcontinue;}}} else { // dayOfWSpec && !dayOfMSpecthrow new UnsupportedOperationException("Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.");}cl.set(Calendar.DAY_OF_MONTH, day);mon = cl.get(Calendar.MONTH) + 1;// '+ 1' because calendar is 0-based for this field, and we are// 1-basedint year = cl.get(Calendar.YEAR);t = -1;// test for expressions that never generate a valid fire date,// but keep looping...if (year > MAX_YEAR) {return null;}// get month...................................................st = months.tailSet(mon);if (st != null && st.size() != 0) {t = mon;mon = st.first();} else {mon = months.first();year++;}if (mon != t) {cl.set(Calendar.SECOND, 0);cl.set(Calendar.MINUTE, 0);cl.set(Calendar.HOUR_OF_DAY, 0);cl.set(Calendar.DAY_OF_MONTH, 1);cl.set(Calendar.MONTH, mon - 1);// '- 1' because calendar is 0-based for this field, and we are// 1-basedcl.set(Calendar.YEAR, year);continue;}cl.set(Calendar.MONTH, mon - 1);// '- 1' because calendar is 0-based for this field, and we are// 1-basedyear = cl.get(Calendar.YEAR);t = -1;// get year...................................................st = years.tailSet(year);if (st != null && st.size() != 0) {t = year;year = st.first();} else {return null; // ran out of years...}if (year != t) {cl.set(Calendar.SECOND, 0);cl.set(Calendar.MINUTE, 0);cl.set(Calendar.HOUR_OF_DAY, 0);cl.set(Calendar.DAY_OF_MONTH, 1);cl.set(Calendar.MONTH, 0);// '- 1' because calendar is 0-based for this field, and we are// 1-basedcl.set(Calendar.YEAR, year);continue;}cl.set(Calendar.YEAR, year);gotOne = true;} // while( !done )return cl.getTime();}/*** Advance the calendar to the particular hour paying particular attention* to daylight saving problems.* * @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);if (cal.get(java.util.Calendar.HOUR_OF_DAY) != hour && hour != 24) {cal.set(java.util.Calendar.HOUR_OF_DAY, hour + 1);}}/*** NOT YET IMPLEMENTED: Returns the time before the given time* that the <code>CronExpression</code> matches.*/ public Date getTimeBefore(Date endTime) { // FUTURE_TODO: implement QUARTZ-423return null;}/*** NOT YET IMPLEMENTED: Returns the final time that the * <code>CronExpression</code> will match.*/public Date getFinalFireTime() {// FUTURE_TODO: implement QUARTZ-423return null;}protected boolean isLeapYear(int year) {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);}}private void readObject(java.io.ObjectInputStream stream)throws java.io.IOException, ClassNotFoundException {stream.defaultReadObject();try {buildExpression(cronExpression);} catch (Exception ignore) {} // never happens}    @Override@Deprecatedpublic Object clone() {return new CronExpression(this);}
}class ValueSet {public int value;public int pos;
}

spring中使用quartz(注解版)相关推荐

  1. Spring中的@Value注解详解

    本文主要介绍Spring @Value 注解注入属性值的使用方法的分析,文章通过示例代码非常详细地介绍,对于每个人的学习或工作都有一定的参考学习价值 文章目录 概述 使用方式 基于配置文件的注入 基于 ...

  2. spring中配置quartz定时器

    spring中配置quartz定时器 最近项目中用到定时器,项目用的spring所以想在spring中配置一下定时器,看到网上用quartz的比较多,所以就搜了一下.参考:http://blog.cs ...

  3. Spring中利用java注解声明切面

    Spring中利用java注解声明切面 第一步:确定在Spring的XML文件中包含AOP的命名空间: 第二步:在Spring的XML文件中输入<aop:aspectj-autoproxy/&g ...

  4. Spring中定时任务Quartz集群配置学习

    Spring中定时任务Quartz集群配置学习 原来配置的Quartz是通过spring配置文件生效的,发现在非集群式的服务器上运行良好,但是将工程部署到水平集群服务器上去后改定时功能不能正常运行,没 ...

  5. Spring中常见的注解收集

    Spring中常见的注解收集 文章目录 Spring中常见的注解收集 1.@ResponseBody 2.@RequestBody 3.@RequestParam 4.@Controller 5.@R ...

  6. Spring 中的各种注解,光会用可不够哦!

    来源:https://digdeep.cnblogs.com/digdeep/p/4525567.html 1. Java中的注解 2. 使用 元注解 来自定义注解 和 处理自定义注解 3. spri ...

  7. spring中的quartz调度问题

    参考:http://cuiyingfeng.blog.51cto.com/43841/59734 1.SchedulerFactoryBean会自动启动. 当在spring文件中定义了多个Schedu ...

  8. 详细讲解Spring中的@Bean注解

    点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/weixin_42140261/ article/details/104864333 随着SpringBoot的流行,我们现在更 ...

  9. Spring中的@ConditionalOnProperty注解

    1.概述 介绍@ConditionalOnProperty注解的主要目的. 2.@ConditionalOnProperty的目的 通常,在开发基于Spring的应用程序时,可能需要根据配置属性的存在 ...

  10. Spring中配置Quartz的misfireInstruction

    参考:http://blog.csdn.net/george_hsu/article/details/6943336 最近在做一个自动发送邮件的小功能,其中用到了Quartz来做事件触发.首先说一下, ...

最新文章

  1. 布局AR VR领域?Tessera 8.5亿美元收购音频公司DTS
  2. 安装SandcastleInstaller
  3. 信息学奥赛一本通 2051:【例3.1】偶数
  4. Windows平台下Git服务器搭建
  5. python外汇交易回测系统_易经量化交易系统之回测系统1
  6. 基于JAVA+SpringMVC+Mybatis+MYSQL的台球计费管理系统
  7. web端业务数据管理平台+Axure运营数据管理平台+月度数据统计分析+年度排行榜数据统计页面分析+运营大数据统计管理后台+用户信息管理+Axure通用web端高保真交互业务数据管理平台
  8. 低代码平台会成为企业数字化基础设施么?
  9. ucgui button
  10. ArcGIS Zonal Statistics as Table 工具报错解决
  11. 关于spring security的URL路径验证问题
  12. Bada学习-多任务模式
  13. 计算机启动时老是检测,笔记本电脑开机时总是自检怎么办 【详解】
  14. python怎么爬取excel_求教! Python爬取的数据 怎么写入Excel表格中
  15. Windows下安装Python pyramid,并运行一个pyramid的Helloworld项目
  16. Alan Turing的纪录片观后感
  17. 基于PaddleDetection-YOLOV3做一个完整的图形目标检测项目
  18. GPS时间以及周内秒
  19. 小学计算机课程调研,中小学信息技术课程教学情况调查报告
  20. 马航:需接受MH370无人生还现实

热门文章

  1. vscode调试时如何在launch.json中添加环境变量
  2. Linux 下查看sqlite文件
  3. Windows/Linux/Solaris 软中断处理机制
  4. git 微盘_GitHub - 123ufo/VdiskSDK-Android: 微盘Android客户端SDK
  5. 2017mysql下载_mysql for visual studio
  6. 基于python的贴吧舆情监控助手实战
  7. Python新闻网站项目-3.Gerapy爬虫分布式部署
  8. Windows提权 cmd 开启 3389
  9. python车牌识别_Python-车牌识别
  10. SAP 物料成本核算冻结:料号. 不能过账,是否取消?消息 CK167