1 25 package org.ofbiz.service.calendar; 26 27 import java.util.Arrays ; 28 import java.util.Calendar ; 29 import java.util.Date ; 30 import java.util.Iterator ; 31 import java.util.List ; 32 33 import org.ofbiz.base.util.Debug; 34 import org.ofbiz.base.util.StringUtil; 35 import org.ofbiz.base.util.UtilMisc; 36 import org.ofbiz.entity.GenericDelegator; 37 import org.ofbiz.entity.GenericEntityException; 38 import org.ofbiz.entity.GenericValue; 39 40 47 public class RecurrenceRule { 48 49 public static final String module = RecurrenceRule.class.getName(); 50 51 public static final int MIN_SEC = 0; 55 public static final int MAX_SEC = 59; 56 public static final int MIN_MIN = 0; 57 public static final int MAX_MIN = 59; 58 public static final int MIN_HR = 0; 59 public static final int MAX_HR = 23; 60 public static final int MIN_MTH_DAY = -31; 61 public static final int MAX_MTH_DAY = 31; 62 public static final int MIN_YEAR_DAY = -366; 63 public static final int MAX_YEAR_DAY = 366; 64 public static final int MIN_WEEK_NO = -53; 65 public static final int MAX_WEEK_NO = 53; 66 public static final int MIN_MTH = 1; 67 public static final int MAX_MTH = 12; 68 69 73 public static final int SECONDLY = 1; 74 75 76 public static final int MINUTELY = 2; 77 78 79 public static final int HOURLY = 3; 80 81 82 public static final int DAILY = 4; 83 84 85 public static final int WEEKLY = 5; 86 87 88 public static final int MONTHLY = 6; 89 90 91 public static final int YEARLY = 7; 92 93 protected GenericValue rule; 97 98 protected List bySecondList; 102 protected List byMinuteList; 103 protected List byHourList; 104 protected List byDayList; 105 protected List byMonthDayList; 106 protected List byYearDayList; 107 protected List byWeekNoList; 108 protected List byMonthList; 109 protected List bySetPosList; 110 111 115 public RecurrenceRule(GenericValue rule) throws RecurrenceRuleException { 116 this.rule = rule; 117 if (!rule.getEntityName().equals("RecurrenceRule")) 118 throw new RecurrenceRuleException("Invalid RecurrenceRule Value object."); 119 init(); 120 } 121 122 126 public void init() throws RecurrenceRuleException { 127 String freq = rule.getString("frequency"); 129 130 if (!checkFreq(freq)) 131 throw new RecurrenceRuleException("Recurrence FREQUENCY is a required parameter."); 132 if (rule.getLong("intervalNumber").longValue() < 1) 133 throw new RecurrenceRuleException("Recurrence INTERVAL must be a positive integer."); 134 135 bySecondList = StringUtil.split(rule.getString("bySecondList"), ","); 137 byMinuteList = StringUtil.split(rule.getString("byMinuteList"), ","); 138 byHourList = StringUtil.split(rule.getString("byHourList"), ","); 139 byDayList = StringUtil.split(rule.getString("byDayList"), ","); 140 byMonthDayList = StringUtil.split(rule.getString("byMonthDayList"), ","); 141 byYearDayList = StringUtil.split(rule.getString("byYearDayList"), ","); 142 byWeekNoList = StringUtil.split(rule.getString("byWeekNoList"), ","); 143 byMonthList = StringUtil.split(rule.getString("byMonthList"), ","); 144 bySetPosList = StringUtil.split(rule.getString("bySetPosList"), ","); 145 } 146 147 private boolean checkFreq(String freq) { 149 if (freq == null) 150 return false; 151 if (freq.equalsIgnoreCase("SECONDLY")) 152 return true; 153 if (freq.equalsIgnoreCase("MINUTELY")) 154 return true; 155 if (freq.equalsIgnoreCase("HOURLY")) 156 return true; 157 if (freq.equalsIgnoreCase("DAILY")) 158 return true; 159 if (freq.equalsIgnoreCase("WEEKLY")) 160 return true; 161 if (freq.equalsIgnoreCase("MONTHLY")) 162 return true; 163 if (freq.equalsIgnoreCase("YEARLY")) 164 return true; 165 return false; 166 } 167 168 172 public long getEndTime() { 173 if (rule == null) { 174 Debug.logVerbose("Rule is null.", module); 175 return -1; 176 } 177 long time = 0; 178 java.sql.Timestamp stamp = null; 179 180 stamp = rule.getTimestamp("untilDateTime"); 181 Debug.logVerbose("Stamp value: " + stamp, module); 182 183 if (stamp != null) { 184 long nanos = (long) stamp.getNanos(); 185 time = stamp.getTime(); 186 time += (nanos / 1000000); 187 } 188 Debug.logVerbose("Returning time: " + time, module); 189 return time; 190 } 191 192 196 public long getCount() { 197 if (rule.get("countNumber") != null) 198 return rule.getLong("countNumber").longValue(); 199 return 0; 200 } 201 202 206 public String getFrequencyName() { 207 return rule.getString("frequency").toUpperCase(); 208 } 209 210 214 public int getFrequency() { 215 String freq = rule.getString("frequency"); 216 217 if (freq == null) 218 return 0; 219 if (freq.equalsIgnoreCase("SECONDLY")) 220 return SECONDLY; 221 if (freq.equalsIgnoreCase("MINUTELY")) 222 return MINUTELY; 223 if (freq.equalsIgnoreCase("HOURLY")) 224 return HOURLY; 225 if (freq.equalsIgnoreCase("DAILY")) 226 return DAILY; 227 if (freq.equalsIgnoreCase("WEEKLY")) 228 return WEEKLY; 229 if (freq.equalsIgnoreCase("MONTHLY")) 230 return MONTHLY; 231 if (freq.equalsIgnoreCase("YEARLY")) 232 return YEARLY; 233 return 0; 234 } 235 236 240 public long getInterval() { 241 if (rule.get("intervalNumber") == null) 242 return 1; 243 return rule.getLong("intervalNumber").longValue(); 244 } 245 246 250 public int getIntervalInt() { 251 return (int) getInterval(); 253 } 254 255 262 public long next(long startTime, long fromTime, long currentCount) { 263 if (startTime == 0) 265 startTime = RecurrenceUtil.now(); 266 if (fromTime == 0) 267 fromTime = startTime; 268 269 if (getEndTime() != 0 && getEndTime() <= RecurrenceUtil.now()) 271 return 0; 272 Debug.logVerbose("Rule NOT expired by end time.", module); 273 274 if (getCount() != -1 && currentCount >= getCount()) 276 return 0; 277 Debug.logVerbose("Rule NOT expired by max count.", module); 278 279 boolean isSeeking = true; 280 long nextRuntime = 0; 281 long seekTime = fromTime; 282 int loopProtection = 0; 283 int maxLoop = (10 * 10 * 10 * 10 * 10); 284 285 while (isSeeking && loopProtection < maxLoop) { 286 Date nextRun = getNextFreq(startTime, seekTime); 287 seekTime = nextRun.getTime(); 288 if (validByRule(nextRun)) { 289 isSeeking = false; 290 nextRuntime = nextRun.getTime(); 291 } 292 loopProtection++; 293 } 294 return nextRuntime; 295 } 296 297 302 public boolean isValid(Date startDate, Date date) { 303 return isValid(startDate.getTime(), date.getTime()); 304 } 305 306 311 public boolean isValid(long startTime, long dateTime) { 312 long testTime = startTime; 313 314 if (testTime == dateTime) 315 return true; 316 while (testTime < dateTime) { 317 testTime = next(startTime, testTime, 1); 318 if (testTime == dateTime) 319 return true; 320 } 321 return false; 322 } 323 324 328 public void remove() throws RecurrenceRuleException { 329 try { 330 rule.remove(); 331 } catch (GenericEntityException e) { 332 throw new RecurrenceRuleException(e.getMessage(), e); 333 } 334 } 335 336 private Date getNextFreq(long startTime, long fromTime) { 338 Calendar cal = Calendar.getInstance(); 340 341 cal.setTime(new Date (startTime)); 342 343 long nextStartTime = startTime; 344 345 while (nextStartTime < fromTime) { 346 switch (getFrequency()) { 348 case SECONDLY: 349 cal.add(Calendar.SECOND, getIntervalInt()); 350 break; 351 352 case MINUTELY: 353 cal.add(Calendar.MINUTE, getIntervalInt()); 354 break; 355 356 case HOURLY: 357 cal.add(Calendar.HOUR, getIntervalInt()); 358 break; 359 360 case DAILY: 361 cal.add(Calendar.DAY_OF_MONTH, getIntervalInt()); 362 break; 363 364 case WEEKLY: 365 cal.add(Calendar.WEEK_OF_YEAR, getIntervalInt()); 366 break; 367 368 case MONTHLY: 369 cal.add(Calendar.MONTH, getIntervalInt()); 370 break; 371 372 case YEARLY: 373 cal.add(Calendar.YEAR, getIntervalInt()); 374 break; 375 376 default: 377 return null; } 379 nextStartTime = cal.getTime().getTime(); 380 } 381 return new Date (nextStartTime); 382 } 383 384 private boolean validByRule(Date date) { 386 Calendar cal = Calendar.getInstance(); 388 389 cal.setTime(date); 390 391 if (bySecondList != null && bySecondList.size() > 0) { 393 if (!bySecondList.contains(new Integer (cal.get(Calendar.SECOND)))) 394 return false; 395 } 396 if (byMinuteList != null && byMinuteList.size() > 0) { 397 if (!byMinuteList.contains(new Integer (cal.get(Calendar.MINUTE)))) 398 return false; 399 } 400 if (byHourList != null && byHourList.size() > 0) { 401 if (!byHourList.contains(new Integer (cal.get(Calendar.HOUR)))) 402 return false; 403 } 404 if (byDayList != null && byDayList.size() > 0) { 405 Iterator iter = byDayList.iterator(); 406 boolean foundDay = false; 407 408 while (iter.hasNext() && !foundDay) { 409 String dayRule = (String ) iter.next(); 410 String dayString = getDailyString(dayRule); 411 412 if (Calendar.DAY_OF_WEEK == getCalendarDay(dayString)) { 413 if ((hasNumber(dayRule)) && (getFrequency() == MONTHLY || getFrequency() == YEARLY)) { 414 int modifier = getDailyNumber(dayRule); 415 416 if (modifier == 0) 417 foundDay = true; 418 419 if (getFrequency() == MONTHLY) { 420 int currentPos = cal.get(Calendar.WEEK_OF_MONTH); 422 int dayPosCalc = cal.get(Calendar.DAY_OF_MONTH) - ((currentPos - 1) * 7); 423 424 if (dayPosCalc < 1) 425 currentPos--; 426 if (modifier > 0) { 427 if (currentPos == modifier) { 428 foundDay = true; 429 } 430 } else if (modifier < 0) { 431 int maxDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH); 432 int firstDay = dayPosCalc > 0 ? dayPosCalc : dayPosCalc + 7; 433 int totalDay = ((maxDay - firstDay) / 7) + 1; 434 int thisDiff = (currentPos - totalDay) - 1; 435 436 if (thisDiff == modifier) { 437 foundDay = true; 438 } 439 } 440 } else if (getFrequency() == YEARLY) { 441 int currentPos = cal.get(Calendar.WEEK_OF_YEAR); 443 int dayPosCalc = cal.get(Calendar.DAY_OF_YEAR) - ((currentPos - 1) * 7); 444 445 if (dayPosCalc < 1) { 446 currentPos--; 447 } 448 if (modifier > 0) { 449 if (currentPos == modifier) { 450 foundDay = true; 451 } 452 } else if (modifier < 0) { 453 int maxDay = cal.getActualMaximum(Calendar.DAY_OF_YEAR); 454 int firstDay = dayPosCalc > 0 ? dayPosCalc : dayPosCalc + 7; 455 int totalDay = ((maxDay - firstDay) / 7) + 1; 456 int thisDiff = (currentPos - totalDay) - 1; 457 458 if (thisDiff == modifier) { 459 foundDay = true; 460 } 461 } 462 } 463 } else { 464 foundDay = true; 466 } 467 } 468 } 469 if (!foundDay) { 470 return false; 471 } 472 } 473 if (byMonthDayList != null && byMonthDayList.size() > 0) { 474 Iterator iter = byMonthDayList.iterator(); 475 boolean foundDay = false; 476 477 while (iter.hasNext() && !foundDay) { 478 int day = 0; 479 String dayStr = (String ) iter.next(); 480 481 try { 482 day = Integer.parseInt(dayStr); 483 } catch (NumberFormatException nfe) { 484 Debug.logError(nfe, "Error parsing day string " + dayStr + ": " + nfe.toString(), module); 485 } 486 int maxDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH); 487 int currentDay = cal.get(Calendar.DAY_OF_MONTH); 488 489 if (day > 0 && day == currentDay) { 490 foundDay = true; 491 } 492 if (day < 0 && day == ((currentDay - maxDay) - 1)) { 493 foundDay = true; 494 } 495 } 496 if (!foundDay) { 497 return false; 498 } 499 } 500 if (byYearDayList != null && byYearDayList.size() > 0) { 501 Iterator iter = byYearDayList.iterator(); 502 boolean foundDay = false; 503 504 while (iter.hasNext() && !foundDay) { 505 int day = 0; 506 String dayStr = (String ) iter.next(); 507 508 try { 509 day = Integer.parseInt(dayStr); 510 } catch (NumberFormatException nfe) { 511 Debug.logError(nfe, "Error parsing day string " + dayStr + ": " + nfe.toString(), module); 512 } 513 int maxDay = cal.getActualMaximum(Calendar.DAY_OF_YEAR); 514 int currentDay = cal.get(Calendar.DAY_OF_YEAR); 515 516 if (day > 0 && day == currentDay) 517 foundDay = true; 518 if (day < 0 && day == ((currentDay - maxDay) - 1)) 519 foundDay = true; 520 } 521 if (!foundDay) 522 return false; 523 } 524 if (byWeekNoList != null && byWeekNoList.size() > 0) { 525 Iterator iter = byWeekNoList.iterator(); 526 boolean foundWeek = false; 527 528 while (iter.hasNext() && !foundWeek) { 529 int week = 0; 530 String weekStr = (String ) iter.next(); 531 532 try { 533 week = Integer.parseInt(weekStr); 534 } catch (NumberFormatException nfe) { 535 Debug.logError(nfe, "Error parsing week string " + weekStr + ": " + nfe.toString(), module); 536 } 537 int maxWeek = cal.getActualMaximum(Calendar.WEEK_OF_YEAR); 538 int currentWeek = cal.get(Calendar.WEEK_OF_YEAR); 539 540 if (week > 0 && week == currentWeek) 541 foundWeek = true; 542 if (week < 0 && week == ((currentWeek - maxWeek) - 1)) 543 foundWeek = true; 544 } 545 if (!foundWeek) 546 return false; 547 } 548 if (byMonthList != null && byMonthList.size() > 0) { 549 Iterator iter = byMonthList.iterator(); 550 boolean foundMonth = false; 551 552 while (iter.hasNext() && !foundMonth) { 553 int month = 0; 554 String monthStr = (String ) iter.next(); 555 556 try { 557 month = Integer.parseInt(monthStr); 558 } catch (NumberFormatException nfe) { 559 Debug.logError(nfe, "Error parsing month string " + monthStr + ": " + nfe.toString(), module); 560 } 561 if (month == cal.get(Calendar.MONTH)) { 562 foundMonth = true; 563 } 564 } 565 if (!foundMonth) 566 return false; 567 } 568 569 return true; 570 } 571 572 private boolean hasNumber(String str) { 574 String list[] = {"+", "-", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"}; 575 List numberList = Arrays.asList(list); 576 String firstChar = str.substring(0, 0); 577 578 if (numberList.contains(firstChar)) 579 return true; 580 return false; 581 } 582 583 private int getDailyNumber(String str) { 585 int number = 0; 586 StringBuffer numberBuf = new StringBuffer (); 587 588 for (int i = 0; i < str.length(); i++) { 589 String thisChar = str.substring(i, i); 590 591 if (hasNumber(thisChar)) 592 numberBuf.append(thisChar); 593 } 594 String numberStr = numberBuf.toString(); 595 596 if (numberStr.length() > 0 && (numberStr.length() > 1 || 597 (numberStr.charAt(0) != '+' && numberStr.charAt(0) != '-'))) { 598 try { 599 number = Integer.parseInt(numberStr); 600 } catch (NumberFormatException nfe) { 601 Debug.logError(nfe, "Error parsing daily number string " + numberStr + ": " + nfe.toString(), module); 602 } 603 } 604 return number; 605 } 606 607 private String getDailyString(String str) { 609 StringBuffer sBuf = new StringBuffer (); 610 611 for (int i = 0; i < str.length(); i++) { 612 String thisChar = str.substring(i, i); 613 614 if (!hasNumber(thisChar)) { 615 sBuf.append(thisChar); 616 } 617 } 618 return sBuf.toString(); 619 } 620 621 private int getCalendarDay(String day) { 623 if (day.equalsIgnoreCase("MO")) 624 return Calendar.MONDAY; 625 if (day.equalsIgnoreCase("TU")) 626 return Calendar.TUESDAY; 627 if (day.equalsIgnoreCase("WE")) 628 return Calendar.WEDNESDAY; 629 if (day.equalsIgnoreCase("TH")) 630 return Calendar.THURSDAY; 631 if (day.equalsIgnoreCase("FR")) 632 return Calendar.FRIDAY; 633 if (day.equalsIgnoreCase("SA")) 634 return Calendar.SATURDAY; 635 if (day.equalsIgnoreCase("SU")) 636 return Calendar.SUNDAY; 637 return 0; 638 } 639 640 public String primaryKey() { 641 return rule.getString("recurrenceRuleId"); 642 } 643 644 public static RecurrenceRule makeRule(GenericDelegator delegator, int frequency, int interval, int count) 645 throws RecurrenceRuleException { 646 return makeRule(delegator, frequency, interval, count, 0); 647 } 648 649 public static RecurrenceRule makeRule(GenericDelegator delegator, int frequency, int interval, long endTime) 650 throws RecurrenceRuleException { 651 return makeRule(delegator, frequency, interval, -1, endTime); 652 } 653 654 public static RecurrenceRule makeRule(GenericDelegator delegator, int frequency, int interval, int count, long endTime) 655 throws RecurrenceRuleException { 656 String freq[] = {"", "SECONDLY", "MINUTELY", "HOURLY", "DAILY", "WEEKLY", "MONTHLY", "YEARLY"}; 657 658 if (frequency < 1 || frequency > 7) 659 throw new RecurrenceRuleException("Invalid frequency"); 660 if (interval < 0) 661 throw new RecurrenceRuleException("Invalid interval"); 662 663 String freqStr = freq[frequency]; 664 665 try { 666 String ruleId = delegator.getNextSeqId("RecurrenceRule").toString(); 667 GenericValue value = delegator.makeValue("RecurrenceRule", UtilMisc.toMap("recurrenceRuleId", ruleId)); 668 669 value.set("frequency", freqStr); 670 value.set("intervalNumber", new Long (interval)); 671 value.set("countNumber", new Long (count)); 672 if (endTime > 0) { 673 value.set("untilDateTime", new java.sql.Timestamp (endTime)); 674 } 675 delegator.create(value); 676 RecurrenceRule newRule = new RecurrenceRule(value); 677 678 return newRule; 679 } catch (GenericEntityException ee) { 680 throw new RecurrenceRuleException(ee.getMessage(), ee); 681 } catch (RecurrenceRuleException re) { 682 throw re; 683 } 684 } 685 } 686 | Popular Tags |