1 17 18 package org.quartz; 19 20 import java.text.NumberFormat ; 21 import java.util.Date ; 22 import java.util.TimeZone ; 23 24 68 public class NthIncludedDayTrigger extends Trigger { 69 70 static final long serialVersionUID = 6267700049629328293L; 71 72 77 public static final int MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1; 78 79 85 public static final int MISFIRE_INSTRUCTION_DO_NOTHING = 2; 86 87 91 public static final int INTERVAL_TYPE_MONTHLY = 1; 92 93 97 public static final int INTERVAL_TYPE_YEARLY = 2; 98 99 111 public static final int INTERVAL_TYPE_WEEKLY = 3; 112 113 private Date startTime = new Date (); 114 private Date endTime; 115 private Date previousFireTime; 116 private Date nextFireTime; 117 private Calendar calendar; 118 119 private int n = 1; 120 private int intervalType = INTERVAL_TYPE_MONTHLY; 121 private int fireAtHour = 12; 122 private int fireAtMinute = 0; 123 private int fireAtSecond = 0; 124 private int nextFireCutoffInterval = 12; 125 126 private TimeZone timeZone; 127 128 141 public NthIncludedDayTrigger() { 142 super(); 143 } 144 145 160 public NthIncludedDayTrigger(String name, String group) { 161 super(name, group); 162 } 163 164 179 public NthIncludedDayTrigger(String name, String group, String jobName, 180 String jobGroup) { 181 super(name, group, jobName, jobGroup); 182 } 183 184 196 public void setN(int n) { 197 if (n > 0) { 198 this.n = n; 199 } else { 200 throw new IllegalArgumentException ("N must be greater than 0."); 201 } 202 } 203 204 211 public int getN() { 212 return this.n; 213 } 214 215 234 public void setIntervalType(int intervalType) { 235 switch (intervalType) { 236 case INTERVAL_TYPE_WEEKLY: 237 this.intervalType = intervalType; 238 break; 239 case INTERVAL_TYPE_MONTHLY: 240 this.intervalType = intervalType; 241 break; 242 case INTERVAL_TYPE_YEARLY: 243 this.intervalType = intervalType; 244 break; 245 default: 246 throw new IllegalArgumentException ("Invalid Interval Type:" 247 + intervalType); 248 } 249 } 250 251 260 public int getIntervalType() { 261 return this.intervalType; 262 } 263 264 277 public void setFireAtTime(String fireAtTime) { 278 int newFireHour; 279 int newFireMinute; 280 int newFireSecond = 0; 281 282 try { 283 int i = fireAtTime.indexOf(":"); 284 newFireHour = Integer.parseInt(fireAtTime.substring(0, i)); 285 newFireMinute = Integer.parseInt(fireAtTime.substring(i+1, i+3)); 286 i = fireAtTime.indexOf(":", i+1); 287 if (i > -1) { 288 newFireSecond = Integer.parseInt(fireAtTime.substring(i+1)); 289 } 290 } catch (Exception e) { 291 throw new IllegalArgumentException ( 292 "Could not parse time expression '" + fireAtTime + "':" + e.getMessage()); 293 } 294 295 if ((newFireHour < 0) || (newFireHour > 23)) { 297 throw new IllegalArgumentException ( 298 "Could not parse time expression '" + fireAtTime + "':" + 299 "fireAtHour must be between 0 and 23"); 300 } else if ((newFireMinute < 0) || (newFireMinute > 59)) { 301 throw new IllegalArgumentException ( 302 "Could not parse time expression '" + fireAtTime + "':" + 303 "fireAtMinute must be between 0 and 59"); 304 } else if ((newFireSecond < 0) || (newFireSecond > 59)) { 305 throw new IllegalArgumentException ( 306 "Could not parse time expression '" + fireAtTime + "':" + 307 "fireAtMinute must be between 0 and 59"); 308 } 309 310 fireAtHour = newFireHour; 311 fireAtMinute = newFireMinute; 312 fireAtSecond = newFireSecond; 313 } 314 315 323 public String getFireAtTime() { 324 NumberFormat format = NumberFormat.getNumberInstance(); 325 format.setMaximumIntegerDigits(2); 326 format.setMinimumIntegerDigits(2); 327 format.setMaximumFractionDigits(0); 328 329 return format.format(this.fireAtHour) + ":" + 330 format.format(this.fireAtMinute) + ":" + 331 format.format(this.fireAtSecond); 332 } 333 334 362 public void setNextFireCutoffInterval(int nextFireCutoffInterval) { 363 this.nextFireCutoffInterval = nextFireCutoffInterval; 364 } 365 366 383 public int getNextFireCutoffInterval() { 384 return this.nextFireCutoffInterval; 385 } 386 387 399 public void setStartTime(Date startTime) { 400 if (startTime == null) { 401 throw new IllegalArgumentException ("Start time may not be null"); 402 } 403 if ((this.endTime != null) && endTime.before(startTime)) { 404 throw new IllegalArgumentException ("Start time must be before end time."); 405 } 406 this.startTime = startTime; 407 } 408 409 417 public Date getStartTime() { 418 return this.startTime; 419 } 420 421 432 public void setEndTime(Date endTime) { 433 if ((endTime != null) && endTime.before(startTime)) { 434 throw new IllegalArgumentException ("End time must be after start time."); 435 } 436 this.endTime = endTime; 437 } 438 439 448 public Date getEndTime() { 449 return this.endTime; 450 } 451 452 461 public void setTimeZone(TimeZone timeZone) { 462 this.timeZone = timeZone; 463 } 464 465 474 public TimeZone getTimeZone() { 475 if (timeZone == null) { 476 timeZone = TimeZone.getDefault(); 477 } 478 return timeZone; 479 } 480 481 482 504 public Date getNextFireTime() { 505 return this.nextFireTime; 506 } 507 508 515 public Date getPreviousFireTime() { 516 return this.previousFireTime; 517 } 518 519 554 public Date getFireTimeAfter(Date afterTime) { 555 if (afterTime == null) { 556 afterTime = new Date (); 557 } 558 559 if (afterTime.before(this.startTime)) { 560 afterTime = new Date (startTime.getTime() - 1000l); 561 } 562 563 if (this.intervalType == INTERVAL_TYPE_WEEKLY) { 564 return getWeeklyFireTimeAfter(afterTime); 565 } else if (this.intervalType == INTERVAL_TYPE_MONTHLY) { 566 return getMonthlyFireTimeAfter(afterTime); 567 } else if (this.intervalType == INTERVAL_TYPE_YEARLY) { 568 return getYearlyFireTimeAfter(afterTime); 569 } else { 570 return null; 571 } 572 } 573 574 581 public Date getFinalFireTime() { 582 Date finalTime = null; 583 java.util.Calendar currCal = java.util.Calendar.getInstance(); 584 currCal.setTime(this.endTime); 585 586 while ((finalTime == null) 587 && (this.startTime.before(currCal.getTime()))) { 588 currCal.add(java.util.Calendar.DATE, -1); 589 590 finalTime = getFireTimeAfter(currCal.getTime()); 591 } 592 593 return finalTime; 594 } 595 596 602 public void triggered(Calendar calendar) { 603 this.calendar = calendar; 604 this.previousFireTime = this.nextFireTime; 605 this.nextFireTime = getFireTimeAfter(this.nextFireTime); 606 } 607 608 622 public Date computeFirstFireTime(Calendar calendar) { 623 this.calendar = calendar; 624 this.nextFireTime = 625 getFireTimeAfter(new Date (this.startTime.getTime() - 1000l)); 626 627 return this.nextFireTime; 628 } 629 630 641 public int executionComplete(JobExecutionContext jobCtx, 642 JobExecutionException result) { 643 if (result != null && result.refireImmediately()) { 644 return INSTRUCTION_RE_EXECUTE_JOB; 645 } 646 647 if (result != null && result.unscheduleFiringTrigger()) { 648 return INSTRUCTION_SET_TRIGGER_COMPLETE; 649 } 650 651 if (result != null && result.unscheduleAllTriggers()) { 652 return INSTRUCTION_SET_ALL_JOB_TRIGGERS_COMPLETE; 653 } 654 655 if (!mayFireAgain()) { 656 return INSTRUCTION_DELETE_TRIGGER; 657 } 658 659 return INSTRUCTION_NOOP; 660 } 661 662 673 public boolean mayFireAgain() { 674 return (getNextFireTime() != null); 675 } 676 677 683 protected boolean validateMisfireInstruction(int misfireInstruction) { 684 if ((misfireInstruction == MISFIRE_INSTRUCTION_SMART_POLICY) || 685 (misfireInstruction == MISFIRE_INSTRUCTION_DO_NOTHING) || 686 (misfireInstruction == MISFIRE_INSTRUCTION_FIRE_ONCE_NOW)) { 687 return true; 688 } else { 689 return false; 690 } 691 } 692 693 704 public void updateAfterMisfire(Calendar calendar) { 705 int instruction = getMisfireInstruction(); 706 707 this.calendar = calendar; 708 709 if (instruction == MISFIRE_INSTRUCTION_SMART_POLICY) { 710 instruction = MISFIRE_INSTRUCTION_FIRE_ONCE_NOW; 711 } 712 713 if (instruction == MISFIRE_INSTRUCTION_DO_NOTHING) { 714 this.nextFireTime = getFireTimeAfter(new Date ()); 715 } else if (instruction == MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) { 716 this.nextFireTime = new Date (); 717 } 718 } 719 720 729 public void updateWithNewCalendar(Calendar calendar, 730 long misfireThreshold) { 731 Date now = new Date (); 732 long diff; 733 734 this.calendar = calendar; 735 this.nextFireTime = getFireTimeAfter(this.previousFireTime); 736 737 if ((this.nextFireTime != null) && (this.nextFireTime.before(now))) { 738 diff = now.getTime() - this.nextFireTime.getTime(); 739 if (diff >= misfireThreshold) { 740 this.nextFireTime = getFireTimeAfter(this.nextFireTime); 741 } 742 } 743 } 744 745 758 private Date getWeeklyFireTimeAfter(Date afterDate) { 759 int currN = 0; 760 java.util.Calendar afterCal; 761 java.util.Calendar currCal; 762 int currWeek; 763 int weekCount = 0; 764 boolean gotOne = false; 765 766 afterCal = java.util.Calendar.getInstance(getTimeZone()); 767 afterCal.setTime(afterDate); 768 769 currCal = java.util.Calendar.getInstance(getTimeZone()); 770 currCal.set(afterCal.get(java.util.Calendar.YEAR), 771 afterCal.get(java.util.Calendar.MONTH), 772 afterCal.get(java.util.Calendar.DAY_OF_MONTH)); 773 774 currCal.add(java.util.Calendar.DAY_OF_MONTH, 776 (afterCal.get(java.util.Calendar.DAY_OF_WEEK) - 1) * -1); 777 778 currCal.set(java.util.Calendar.HOUR_OF_DAY, this.fireAtHour); 779 currCal.set(java.util.Calendar.MINUTE, this.fireAtMinute); 780 currCal.set(java.util.Calendar.SECOND, this.fireAtSecond); 781 currCal.set(java.util.Calendar.MILLISECOND, 0); 782 783 currWeek = currCal.get(java.util.Calendar.WEEK_OF_YEAR); 784 785 while ((!gotOne) && (weekCount < this.nextFireCutoffInterval)) { 786 while ((currN != this.n) && (weekCount < 12)) { 787 if (currCal.get(java.util.Calendar.WEEK_OF_YEAR) != currWeek) { 789 currN = 0; 790 weekCount++; 791 currWeek = currCal.get(java.util.Calendar.WEEK_OF_YEAR); 792 } 793 794 if ((calendar == null) 798 || (calendar.isTimeIncluded(currCal.getTime().getTime()))) { 799 currN++; 800 } 801 802 if (currN != this.n) { 803 currCal.add(java.util.Calendar.DATE, 1); 804 } 805 806 if ((this.endTime != null) 808 && (currCal.getTime().after(this.endTime))) { 809 return null; 810 } 811 } 812 813 if (currN == this.n) { 817 if (afterDate.before(currCal.getTime())) { 818 gotOne = true; 819 } else { currCal.add(java.util.Calendar.DAY_OF_MONTH, -1 * (currN - 1)); 821 currCal.add(java.util.Calendar.DAY_OF_MONTH, 7); 822 currN = 0; 823 } 824 } 825 } 826 827 if (weekCount < this.nextFireCutoffInterval) { 828 return currCal.getTime(); 829 } else { 830 return null; 831 } 832 } 833 834 847 private Date getMonthlyFireTimeAfter(Date afterDate) { 848 int currN = 0; 849 java.util.Calendar afterCal; 850 java.util.Calendar currCal; 851 int currMonth; 852 int monthCount = 0; 853 boolean gotOne = false; 854 855 afterCal = java.util.Calendar.getInstance(getTimeZone()); 856 afterCal.setTime(afterDate); 857 858 currCal = java.util.Calendar.getInstance(getTimeZone()); 859 currCal.set(afterCal.get(java.util.Calendar.YEAR), 860 afterCal.get(java.util.Calendar.MONTH), 1); 861 currCal.set(java.util.Calendar.HOUR_OF_DAY, this.fireAtHour); 862 currCal.set(java.util.Calendar.MINUTE, this.fireAtMinute); 863 currCal.set(java.util.Calendar.SECOND, this.fireAtSecond); 864 currCal.set(java.util.Calendar.MILLISECOND, 0); 865 866 currMonth = currCal.get(java.util.Calendar.MONTH); 867 868 while ((!gotOne) && (monthCount < this.nextFireCutoffInterval)) { 869 while ((currN != this.n) && (monthCount < 12)) { 870 if (currCal.get(java.util.Calendar.MONTH) != currMonth) { 872 currN = 0; 873 monthCount++; 874 currMonth = currCal.get(java.util.Calendar.MONTH); 875 } 876 877 if ((calendar == null) 881 || (calendar.isTimeIncluded(currCal.getTime().getTime()))) { 882 currN++; 883 } 884 885 if (currN != this.n) { 886 currCal.add(java.util.Calendar.DATE, 1); 887 } 888 889 if ((this.endTime != null) 891 && (currCal.getTime().after(this.endTime))) { 892 return null; 893 } 894 } 895 896 if (currN == this.n) { 900 if (afterDate.before(currCal.getTime())) { 901 gotOne = true; 902 } else { currCal.set(java.util.Calendar.DAY_OF_MONTH, 1); 904 currCal.add(java.util.Calendar.MONTH, 1); 905 currN = 0; 906 } 907 } 908 } 909 910 if (monthCount < this.nextFireCutoffInterval) { 911 return currCal.getTime(); 912 } else { 913 return null; 914 } 915 } 916 917 930 private Date getYearlyFireTimeAfter(Date afterDate) { 931 int currN = 0; 932 java.util.Calendar afterCal; 933 java.util.Calendar currCal; 934 int currYear; 935 int yearCount = 0; 936 boolean gotOne = false; 937 938 afterCal = java.util.Calendar.getInstance(getTimeZone()); 939 afterCal.setTime(afterDate); 940 941 currCal = java.util.Calendar.getInstance(getTimeZone()); 942 currCal.set(afterCal.get(java.util.Calendar.YEAR), 943 java.util.Calendar.JANUARY, 1); 944 currCal.set(java.util.Calendar.HOUR_OF_DAY, this.fireAtHour); 945 currCal.set(java.util.Calendar.MINUTE, this.fireAtMinute); 946 currCal.set(java.util.Calendar.SECOND, this.fireAtSecond); 947 currCal.set(java.util.Calendar.MILLISECOND, 0); 948 949 currYear = currCal.get(java.util.Calendar.YEAR); 950 951 while ((!gotOne) && (yearCount < this.nextFireCutoffInterval)) { 952 while ((currN != this.n) && (yearCount < 5)) { 953 if (currCal.get(java.util.Calendar.YEAR) != currYear) { 955 currN = 0; 956 yearCount++; 957 currYear = currCal.get(java.util.Calendar.YEAR); 958 } 959 960 if ((calendar == null) 964 || (calendar.isTimeIncluded(currCal.getTime().getTime()))) { 965 currN++; 966 } 967 968 if (currN != this.n) { 969 currCal.add(java.util.Calendar.DATE, 1); 970 } 971 972 if ((this.endTime != null) 974 && (currCal.getTime().after(this.endTime))) { 975 return null; 976 } 977 } 978 979 if (currN == this.n) { 983 if (afterDate.before(currCal.getTime())) { 984 gotOne = true; 985 } else { currCal.set(java.util.Calendar.DAY_OF_MONTH, 1); 987 currCal.set(java.util.Calendar.MONTH, 988 java.util.Calendar.JANUARY); 989 currCal.add(java.util.Calendar.YEAR, 1); 990 currN = 0; 991 } 992 } 993 } 994 995 if (yearCount < this.nextFireCutoffInterval) { 996 return currCal.getTime(); 997 } else { 998 return null; 999 } 1000 } 1001} | Popular Tags |