Source Code Cross Referenced for NthIncludedDayTrigger.java in  » Project-Management » quartz » org » quartz » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Project Management » quartz » org.quartz 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* 
0002:         * Copyright 2004-2005 OpenSymphony 
0003:         * 
0004:         * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
0005:         * use this file except in compliance with the License. You may obtain a copy 
0006:         * of the License at 
0007:         * 
0008:         *   http://www.apache.org/licenses/LICENSE-2.0 
0009:         *   
0010:         * Unless required by applicable law or agreed to in writing, software 
0011:         * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
0012:         * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
0013:         * License for the specific language governing permissions and limitations 
0014:         * under the License.
0015:         * 
0016:         */
0017:
0018:        package org.quartz;
0019:
0020:        import java.text.NumberFormat;
0021:        import java.util.Date;
0022:        import java.util.TimeZone;
0023:
0024:        /**
0025:         * A trigger which fires on the N<SUP>th</SUP> day of every interval type 
0026:         * ({@link #INTERVAL_TYPE_WEEKLY}, {@link #INTERVAL_TYPE_MONTHLY} or 
0027:         * {@link #INTERVAL_TYPE_YEARLY}) that is <i>not</i> excluded by the associated
0028:         * calendar. When determining what the N<SUP>th</SUP> day of the month or year
0029:         * is, <CODE>NthIncludedDayTrigger</CODE> will skip excluded days on the 
0030:         * associated calendar. This would commonly be used in an N<SUP>th</SUP> 
0031:         * business day situation, in which the user wishes to fire a particular job on
0032:         * the N<SUP>th</SUP> business day (i.e. the 5<SUP>th</SUP> business day of
0033:         * every month). Each <CODE>NthIncludedDayTrigger</CODE> also has an associated
0034:         * <CODE>fireAtTime</CODE> which indicates at what time of day the trigger is
0035:         * to fire.
0036:         * <P>
0037:         * All <CODE>NthIncludedDayTrigger</CODE>s default to a monthly interval type
0038:         * (fires on the N<SUP>th</SUP> day of every month) with N = 1 (first 
0039:         * non-excluded day) and <CODE>fireAtTime</CODE> set to 12:00 PM (noon). These
0040:         * values can be changed using the {@link #setN}, {@link #setIntervalType}, and
0041:         * {@link #setFireAtTime} methods. Users may also want to note the 
0042:         * {@link #setNextFireCutoffInterval} and {@link #getNextFireCutoffInterval}
0043:         * methods.
0044:         * <P>
0045:         * Take, for example, the following calendar:
0046:         * <P>
0047:         * <PRE>
0048:         *        July                  August                September
0049:         * Su Mo Tu We Th Fr Sa   Su Mo Tu We Th Fr Sa   Su Mo Tu We Th Fr Sa
0050:         *                 1  W       1  2  3  4  5  W                1  2  W
0051:         *  W  H  5  6  7  8  W    W  8  9 10 11 12  W    W  H  6  7  8  9  W
0052:         *  W 11 12 13 14 15  W    W 15 16 17 18 19  W    W 12 13 14 15 16  W
0053:         *  W 18 19 20 21 22  W    W 22 23 24 25 26  W    W 19 20 21 22 23  W
0054:         *  W 25 26 27 28 29  W    W 29 30 31             W 26 27 28 29 30
0055:         *  W
0056:         * </PRE>
0057:         * <P>
0058:         * Where W's represent weekend days, and H's represent holidays, all of which
0059:         * are excluded on a calendar associated with an 
0060:         * <CODE>NthIncludedDayTrigger</CODE> with <CODE>n=5</CODE> and 
0061:         * <CODE>intervalType=INTERVAL_TYPE_MONTHLY</CODE>. In this case, the trigger 
0062:         * would fire on the 8<SUP>th</SUP> of July (because of the July 4 holiday), 
0063:         * the 5<SUP>th</SUP> of August, and the 8<SUP>th</SUP> of September (because 
0064:         * of Labor Day).
0065:         * 
0066:         * @author  Aaron Craven
0067:         */
0068:        public class NthIncludedDayTrigger extends Trigger {
0069:
0070:            static final long serialVersionUID = 6267700049629328293L;
0071:
0072:            /**
0073:             * Instructs the <CODE>Scheduler</CODE> that upon a mis-fire situation, the
0074:             * <CODE>NthIncludedDayTrigger</CODE> wants to be fired now by the 
0075:             * <CODE>Scheduler</CODE>
0076:             */
0077:            public static final int MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1;
0078:
0079:            /**
0080:             * Instructs the <CODE>Scheduler</CODE> that upon a mis-fire situation, the
0081:             * <CODE>NthIncludedDayTrigger</CODE> wants to have 
0082:             * <CODE>nextFireTime</CODE> updated to the next time in the schedule after
0083:             * the current time, but it does not want to be fired now.
0084:             */
0085:            public static final int MISFIRE_INSTRUCTION_DO_NOTHING = 2;
0086:
0087:            /**
0088:             * indicates a monthly trigger type (fires on the N<SUP>th</SUP> included
0089:             * day of every month).
0090:             */
0091:            public static final int INTERVAL_TYPE_MONTHLY = 1;
0092:
0093:            /**
0094:             * indicates a yearly trigger type (fires on the N<SUP>th</SUP> included 
0095:             * day of every year).
0096:             */
0097:            public static final int INTERVAL_TYPE_YEARLY = 2;
0098:
0099:            /**
0100:             * indicates a weekly trigger type (fires on the N<SUP>th</SUP> included
0101:             * day of every week). When using this interval type, care must be taken
0102:             * not to think of the value of <CODE>n</CODE> as an analog to 
0103:             * <CODE>java.util.Calendar.DAY_OF_WEEK</CODE>. Such a comparison can only
0104:             * be drawn when there are no calendars associated with the trigger. To 
0105:             * illustrate, consider an <CODE>NthIncludedDayTrigger</CODE> with 
0106:             * <CODE>n = 3</CODE> which is associated with a Calendar excluding
0107:             * non-weekdays. The trigger would fire on the 3<SUP>rd</SUP> 
0108:             * <I>included</I> day of the week, which would be 4<SUP>th</SUP> 
0109:             * <I>actual</I> day of the week.
0110:             */
0111:            public static final int INTERVAL_TYPE_WEEKLY = 3;
0112:
0113:            private Date startTime = new Date();
0114:            private Date endTime;
0115:            private Date previousFireTime;
0116:            private Date nextFireTime;
0117:            private Calendar calendar;
0118:
0119:            private int n = 1;
0120:            private int intervalType = INTERVAL_TYPE_MONTHLY;
0121:            private int fireAtHour = 12;
0122:            private int fireAtMinute = 0;
0123:            private int fireAtSecond = 0;
0124:            private int nextFireCutoffInterval = 12;
0125:
0126:            private TimeZone timeZone;
0127:
0128:            /**
0129:             * Create an <CODE>NthIncludedDayTrigger</CODE> with no specified name,
0130:             * group, or <CODE>JobDetail</CODE>. This will result initially in a
0131:             * default monthly trigger that fires on the first day of every month at
0132:             * 12:00 PM (<CODE>n</CODE>=1, 
0133:             * <CODE>intervalType={@link #INTERVAL_TYPE_MONTHLY}</CODE>, 
0134:             * <CODE>fireAtTime="12:00"</CODE>).
0135:             * <P>
0136:             * Note that <CODE>setName()</CODE>, <CODE>setGroup()</CODE>, 
0137:             * <CODE>setJobName()</CODE>, and <CODE>setJobGroup()</CODE>, must be 
0138:             * called before the <CODE>NthIncludedDayTrigger</CODE> can be placed into
0139:             * a <CODE>Scheduler</CODE>.
0140:             */
0141:            public NthIncludedDayTrigger() {
0142:                super ();
0143:            }
0144:
0145:            /**
0146:             * Create an <CODE>NthIncludedDayTrigger</CODE> with the given name and
0147:             * group but no specified <CODE>JobDetail</CODE>. This will result 
0148:             * initially in a default monthly trigger that fires on the first day of 
0149:             * every month at 12:00 PM (<CODE>n</CODE>=1, 
0150:             * <CODE>intervalType={@link #INTERVAL_TYPE_MONTHLY}</CODE>, 
0151:             * <CODE>fireAtTime="12:00"</CODE>).
0152:             * <P>
0153:             * Note that <CODE>setJobName()</CODE> and <CODE>setJobGroup()</CODE> must
0154:             * be called before the <CODE>NthIncludedDayTrigger</CODE> can be placed 
0155:             * into a <CODE>Scheduler</CODE>.
0156:             *  
0157:             * @param name  the name for the <CODE>NthIncludedDayTrigger</CODE>
0158:             * @param group the group for the <CODE>NthIncludedDayTrigger</CODE>
0159:             */
0160:            public NthIncludedDayTrigger(String name, String group) {
0161:                super (name, group);
0162:            }
0163:
0164:            /**
0165:             * Create an <CODE>NthIncludedDayTrigger</CODE> with the given name and
0166:             * group and the specified <CODE>JobDetail</CODE>. This will result 
0167:             * initially in a default monthly trigger that fires on the first day of
0168:             * every month at 12:00 PM (<CODE>n</CODE>=1, 
0169:             * <CODE>intervalType={@link #INTERVAL_TYPE_MONTHLY}</CODE>, 
0170:             * <CODE>fireAtTime="12:00"</CODE>).
0171:             * 
0172:             * @param name     the name for the <CODE>NthIncludedDayTrigger</CODE>
0173:             * @param group    the group for the <CODE>NthIncludedDayTrigger</CODE>
0174:             * @param jobName  the name of the job to associate with the 
0175:             *                 <CODE>NthIncludedDayTrigger</CODE>
0176:             * @param jobGroup the group containing the job to associate with the 
0177:             *                 <CODE>NthIncludedDayTrigger</CODE>
0178:             */
0179:            public NthIncludedDayTrigger(String name, String group,
0180:                    String jobName, String jobGroup) {
0181:                super (name, group, jobName, jobGroup);
0182:            }
0183:
0184:            /**
0185:             * Sets the day of the interval on which the 
0186:             * <CODE>NthIncludedDayTrigger</CODE> should fire. If the N<SUP>th</SUP>
0187:             * day of the interval does not exist (i.e. the 32<SUP>nd</SUP> of a 
0188:             * month), the trigger simply will never fire. N may not be less than 1.
0189:             * 
0190:             * @param  n the day of the interval on which the trigger should fire.
0191:             * @throws java.lang.IllegalArgumentException
0192:             *         the value entered for N was not valid (probably less than or 
0193:             *         equal to zero).
0194:             * @see #getN()
0195:             */
0196:            public void setN(int n) {
0197:                if (n > 0) {
0198:                    this .n = n;
0199:                } else {
0200:                    throw new IllegalArgumentException(
0201:                            "N must be greater than 0.");
0202:                }
0203:            }
0204:
0205:            /**
0206:             * Returns the day of the interval on which the 
0207:             * <CODE>NthIncludedDayTrigger</CODE> should fire.
0208:             * 
0209:             * @return the value of <CODE>n</CODE>
0210:             * @see #setN(int)
0211:             */
0212:            public int getN() {
0213:                return this .n;
0214:            }
0215:
0216:            /**
0217:             * Sets the interval type for the <CODE>NthIncludedDayTrigger</CODE>. If
0218:             * {@link #INTERVAL_TYPE_MONTHLY}, the trigger will fire on the 
0219:             * N<SUP>th</SUP> included day of every month. If 
0220:             * {@link #INTERVAL_TYPE_YEARLY}, the trigger will fire on the 
0221:             * N<SUP>th</SUP> included day of every year. If 
0222:             * {@link #INTERVAL_TYPE_WEEKLY}, the trigger will fire on the 
0223:             * N<SUP>th</SUP> included day of every week. 
0224:             * 
0225:             * @param  intervalType the interval type for the trigger
0226:             * @throws java.lang.IllegalArgumentException
0227:             *         the value of <CODE>intervalType</CODE> is not valid. Valid
0228:             *         values are represented by the INTERVAL_TYPE_WEEKLY, 
0229:             *         INTERVAL_TYPE_MONTHLY and INTERVAL_TYPE_YEARLY constants.
0230:             * @see #getIntervalType()
0231:             * @see #INTERVAL_TYPE_WEEKLY
0232:             * @see #INTERVAL_TYPE_MONTHLY
0233:             * @see #INTERVAL_TYPE_YEARLY
0234:             */
0235:            public void setIntervalType(int intervalType) {
0236:                switch (intervalType) {
0237:                case INTERVAL_TYPE_WEEKLY:
0238:                    this .intervalType = intervalType;
0239:                    break;
0240:                case INTERVAL_TYPE_MONTHLY:
0241:                    this .intervalType = intervalType;
0242:                    break;
0243:                case INTERVAL_TYPE_YEARLY:
0244:                    this .intervalType = intervalType;
0245:                    break;
0246:                default:
0247:                    throw new IllegalArgumentException("Invalid Interval Type:"
0248:                            + intervalType);
0249:                }
0250:            }
0251:
0252:            /**
0253:             * Returns the interval type for the <CODE>NthIncludedDayTrigger</CODE>.
0254:             * 
0255:             * @return the trigger's interval type
0256:             * @see #setIntervalType(int)
0257:             * @see #INTERVAL_TYPE_WEEKLY
0258:             * @see #INTERVAL_TYPE_MONTHLY
0259:             * @see #INTERVAL_TYPE_YEARLY
0260:             */
0261:            public int getIntervalType() {
0262:                return this .intervalType;
0263:            }
0264:
0265:            /**
0266:             * Sets the fire time for the <CODE>NthIncludedDayTrigger</CODE>, which
0267:             * should be represented as a string with the format 
0268:             * &quot;HH:MM[:SS]&quot;, with HH representing the 24-hour clock hour
0269:             * of the fire time. Hours can be represented as either a one-digit or 
0270:             * two-digit number. Seconds are optional.
0271:             * 
0272:             * @param  fireAtTime the time at which the trigger should fire
0273:             * @throws java.lang.IllegalArgumentException
0274:             *         the specified value for <CODE>fireAtTime</CODE> could not be 
0275:             *         successfully parsed into a valid time of day.
0276:             * @see #getFireAtTime()
0277:             */
0278:            public void setFireAtTime(String fireAtTime) {
0279:                int newFireHour;
0280:                int newFireMinute;
0281:                int newFireSecond = 0;
0282:
0283:                try {
0284:                    int i = fireAtTime.indexOf(":");
0285:                    newFireHour = Integer.parseInt(fireAtTime.substring(0, i));
0286:                    newFireMinute = Integer.parseInt(fireAtTime.substring(
0287:                            i + 1, i + 3));
0288:                    i = fireAtTime.indexOf(":", i + 1);
0289:                    if (i > -1) {
0290:                        newFireSecond = Integer.parseInt(fireAtTime
0291:                                .substring(i + 1));
0292:                    }
0293:                } catch (Exception e) {
0294:                    throw new IllegalArgumentException(
0295:                            "Could not parse time expression '" + fireAtTime
0296:                                    + "':" + e.getMessage());
0297:                }
0298:
0299:                // Check ranges
0300:                if ((newFireHour < 0) || (newFireHour > 23)) {
0301:                    throw new IllegalArgumentException(
0302:                            "Could not parse time expression '" + fireAtTime
0303:                                    + "':"
0304:                                    + "fireAtHour must be between 0 and 23");
0305:                } else if ((newFireMinute < 0) || (newFireMinute > 59)) {
0306:                    throw new IllegalArgumentException(
0307:                            "Could not parse time expression '" + fireAtTime
0308:                                    + "':"
0309:                                    + "fireAtMinute must be between 0 and 59");
0310:                } else if ((newFireSecond < 0) || (newFireSecond > 59)) {
0311:                    throw new IllegalArgumentException(
0312:                            "Could not parse time expression '" + fireAtTime
0313:                                    + "':"
0314:                                    + "fireAtMinute must be between 0 and 59");
0315:                }
0316:
0317:                fireAtHour = newFireHour;
0318:                fireAtMinute = newFireMinute;
0319:                fireAtSecond = newFireSecond;
0320:            }
0321:
0322:            /**
0323:             * Returns the fire time for the <CODE>NthIncludedDayTrigger</CODE> as a
0324:             * string with the format &quot;HH:MM&quot;, with HH representing the 
0325:             * 24-hour clock hour of the fire time.
0326:             * 
0327:             * @return the fire time for the trigger
0328:             * @see #setFireAtTime(String)
0329:             */
0330:            public String getFireAtTime() {
0331:                NumberFormat format = NumberFormat.getNumberInstance();
0332:                format.setMaximumIntegerDigits(2);
0333:                format.setMinimumIntegerDigits(2);
0334:                format.setMaximumFractionDigits(0);
0335:
0336:                return format.format(this .fireAtHour) + ":"
0337:                        + format.format(this .fireAtMinute) + ":"
0338:                        + format.format(this .fireAtSecond);
0339:            }
0340:
0341:            /**
0342:             * Sets the <CODE>nextFireCutoffInterval</CODE> for the 
0343:             * <CODE>NthIncludedDayTrigger</CODE>.
0344:             * <P>
0345:             * Because of the conceptual design of <CODE>NthIncludedDayTrigger</CODE>,
0346:             * it is not always possible to decide with certainty that the trigger
0347:             * will <I>never</I> fire again. Therefore, it will search for the next 
0348:             * fire time up to a given cutoff. These cutoffs can be changed by using the
0349:             * {@link #setNextFireCutoffInterval(int)} and 
0350:             * {@link #getNextFireCutoffInterval()} methods. The default cutoff is 12
0351:             * of the intervals specified by <CODE>{@link #getIntervalType()
0352:             * intervalType}</CODE>.
0353:             * <P>
0354:             * In most cases, the default value of this setting (12) is sufficient (it
0355:             * is highly unlikely, for example, that you will need to look at more than
0356:             * 12 months of dates to ensure that your trigger will never fire again).  
0357:             * However, this setting is included to allow for the rare exceptions where
0358:             * this might not be true.
0359:             * <P>
0360:             * For example, if your trigger is associated with a calendar that excludes
0361:             * a great many dates in the next 12 months, and hardly any following that,
0362:             * it is possible (if <CODE>n</CODE> is large enough) that you could run 
0363:             * into this situation.  
0364:             * 
0365:             * @param nextFireCutoffInterval the desired cutoff interval
0366:             * @see #getNextFireCutoffInterval()
0367:             * @see #getNextFireTime()
0368:             */
0369:            public void setNextFireCutoffInterval(int nextFireCutoffInterval) {
0370:                this .nextFireCutoffInterval = nextFireCutoffInterval;
0371:            }
0372:
0373:            /**
0374:             * Returns the <CODE>nextFireCutoffInterval</CODE> for the 
0375:             * <CODE>NthIncludedDayTrigger</CODE>.
0376:             * <P>
0377:             * Because of the conceptual design of <CODE>NthIncludedDayTrigger</CODE>,
0378:             * it is not always possible to decide with certainty that the trigger
0379:             * will <I>never</I> fire again. Therefore, it will search for the next 
0380:             * fire time up to a given cutoff. These cutoffs can be changed by using the
0381:             * {@link #setNextFireCutoffInterval(int)} and 
0382:             * {@link #getNextFireCutoffInterval()} methods. The default cutoff is 12
0383:             * of the intervals specified by <CODE>{@link #getIntervalType()
0384:             * intervalType}</CODE>.
0385:             * 
0386:             * @return the chosen cutoff interval
0387:             * @see #setNextFireCutoffInterval(int)
0388:             * @see #getNextFireTime()
0389:             */
0390:            public int getNextFireCutoffInterval() {
0391:                return this .nextFireCutoffInterval;
0392:            }
0393:
0394:            /** 
0395:             * Sets the date/time on which the trigger may begin firing. This defines
0396:             * the initial boundary for trigger firings &mdash; the trigger will not
0397:             * fire prior to this date and time. Defaults to the current date and time
0398:             * when the <CODE>NthIncludedDayTrigger</CODE> is created.
0399:             * 
0400:             * @param  startTime the initial boundary for trigger firings
0401:             * @throws java.lang.IllegalArgumentException
0402:             *         the specified start time is after the current end time or is 
0403:             *         null
0404:             * @see #getStartTime()
0405:             */
0406:            public void setStartTime(Date startTime) {
0407:                if (startTime == null) {
0408:                    throw new IllegalArgumentException(
0409:                            "Start time may not be null");
0410:                }
0411:                if ((this .endTime != null) && endTime.before(startTime)) {
0412:                    throw new IllegalArgumentException(
0413:                            "Start time must be before end time.");
0414:                }
0415:                this .startTime = startTime;
0416:            }
0417:
0418:            /**
0419:             * Returns the date/time on which the trigger may begin firing. This 
0420:             * defines the initial boundary for trigger firings &mdash; the trigger
0421:             * will not fire prior to this date and time.
0422:             * 
0423:             * @return the initial date/time on which the trigger may begin firing
0424:             * @see #setStartTime(Date)
0425:             */
0426:            public Date getStartTime() {
0427:                return this .startTime;
0428:            }
0429:
0430:            /** 
0431:             * Sets the date/time on which the trigger must stop firing. This defines
0432:             * the final boundary for trigger firings &mdash; the trigger will not
0433:             * fire after to this date and time. If this value is null, no end time
0434:             * boundary is assumed, and the trigger can continue indefinitely.
0435:             * 
0436:             * @param  endTime the final boundary for trigger firings
0437:             * @throws java.lang.IllegalArgumentException
0438:             *         the specified end time is before the current start time
0439:             * @see #getEndTime()
0440:             */
0441:            public void setEndTime(Date endTime) {
0442:                if ((endTime != null) && endTime.before(startTime)) {
0443:                    throw new IllegalArgumentException(
0444:                            "End time must be after start time.");
0445:                }
0446:                this .endTime = endTime;
0447:            }
0448:
0449:            /** 
0450:             * Returns the date/time on which the trigger must stop firing. This 
0451:             * defines the final boundary for trigger firings &mdash; the trigger will
0452:             * not fire after to this date and time. If this value is null, no end time
0453:             * boundary is assumed, and the trigger can continue indefinitely.
0454:             * 
0455:             * @return the date/time on which the trigger must stop firing
0456:             * @see #setEndTime(Date)
0457:             */
0458:            public Date getEndTime() {
0459:                return this .endTime;
0460:            }
0461:
0462:            /**
0463:             * Sets the time zone in which the <code>fireAtTime</code> will be resolved.
0464:             * If no time zone is provided, then the default time zone will be used. 
0465:             * 
0466:             * @see TimeZone#getDefault()
0467:             * @see #getTimeZone()
0468:             * @see #getFireAtTime()
0469:             * @see #setFireAtTime(String)
0470:             */
0471:            public void setTimeZone(TimeZone timeZone) {
0472:                this .timeZone = timeZone;
0473:            }
0474:
0475:            /**
0476:             * Gets the time zone in which the <code>fireAtTime</code> will be resolved.
0477:             * If no time zone was explicitly set, then the default time zone is used. 
0478:             * 
0479:             * @see TimeZone#getDefault()
0480:             * @see #getTimeZone()
0481:             * @see #getFireAtTime()
0482:             * @see #setFireAtTime(String)
0483:             */
0484:            public TimeZone getTimeZone() {
0485:                if (timeZone == null) {
0486:                    timeZone = TimeZone.getDefault();
0487:                }
0488:                return timeZone;
0489:            }
0490:
0491:            /**
0492:             * Returns the next time at which the <CODE>NthIncludedDayTrigger</CODE>
0493:             * will fire. If the trigger will not fire again, <CODE>null</CODE> will be
0494:             * returned. 
0495:             * <P>
0496:             * Because of the conceptual design of <CODE>NthIncludedDayTrigger</CODE>,
0497:             * it is not always possible to decide with certainty that the trigger
0498:             * will <I>never</I> fire again. Therefore, it will search for the next 
0499:             * fire time up to a given cutoff. These cutoffs can be changed by using the
0500:             * {@link #setNextFireCutoffInterval(int)} and 
0501:             * {@link #getNextFireCutoffInterval()} methods. The default cutoff is 12
0502:             * of the intervals specified by <CODE>{@link #getIntervalType()
0503:             * intervalType}</CODE>.
0504:             * <P>
0505:             * The returned value is not guaranteed to be valid until after
0506:             * the trigger has been added to the scheduler.
0507:             * 
0508:             * @return the next fire time for the trigger
0509:             * @see #getNextFireCutoffInterval()
0510:             * @see #setNextFireCutoffInterval(int)
0511:             * @see #getFireTimeAfter(Date)
0512:             */
0513:            public Date getNextFireTime() {
0514:                return this .nextFireTime;
0515:            }
0516:
0517:            /**
0518:             * Returns the previous time at which the 
0519:             * <CODE>NthIncludedDayTrigger</CODE> fired. If the trigger has not yet 
0520:             * fired, <CODE>null</CODE> will be returned.
0521:             * 
0522:             * @return the previous fire time for the trigger
0523:             */
0524:            public Date getPreviousFireTime() {
0525:                return this .previousFireTime;
0526:            }
0527:
0528:            /**
0529:             * Returns the first time the <CODE>NthIncludedDayTrigger</CODE> will fire
0530:             * after the specified date. 
0531:             * <P> 
0532:             * Because of the conceptual design of <CODE>NthIncludedDayTrigger</CODE>,
0533:             * it is not always possible to decide with certainty that the trigger
0534:             * will <I>never</I> fire again. Therefore, it will search for the next 
0535:             * fire time up to a given cutoff. These cutoffs can be changed by using the
0536:             * {@link #setNextFireCutoffInterval(int)} and 
0537:             * {@link #getNextFireCutoffInterval()} methods. The default cutoff is 12
0538:             * of the intervals specified by <CODE>{@link #getIntervalType()
0539:             * intervalType}</CODE>.
0540:             * <P>
0541:             * Therefore, for triggers with <CODE>intervalType = 
0542:             * {@link NthIncludedDayTrigger#INTERVAL_TYPE_WEEKLY 
0543:             * INTERVAL_TYPE_WEEKLY}</CODE>, if the trigger will not fire within 12
0544:             * weeks after the given date/time, <CODE>null</CODE> will be returned. For
0545:             * triggers with <CODE>intervalType = 
0546:             * {@link NthIncludedDayTrigger#INTERVAL_TYPE_MONTHLY
0547:             * INTERVAL_TYPE_MONTHLY}</CODE>, if the trigger will not fire within 12 
0548:             * months after the given date/time, <CODE>null</CODE> will be returned. 
0549:             * For triggers with <CODE>intervalType = 
0550:             * {@link NthIncludedDayTrigger#INTERVAL_TYPE_YEARLY 
0551:             * INTERVAL_TYPE_YEARLY}</CODE>, if the trigger will not fire within 12
0552:             * years after the given date/time, <CODE>null</CODE> will be returned.  In 
0553:             * all cases, if the trigger will not fire before <CODE>endTime</CODE>, 
0554:             * <CODE>null</CODE> will be returned.
0555:             * 
0556:             * @param  afterTime The time after which to find the nearest fire time.
0557:             *                   This argument is treated as exclusive &mdash; that is,
0558:             *                   if afterTime is a valid fire time for the trigger, it
0559:             *                   will not be returned as the next fire time.
0560:             * @return the first time the trigger will fire following the specified
0561:             *         date
0562:             */
0563:            public Date getFireTimeAfter(Date afterTime) {
0564:                if (afterTime == null) {
0565:                    afterTime = new Date();
0566:                }
0567:
0568:                if (afterTime.before(this .startTime)) {
0569:                    afterTime = new Date(startTime.getTime() - 1000l);
0570:                }
0571:
0572:                if (this .intervalType == INTERVAL_TYPE_WEEKLY) {
0573:                    return getWeeklyFireTimeAfter(afterTime);
0574:                } else if (this .intervalType == INTERVAL_TYPE_MONTHLY) {
0575:                    return getMonthlyFireTimeAfter(afterTime);
0576:                } else if (this .intervalType == INTERVAL_TYPE_YEARLY) {
0577:                    return getYearlyFireTimeAfter(afterTime);
0578:                } else {
0579:                    return null;
0580:                }
0581:            }
0582:
0583:            /**
0584:             * Returns the last time the <CODE>NthIncludedDayTrigger</CODE> will fire.
0585:             * If the trigger will not fire at any point between <CODE>startTime</CODE>
0586:             * and <CODE>endTime</CODE>, <CODE>null</CODE> will be returned.
0587:             * 
0588:             * @return the last time the trigger will fire.
0589:             */
0590:            public Date getFinalFireTime() {
0591:                Date finalTime = null;
0592:                java.util.Calendar currCal = java.util.Calendar.getInstance();
0593:                currCal.setTime(this .endTime);
0594:
0595:                while ((finalTime == null)
0596:                        && (this .startTime.before(currCal.getTime()))) {
0597:                    currCal.add(java.util.Calendar.DATE, -1);
0598:
0599:                    finalTime = getFireTimeAfter(currCal.getTime());
0600:                }
0601:
0602:                return finalTime;
0603:            }
0604:
0605:            /**
0606:             * Called when the <CODE>Scheduler</CODE> has decided to 'fire' the trigger
0607:             * (execute the associated <CODE>Job</CODE>), in order to give the 
0608:             * <CODE>Trigger</CODE> a chance to update itself for its next triggering 
0609:             * (if any).
0610:             */
0611:            public void triggered(Calendar calendar) {
0612:                this .calendar = calendar;
0613:                this .previousFireTime = this .nextFireTime;
0614:                this .nextFireTime = getFireTimeAfter(this .nextFireTime);
0615:            }
0616:
0617:            /**
0618:             * Called by the scheduler at the time a <CODE>Trigger</code> is first
0619:             * added to the scheduler, in order to have the <CODE>Trigger</CODE>
0620:             * compute its first fire time, based on any associated calendar.
0621:             * <P>
0622:             * After this method has been called, <CODE>getNextFireTime()</CODE>
0623:             * should return a valid answer.
0624:             * </p>
0625:             * 
0626:             * @return the first time at which the <CODE>Trigger</CODE> will be fired
0627:             *         by the scheduler, which is also the same value 
0628:             *         {@link #getNextFireTime()} will return (until after the first 
0629:             *         firing of the <CODE>Trigger</CODE>).
0630:             */
0631:            public Date computeFirstFireTime(Calendar calendar) {
0632:                this .calendar = calendar;
0633:                this .nextFireTime = getFireTimeAfter(new Date(this .startTime
0634:                        .getTime() - 1000l));
0635:
0636:                return this .nextFireTime;
0637:            }
0638:
0639:            /**
0640:             * Called after the <CODE>Scheduler</CODE> has executed the 
0641:             * <code>JobDetail</CODE> associated with the <CODE>Trigger</CODE> in order
0642:             * to get the final instruction code from the trigger.
0643:             * 
0644:             * @param jobCtx the <CODE>JobExecutionContext</CODE> that was used by the
0645:             *               <CODE>Job</CODE>'s <CODE>execute()</CODE> method.
0646:             * @param result the <CODE>JobExecutionException</CODE> thrown by the
0647:             *               <CODE>Job</CODE>, if any (may be <CODE>null</CODE>)
0648:             * @return one of the Trigger.INSTRUCTION_XXX constants.
0649:             */
0650:            public int executionComplete(JobExecutionContext jobCtx,
0651:                    JobExecutionException result) {
0652:                if (result != null && result.refireImmediately()) {
0653:                    return INSTRUCTION_RE_EXECUTE_JOB;
0654:                }
0655:
0656:                if (result != null && result.unscheduleFiringTrigger()) {
0657:                    return INSTRUCTION_SET_TRIGGER_COMPLETE;
0658:                }
0659:
0660:                if (result != null && result.unscheduleAllTriggers()) {
0661:                    return INSTRUCTION_SET_ALL_JOB_TRIGGERS_COMPLETE;
0662:                }
0663:
0664:                if (!mayFireAgain()) {
0665:                    return INSTRUCTION_DELETE_TRIGGER;
0666:                }
0667:
0668:                return INSTRUCTION_NOOP;
0669:            }
0670:
0671:            /**
0672:             * Used by the <CODE>Scheduler</CODE> to determine whether or not it is
0673:             * possible for this <CODE>Trigger</CODE> to fire again.
0674:             * <P>
0675:             * If the returned value is <CODE>false</CODE> then the 
0676:             * <CODE>Scheduler</CODE> may remove the <CODE>Trigger</CODE> from the
0677:             * <CODE>JobStore</CODE>
0678:             * 
0679:             * @return a boolean indicator of whether the trigger could potentially fire
0680:             *         again
0681:             */
0682:            public boolean mayFireAgain() {
0683:                return (getNextFireTime() != null);
0684:            }
0685:
0686:            /**
0687:             * Indicates whether <CODE>misfireInstruction</CODE> is a valid misfire
0688:             * instruction for this <CODE>Trigger</CODE>.
0689:             * 
0690:             * @return whether <CODE>misfireInstruction</CODE> is valid.
0691:             */
0692:            protected boolean validateMisfireInstruction(int misfireInstruction) {
0693:                if ((misfireInstruction == MISFIRE_INSTRUCTION_SMART_POLICY)
0694:                        || (misfireInstruction == MISFIRE_INSTRUCTION_DO_NOTHING)
0695:                        || (misfireInstruction == MISFIRE_INSTRUCTION_FIRE_ONCE_NOW)) {
0696:                    return true;
0697:                } else {
0698:                    return false;
0699:                }
0700:            }
0701:
0702:            /**
0703:             * Updates the <CODE>NthIncludedDayTrigger</CODE>'s state based on the
0704:             * MISFIRE_INSTRUCTION_XXX that was selected when the 
0705:             * <CODE>NthIncludedDayTrigger</CODE> was created
0706:             * <P>
0707:             * If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY,
0708:             * then the instruction will be interpreted as 
0709:             * {@link #MISFIRE_INSTRUCTION_FIRE_ONCE_NOW}.
0710:             * 
0711:             * @param calendar a new or updated calendar to use for the trigger
0712:             */
0713:            public void updateAfterMisfire(Calendar calendar) {
0714:                int instruction = getMisfireInstruction();
0715:
0716:                this .calendar = calendar;
0717:
0718:                if (instruction == MISFIRE_INSTRUCTION_SMART_POLICY) {
0719:                    instruction = MISFIRE_INSTRUCTION_FIRE_ONCE_NOW;
0720:                }
0721:
0722:                if (instruction == MISFIRE_INSTRUCTION_DO_NOTHING) {
0723:                    this .nextFireTime = getFireTimeAfter(new Date());
0724:                } else if (instruction == MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) {
0725:                    this .nextFireTime = new Date();
0726:                }
0727:            }
0728:
0729:            /**
0730:             * Updates the <CODE>NthIncludedDayTrigger</CODE>'s state based on the 
0731:             * given new version of the associated <CODE>Calendar</CODE>. 
0732:             * 
0733:             * @param calendar         a new or updated calendar to use for the trigger
0734:             * @param misfireThreshold the amount of time (in milliseconds) that must
0735:             *                         be between &quot;now&quot; and the time the next
0736:             *                         firing of the trigger is supposed to occur.
0737:             */
0738:            public void updateWithNewCalendar(Calendar calendar,
0739:                    long misfireThreshold) {
0740:                Date now = new Date();
0741:                long diff;
0742:
0743:                this .calendar = calendar;
0744:                this .nextFireTime = getFireTimeAfter(this .previousFireTime);
0745:
0746:                if ((this .nextFireTime != null)
0747:                        && (this .nextFireTime.before(now))) {
0748:                    diff = now.getTime() - this .nextFireTime.getTime();
0749:                    if (diff >= misfireThreshold) {
0750:                        this .nextFireTime = getFireTimeAfter(this .nextFireTime);
0751:                    }
0752:                }
0753:            }
0754:
0755:            /**
0756:             * Calculates the first time an <CODE>NthIncludedDayTrigger</CODE> with 
0757:             * <CODE>intervalType = {@link #INTERVAL_TYPE_WEEKLY}</CODE> will fire 
0758:             * after the specified date. See {@link #getNextFireTime} for more 
0759:             * information.
0760:             * 
0761:             * @param afterDate The time after which to find the nearest fire time.
0762:             *                  This argument is treated as exclusive &mdash; that is,
0763:             *                  if afterTime is a valid fire time for the trigger, it
0764:             *                  will not be returned as the next fire time.
0765:             * @return the first time the trigger will fire following the specified
0766:             *         date
0767:             */
0768:            private Date getWeeklyFireTimeAfter(Date afterDate) {
0769:                int currN = 0;
0770:                java.util.Calendar afterCal;
0771:                java.util.Calendar currCal;
0772:                int currWeek;
0773:                int weekCount = 0;
0774:                boolean gotOne = false;
0775:
0776:                afterCal = java.util.Calendar.getInstance(getTimeZone());
0777:                afterCal.setTime(afterDate);
0778:
0779:                currCal = java.util.Calendar.getInstance(getTimeZone());
0780:                currCal.set(afterCal.get(java.util.Calendar.YEAR), afterCal
0781:                        .get(java.util.Calendar.MONTH), afterCal
0782:                        .get(java.util.Calendar.DAY_OF_MONTH));
0783:
0784:                //move to the first day of the week (SUNDAY)
0785:                currCal.add(java.util.Calendar.DAY_OF_MONTH, (afterCal
0786:                        .get(java.util.Calendar.DAY_OF_WEEK) - 1)
0787:                        * -1);
0788:
0789:                currCal.set(java.util.Calendar.HOUR_OF_DAY, this .fireAtHour);
0790:                currCal.set(java.util.Calendar.MINUTE, this .fireAtMinute);
0791:                currCal.set(java.util.Calendar.SECOND, this .fireAtSecond);
0792:                currCal.set(java.util.Calendar.MILLISECOND, 0);
0793:
0794:                currWeek = currCal.get(java.util.Calendar.WEEK_OF_YEAR);
0795:
0796:                while ((!gotOne) && (weekCount < this .nextFireCutoffInterval)) {
0797:                    while ((currN != this .n) && (weekCount < 12)) {
0798:                        //if we move into a new week, reset the current "n" counter
0799:                        if (currCal.get(java.util.Calendar.WEEK_OF_YEAR) != currWeek) {
0800:                            currN = 0;
0801:                            weekCount++;
0802:                            currWeek = currCal
0803:                                    .get(java.util.Calendar.WEEK_OF_YEAR);
0804:                        }
0805:
0806:                        //treating a null calendar as an all-inclusive calendar,
0807:                        // increment currN if the current date being tested is included
0808:                        // on the calendar
0809:                        if ((calendar == null)
0810:                                || (calendar.isTimeIncluded(currCal.getTime()
0811:                                        .getTime()))) {
0812:                            currN++;
0813:                        }
0814:
0815:                        if (currN != this .n) {
0816:                            currCal.add(java.util.Calendar.DATE, 1);
0817:                        }
0818:
0819:                        //if we pass endTime, drop out and return null.
0820:                        if ((this .endTime != null)
0821:                                && (currCal.getTime().after(this .endTime))) {
0822:                            return null;
0823:                        }
0824:                    }
0825:
0826:                    //We found an "n" or we've checked the requisite number of weeks.
0827:                    // If we've found an "n", is it the right one? -- that is, we could
0828:                    // be looking at an nth day PRIOR to afterDate
0829:                    if (currN == this .n) {
0830:                        if (afterDate.before(currCal.getTime())) {
0831:                            gotOne = true;
0832:                        } else { //resume checking on the first day of the next week
0833:                            currCal.add(java.util.Calendar.DAY_OF_MONTH, -1
0834:                                    * (currN - 1));
0835:                            currCal.add(java.util.Calendar.DAY_OF_MONTH, 7);
0836:                            currN = 0;
0837:                        }
0838:                    }
0839:                }
0840:
0841:                if (weekCount < this .nextFireCutoffInterval) {
0842:                    return currCal.getTime();
0843:                } else {
0844:                    return null;
0845:                }
0846:            }
0847:
0848:            /**
0849:             * Calculates the first time an <CODE>NthIncludedDayTrigger</CODE> with 
0850:             * <CODE>intervalType = {@link #INTERVAL_TYPE_MONTHLY}</CODE> will fire 
0851:             * after the specified date. See {@link #getNextFireTime} for more 
0852:             * information.
0853:             * 
0854:             * @param afterDate The time after which to find the nearest fire time.
0855:             *                  This argument is treated as exclusive &mdash; that is,
0856:             *                  if afterTime is a valid fire time for the trigger, it
0857:             *                  will not be returned as the next fire time.
0858:             * @return the first time the trigger will fire following the specified
0859:             *         date
0860:             */
0861:            private Date getMonthlyFireTimeAfter(Date afterDate) {
0862:                int currN = 0;
0863:                java.util.Calendar afterCal;
0864:                java.util.Calendar currCal;
0865:                int currMonth;
0866:                int monthCount = 0;
0867:                boolean gotOne = false;
0868:
0869:                afterCal = java.util.Calendar.getInstance(getTimeZone());
0870:                afterCal.setTime(afterDate);
0871:
0872:                currCal = java.util.Calendar.getInstance(getTimeZone());
0873:                currCal.set(afterCal.get(java.util.Calendar.YEAR), afterCal
0874:                        .get(java.util.Calendar.MONTH), 1);
0875:                currCal.set(java.util.Calendar.HOUR_OF_DAY, this .fireAtHour);
0876:                currCal.set(java.util.Calendar.MINUTE, this .fireAtMinute);
0877:                currCal.set(java.util.Calendar.SECOND, this .fireAtSecond);
0878:                currCal.set(java.util.Calendar.MILLISECOND, 0);
0879:
0880:                currMonth = currCal.get(java.util.Calendar.MONTH);
0881:
0882:                while ((!gotOne) && (monthCount < this .nextFireCutoffInterval)) {
0883:                    while ((currN != this .n) && (monthCount < 12)) {
0884:                        //if we move into a new month, reset the current "n" counter
0885:                        if (currCal.get(java.util.Calendar.MONTH) != currMonth) {
0886:                            currN = 0;
0887:                            monthCount++;
0888:                            currMonth = currCal.get(java.util.Calendar.MONTH);
0889:                        }
0890:
0891:                        //treating a null calendar as an all-inclusive calendar,
0892:                        // increment currN if the current date being tested is included
0893:                        // on the calendar
0894:                        if ((calendar == null)
0895:                                || (calendar.isTimeIncluded(currCal.getTime()
0896:                                        .getTime()))) {
0897:                            currN++;
0898:                        }
0899:
0900:                        if (currN != this .n) {
0901:                            currCal.add(java.util.Calendar.DATE, 1);
0902:                        }
0903:
0904:                        //if we pass endTime, drop out and return null.
0905:                        if ((this .endTime != null)
0906:                                && (currCal.getTime().after(this .endTime))) {
0907:                            return null;
0908:                        }
0909:                    }
0910:
0911:                    //We found an "n" or we've checked the requisite number of months.
0912:                    // If we've found an "n", is it the right one? -- that is, we could
0913:                    // be looking at an nth day PRIOR to afterDate
0914:                    if (currN == this .n) {
0915:                        if (afterDate.before(currCal.getTime())) {
0916:                            gotOne = true;
0917:                        } else { //resume checking on the first day of the next month
0918:                            currCal.set(java.util.Calendar.DAY_OF_MONTH, 1);
0919:                            currCal.add(java.util.Calendar.MONTH, 1);
0920:                            currN = 0;
0921:                        }
0922:                    }
0923:                }
0924:
0925:                if (monthCount < this .nextFireCutoffInterval) {
0926:                    return currCal.getTime();
0927:                } else {
0928:                    return null;
0929:                }
0930:            }
0931:
0932:            /**
0933:             * Calculates the first time an <CODE>NthIncludedDayTrigger</CODE> with 
0934:             * <CODE>intervalType = {@link #INTERVAL_TYPE_YEARLY}</CODE> will fire 
0935:             * after the specified date. See {@link #getNextFireTime} for more 
0936:             * information.
0937:             * 
0938:             * @param afterDate The time after which to find the nearest fire time.
0939:             *                  This argument is treated as exclusive &mdash; that is,
0940:             *                  if afterTime is a valid fire time for the trigger, it
0941:             *                  will not be returned as the next fire time.
0942:             * @return the first time the trigger will fire following the specified
0943:             *         date
0944:             */
0945:            private Date getYearlyFireTimeAfter(Date afterDate) {
0946:                int currN = 0;
0947:                java.util.Calendar afterCal;
0948:                java.util.Calendar currCal;
0949:                int currYear;
0950:                int yearCount = 0;
0951:                boolean gotOne = false;
0952:
0953:                afterCal = java.util.Calendar.getInstance(getTimeZone());
0954:                afterCal.setTime(afterDate);
0955:
0956:                currCal = java.util.Calendar.getInstance(getTimeZone());
0957:                currCal.set(afterCal.get(java.util.Calendar.YEAR),
0958:                        java.util.Calendar.JANUARY, 1);
0959:                currCal.set(java.util.Calendar.HOUR_OF_DAY, this .fireAtHour);
0960:                currCal.set(java.util.Calendar.MINUTE, this .fireAtMinute);
0961:                currCal.set(java.util.Calendar.SECOND, this .fireAtSecond);
0962:                currCal.set(java.util.Calendar.MILLISECOND, 0);
0963:
0964:                currYear = currCal.get(java.util.Calendar.YEAR);
0965:
0966:                while ((!gotOne) && (yearCount < this .nextFireCutoffInterval)) {
0967:                    while ((currN != this .n) && (yearCount < 5)) {
0968:                        //if we move into a new year, reset the current "n" counter
0969:                        if (currCal.get(java.util.Calendar.YEAR) != currYear) {
0970:                            currN = 0;
0971:                            yearCount++;
0972:                            currYear = currCal.get(java.util.Calendar.YEAR);
0973:                        }
0974:
0975:                        //treating a null calendar as an all-inclusive calendar,
0976:                        // increment currN if the current date being tested is included
0977:                        // on the calendar
0978:                        if ((calendar == null)
0979:                                || (calendar.isTimeIncluded(currCal.getTime()
0980:                                        .getTime()))) {
0981:                            currN++;
0982:                        }
0983:
0984:                        if (currN != this .n) {
0985:                            currCal.add(java.util.Calendar.DATE, 1);
0986:                        }
0987:
0988:                        //if we pass endTime, drop out and return null.
0989:                        if ((this .endTime != null)
0990:                                && (currCal.getTime().after(this .endTime))) {
0991:                            return null;
0992:                        }
0993:                    }
0994:
0995:                    //We found an "n" or we've checked the requisite number of years.
0996:                    // If we've found an "n", is it the right one? -- that is, we 
0997:                    // could be looking at an nth day PRIOR to afterDate
0998:                    if (currN == this .n) {
0999:                        if (afterDate.before(currCal.getTime())) {
1000:                            gotOne = true;
1001:                        } else { //resume checking on the first day of the next year
1002:                            currCal.set(java.util.Calendar.DAY_OF_MONTH, 1);
1003:                            currCal.set(java.util.Calendar.MONTH,
1004:                                    java.util.Calendar.JANUARY);
1005:                            currCal.add(java.util.Calendar.YEAR, 1);
1006:                            currN = 0;
1007:                        }
1008:                    }
1009:                }
1010:
1011:                if (yearCount < this.nextFireCutoffInterval) {
1012:                    return currCal.getTime();
1013:                } else {
1014:                    return null;
1015:                }
1016:            }
1017:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.