| /******************************************************************************* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.ofbiz.service.calendar; |
| |
| import java.util.Arrays; |
| import com.ibm.icu.util.Calendar; |
| import java.util.Date; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.apache.ofbiz.base.util.Debug; |
| import org.apache.ofbiz.base.util.StringUtil; |
| import org.apache.ofbiz.base.util.UtilValidate; |
| import org.apache.ofbiz.entity.Delegator; |
| import org.apache.ofbiz.entity.GenericEntityException; |
| import org.apache.ofbiz.entity.GenericValue; |
| |
| /** |
| * Recurrence Rule Object |
| */ |
| public class RecurrenceRule { |
| |
| public static final String module = RecurrenceRule.class.getName(); |
| |
| // ********************** |
| // * byXXX constants |
| // ********************** |
| public static final int MIN_SEC = 0; |
| public static final int MAX_SEC = 59; |
| public static final int MIN_MIN = 0; |
| public static final int MAX_MIN = 59; |
| public static final int MIN_HR = 0; |
| public static final int MAX_HR = 23; |
| public static final int MIN_MTH_DAY = -31; |
| public static final int MAX_MTH_DAY = 31; |
| public static final int MIN_YEAR_DAY = -366; |
| public static final int MAX_YEAR_DAY = 366; |
| public static final int MIN_WEEK_NO = -53; |
| public static final int MAX_WEEK_NO = 53; |
| public static final int MIN_MTH = 1; |
| public static final int MAX_MTH = 12; |
| |
| // ********************** |
| // * Frequency constants |
| // ********************** |
| /** Frequency SECONDLY */ |
| public static final int SECONDLY = 1; |
| |
| /** Frequency MINUTELY */ |
| public static final int MINUTELY = 2; |
| |
| /** Frequency HOURLY */ |
| public static final int HOURLY = 3; |
| |
| /** Frequency DAILY */ |
| public static final int DAILY = 4; |
| |
| /** Frequency WEEKLY */ |
| public static final int WEEKLY = 5; |
| |
| /** Frequency MONTHLY */ |
| public static final int MONTHLY = 6; |
| |
| /** Frequency YEARLY */ |
| public static final int YEARLY = 7; |
| |
| // ********************** |
| // * GenericValue object |
| // ********************** |
| protected GenericValue rule; |
| |
| // ********************** |
| // * Parsed byXXX lists |
| // ********************** |
| protected List<String> bySecondList; |
| protected List<String> byMinuteList; |
| protected List<String> byHourList; |
| protected List<String> byDayList; |
| protected List<String> byMonthDayList; |
| protected List<String> byYearDayList; |
| protected List<String> byWeekNoList; |
| protected List<String> byMonthList; |
| protected List<String> bySetPosList; |
| |
| /** |
| * Creates a new RecurrenceRule object from a RecurrenceInfo entity. |
| *@param rule GenericValue object defining this rule. |
| */ |
| public RecurrenceRule(GenericValue rule) throws RecurrenceRuleException { |
| this.rule = rule; |
| if (!rule.getEntityName().equals("RecurrenceRule")) |
| throw new RecurrenceRuleException("Invalid RecurrenceRule Value object."); |
| init(); |
| } |
| |
| /** |
| * Initializes the rules for this RecurrenceInfo object. |
| *@throws RecurrenceRuleException |
| */ |
| public void init() throws RecurrenceRuleException { |
| // Check the validity of the rule |
| String freq = rule.getString("frequency"); |
| |
| if (!checkFreq(freq)) |
| throw new RecurrenceRuleException("Recurrence FREQUENCY is a required parameter."); |
| if (rule.getLong("intervalNumber").longValue() < 1) |
| throw new RecurrenceRuleException("Recurrence INTERVAL must be a positive integer."); |
| |
| // Initialize the byXXX lists |
| bySecondList = StringUtil.split(rule.getString("bySecondList"), ","); |
| byMinuteList = StringUtil.split(rule.getString("byMinuteList"), ","); |
| byHourList = StringUtil.split(rule.getString("byHourList"), ","); |
| byDayList = StringUtil.split(rule.getString("byDayList"), ","); |
| byMonthDayList = StringUtil.split(rule.getString("byMonthDayList"), ","); |
| byYearDayList = StringUtil.split(rule.getString("byYearDayList"), ","); |
| byWeekNoList = StringUtil.split(rule.getString("byWeekNoList"), ","); |
| byMonthList = StringUtil.split(rule.getString("byMonthList"), ","); |
| bySetPosList = StringUtil.split(rule.getString("bySetPosList"), ","); |
| } |
| |
| // Checks for a valid frequency property. |
| private boolean checkFreq(String freq) { |
| if (freq == null) |
| return false; |
| if (freq.equalsIgnoreCase("SECONDLY")) |
| return true; |
| if (freq.equalsIgnoreCase("MINUTELY")) |
| return true; |
| if (freq.equalsIgnoreCase("HOURLY")) |
| return true; |
| if (freq.equalsIgnoreCase("DAILY")) |
| return true; |
| if (freq.equalsIgnoreCase("WEEKLY")) |
| return true; |
| if (freq.equalsIgnoreCase("MONTHLY")) |
| return true; |
| if (freq.equalsIgnoreCase("YEARLY")) |
| return true; |
| return false; |
| } |
| |
| /** |
| * Gets the end time of the recurrence rule or 0 if none. |
| *@return long The timestamp of the end time for this rule or 0 for none. |
| */ |
| public long getEndTime() { |
| if (rule == null) { |
| Debug.logVerbose("Rule is null.", module); |
| return -1; |
| } |
| long time = 0; |
| java.sql.Timestamp stamp = null; |
| |
| stamp = rule.getTimestamp("untilDateTime"); |
| Debug.logVerbose("Stamp value: " + stamp, module); |
| |
| if (stamp != null) { |
| long nanos = stamp.getNanos(); |
| time = stamp.getTime(); |
| time += (nanos / 1000000); |
| } |
| Debug.logVerbose("Returning time: " + time, module); |
| return time; |
| } |
| |
| /** |
| * Get the number of times this recurrence will run (-1 until end time). |
| *@return long The number of time this recurrence will run. |
| */ |
| public long getCount() { |
| if (rule.get("countNumber") != null) |
| return rule.getLong("countNumber").longValue(); |
| return 0; |
| } |
| |
| /** |
| * Returns the frequency name of the recurrence. |
| *@return String The name of this frequency. |
| */ |
| public String getFrequencyName() { |
| return rule.getString("frequency").toUpperCase(); |
| } |
| |
| /** |
| * Returns the frequency of this recurrence. |
| *@return int The reference value for the frequency |
| */ |
| public int getFrequency() { |
| String freq = rule.getString("frequency"); |
| |
| if (freq == null) |
| return 0; |
| if (freq.equalsIgnoreCase("SECONDLY")) |
| return SECONDLY; |
| if (freq.equalsIgnoreCase("MINUTELY")) |
| return MINUTELY; |
| if (freq.equalsIgnoreCase("HOURLY")) |
| return HOURLY; |
| if (freq.equalsIgnoreCase("DAILY")) |
| return DAILY; |
| if (freq.equalsIgnoreCase("WEEKLY")) |
| return WEEKLY; |
| if (freq.equalsIgnoreCase("MONTHLY")) |
| return MONTHLY; |
| if (freq.equalsIgnoreCase("YEARLY")) |
| return YEARLY; |
| return 0; |
| } |
| |
| /** |
| * Returns the interval of the frequency. |
| *@return long Interval value |
| */ |
| public long getInterval() { |
| if (rule.get("intervalNumber") == null) |
| return 1; |
| return rule.getLong("intervalNumber").longValue(); |
| } |
| |
| /** |
| * Returns the interval of the frequency as an int. |
| *@return The interval of this frequency as an integer. |
| */ |
| public int getIntervalInt() { |
| // if (Debug.verboseOn()) Debug.logVerbose("[RecurrenceInfo.getInterval] : " + getInterval(), module); |
| return (int) getInterval(); |
| } |
| |
| /** |
| * Returns the next recurrence of this rule. |
| *@param startTime The time this recurrence first began. |
| *@param fromTime The time to base the next recurrence on. |
| *@param currentCount The total number of times the recurrence has run. |
| *@return long The next recurrence as a long. |
| */ |
| public long next(long startTime, long fromTime, long currentCount) { |
| // Set up the values |
| if (startTime == 0) |
| startTime = RecurrenceUtil.now(); |
| if (fromTime == 0) |
| fromTime = startTime; |
| |
| // Test the end time of the recurrence. |
| if (getEndTime() != 0 && getEndTime() <= RecurrenceUtil.now()) |
| return 0; |
| Debug.logVerbose("Rule NOT expired by end time.", module); |
| |
| // Test the recurrence limit. |
| if (getCount() != -1 && currentCount >= getCount()) |
| return 0; |
| Debug.logVerbose("Rule NOT expired by max count.", module); |
| |
| boolean isSeeking = true; |
| long nextRuntime = 0; |
| long seekTime = fromTime; |
| int loopProtection = 0; |
| int maxLoop = (10 * 10 * 10 * 10 * 10); |
| |
| while (isSeeking && loopProtection < maxLoop) { |
| Date nextRun = getNextFreq(startTime, seekTime); |
| seekTime = nextRun.getTime(); |
| if (validByRule(nextRun)) { |
| isSeeking = false; |
| nextRuntime = nextRun.getTime(); |
| } |
| loopProtection++; |
| } |
| return nextRuntime; |
| } |
| |
| /** |
| * Gets the current recurrence (current for the checkTime) of this rule and returns it if it is valid. |
| * If the current recurrence is not valid, doesn't try to find a valid one, instead returns 0. |
| *@param startTime The time this recurrence first began. |
| *@param checkTime The time to base the current recurrence on. |
| *@param currentCount The total number of times the recurrence has run. |
| *@return long The current recurrence as long if valid. If next recurrence is not valid, returns 0. |
| */ |
| public long validCurrent(long startTime, long checkTime, long currentCount) { |
| if (startTime == 0) { |
| startTime = RecurrenceUtil.now(); |
| } |
| if (checkTime == 0) { |
| checkTime = startTime; |
| } |
| |
| // Test the end time of the recurrence. |
| if (getEndTime() != 0 && getEndTime() <= RecurrenceUtil.now()) { |
| return 0; |
| } |
| |
| // Test the recurrence limit. |
| if (getCount() != -1 && currentCount >= getCount()) { |
| return 0; |
| } |
| |
| // Get the next frequency from checkTime |
| Date nextRun = getNextFreq(startTime, checkTime); |
| Calendar cal = Calendar.getInstance(); |
| Calendar checkTimeCal = Calendar.getInstance(); |
| cal.setTime(nextRun); |
| checkTimeCal.setTime(new Date(checkTime)); |
| |
| // Get previous frequency and update its values from checkTime |
| switch (getFrequency()) { |
| case YEARLY: |
| cal.add(Calendar.YEAR, -getIntervalInt()); |
| if (cal.get(Calendar.YEAR) != checkTimeCal.get(Calendar.YEAR)) { |
| return 0; |
| } |
| |
| case MONTHLY: |
| if (MONTHLY == getFrequency()) { |
| cal.add(Calendar.MONTH, -getIntervalInt()); |
| if (cal.get(Calendar.MONTH) != checkTimeCal.get(Calendar.MONTH)) { |
| return 0; |
| } |
| } else { |
| cal.set(Calendar.MONTH, checkTimeCal.get(Calendar.MONTH)); |
| } |
| |
| case WEEKLY: |
| if (WEEKLY == getFrequency()) { |
| cal.add(Calendar.WEEK_OF_YEAR, -getIntervalInt()); |
| if (cal.get(Calendar.WEEK_OF_YEAR) != checkTimeCal.get(Calendar.WEEK_OF_YEAR)) { |
| return 0; |
| } |
| } else { |
| cal.set(Calendar.WEEK_OF_YEAR, checkTimeCal.get(Calendar.WEEK_OF_YEAR)); |
| } |
| |
| case DAILY: |
| if (DAILY == getFrequency()) { |
| cal.add(Calendar.DAY_OF_MONTH, -getIntervalInt()); |
| if (cal.get(Calendar.DAY_OF_MONTH) != checkTimeCal.get(Calendar.DAY_OF_MONTH)) { |
| return 0; |
| } |
| } else { |
| cal.set(Calendar.DAY_OF_MONTH, checkTimeCal.get(Calendar.DAY_OF_MONTH)); |
| } |
| |
| case HOURLY: |
| if (HOURLY == getFrequency()) { |
| cal.add(Calendar.HOUR_OF_DAY, -getIntervalInt()); |
| if (cal.get(Calendar.HOUR_OF_DAY) != checkTimeCal.get(Calendar.HOUR_OF_DAY)) { |
| return 0; |
| } |
| } else { |
| cal.set(Calendar.HOUR_OF_DAY, checkTimeCal.get(Calendar.HOUR_OF_DAY)); |
| } |
| |
| case MINUTELY: |
| if (MINUTELY == getFrequency()) { |
| cal.add(Calendar.MINUTE, -getIntervalInt()); |
| if (cal.get(Calendar.MINUTE) != checkTimeCal.get(Calendar.MINUTE)) { |
| return 0; |
| } |
| } else { |
| cal.set(Calendar.MINUTE, checkTimeCal.get(Calendar.MINUTE)); |
| } |
| |
| case SECONDLY: |
| if (SECONDLY == getFrequency()) { |
| cal.add(Calendar.SECOND, -getIntervalInt()); |
| if (cal.get(Calendar.SECOND) != checkTimeCal.get(Calendar.SECOND)) { |
| return 0; |
| } |
| } else { |
| cal.set(Calendar.SECOND, checkTimeCal.get(Calendar.SECOND)); |
| } |
| } |
| |
| // Check for validity of the current frequency. |
| if (validByRule(cal.getTime())) { |
| return cal.getTime().getTime(); |
| } |
| |
| return 0; |
| } |
| |
| /** |
| * Tests the date to see if it falls within the rules |
| *@param startDate date object to test |
| *@return True if the date is within the rules |
| */ |
| public boolean isValid(Date startDate, Date date) { |
| return isValid(startDate.getTime(), date.getTime()); |
| } |
| |
| /** |
| * Tests the date to see if it falls within the rules |
| *@param startTime date object to test |
| *@return True if the date is within the rules |
| */ |
| public boolean isValid(long startTime, long dateTime) { |
| long testTime = startTime; |
| |
| if (testTime == dateTime) |
| return true; |
| while (testTime < dateTime) { |
| testTime = next(startTime, testTime, 1); |
| if (testTime == dateTime) |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Removes this rule from the persistant store. |
| *@throws RecurrenceRuleException |
| */ |
| public void remove() throws RecurrenceRuleException { |
| try { |
| rule.remove(); |
| } catch (GenericEntityException e) { |
| throw new RecurrenceRuleException(e.getMessage(), e); |
| } |
| } |
| |
| // Gets the next frequency/interval recurrence from specified time |
| private Date getNextFreq(long startTime, long fromTime) { |
| // Build a Calendar object |
| Calendar cal = Calendar.getInstance(); |
| |
| cal.setTime(new Date(startTime)); |
| |
| long nextStartTime = startTime; |
| |
| while (nextStartTime < fromTime) { |
| // if (Debug.verboseOn()) Debug.logVerbose("[RecurrenceInfo.getNextFreq] : Updating time - " + getFrequency(), module); |
| switch (getFrequency()) { |
| case SECONDLY: |
| cal.add(Calendar.SECOND, getIntervalInt()); |
| break; |
| |
| case MINUTELY: |
| cal.add(Calendar.MINUTE, getIntervalInt()); |
| break; |
| |
| case HOURLY: |
| cal.add(Calendar.HOUR_OF_DAY, getIntervalInt()); |
| break; |
| |
| case DAILY: |
| cal.add(Calendar.DAY_OF_MONTH, getIntervalInt()); |
| break; |
| |
| case WEEKLY: |
| cal.add(Calendar.WEEK_OF_YEAR, getIntervalInt()); |
| break; |
| |
| case MONTHLY: |
| cal.add(Calendar.MONTH, getIntervalInt()); |
| break; |
| |
| case YEARLY: |
| cal.add(Calendar.YEAR, getIntervalInt()); |
| break; |
| |
| default: |
| return null; // should never happen |
| } |
| nextStartTime = cal.getTime().getTime(); |
| } |
| return new Date(nextStartTime); |
| } |
| |
| // Checks to see if a date is valid by the byXXX rules |
| private boolean validByRule(Date date) { |
| // Build a Calendar object |
| Calendar cal = Calendar.getInstance(); |
| |
| cal.setTime(date); |
| |
| // Test each byXXX rule. |
| if (UtilValidate.isNotEmpty(bySecondList)) { |
| if (!bySecondList.contains(String.valueOf(cal.get(Calendar.SECOND)))) |
| return false; |
| } |
| if (UtilValidate.isNotEmpty(byMinuteList)) { |
| if (!byMinuteList.contains(String.valueOf(cal.get(Calendar.MINUTE)))) |
| return false; |
| } |
| if (UtilValidate.isNotEmpty(byHourList)) { |
| if (!byHourList.contains(String.valueOf(cal.get(Calendar.HOUR_OF_DAY)))) |
| return false; |
| } |
| if (UtilValidate.isNotEmpty(byDayList)) { |
| Iterator<String> iter = byDayList.iterator(); |
| boolean foundDay = false; |
| |
| while (iter.hasNext() && !foundDay) { |
| String dayRule = iter.next(); |
| String dayString = getDailyString(dayRule); |
| |
| if (cal.get(Calendar.DAY_OF_WEEK) == getCalendarDay(dayString)) { |
| if ((hasNumber(dayRule)) && (getFrequency() == MONTHLY || getFrequency() == YEARLY)) { |
| int modifier = getDailyNumber(dayRule); |
| |
| if (modifier == 0) |
| foundDay = true; |
| |
| if (getFrequency() == MONTHLY) { |
| // figure if we are the nth xDAY if this month |
| int currentPos = cal.get(Calendar.WEEK_OF_MONTH); |
| int dayPosCalc = cal.get(Calendar.DAY_OF_MONTH) - ((currentPos - 1) * 7); |
| |
| if (dayPosCalc < 1) |
| currentPos--; |
| if (modifier > 0) { |
| if (currentPos == modifier) { |
| foundDay = true; |
| } |
| } else if (modifier < 0) { |
| int maxDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH); |
| int firstDay = dayPosCalc > 0 ? dayPosCalc : dayPosCalc + 7; |
| int totalDay = ((maxDay - firstDay) / 7) + 1; |
| int thisDiff = (currentPos - totalDay) - 1; |
| |
| if (thisDiff == modifier) { |
| foundDay = true; |
| } |
| } |
| } else if (getFrequency() == YEARLY) { |
| // figure if we are the nth xDAY if this year |
| int currentPos = cal.get(Calendar.WEEK_OF_YEAR); |
| int dayPosCalc = cal.get(Calendar.DAY_OF_YEAR) - ((currentPos - 1) * 7); |
| |
| if (dayPosCalc < 1) { |
| currentPos--; |
| } |
| if (modifier > 0) { |
| if (currentPos == modifier) { |
| foundDay = true; |
| } |
| } else if (modifier < 0) { |
| int maxDay = cal.getActualMaximum(Calendar.DAY_OF_YEAR); |
| int firstDay = dayPosCalc > 0 ? dayPosCalc : dayPosCalc + 7; |
| int totalDay = ((maxDay - firstDay) / 7) + 1; |
| int thisDiff = (currentPos - totalDay) - 1; |
| |
| if (thisDiff == modifier) { |
| foundDay = true; |
| } |
| } |
| } |
| } else { |
| // we are a DOW only rule |
| foundDay = true; |
| } |
| } |
| } |
| if (!foundDay) { |
| return false; |
| } |
| } |
| if (UtilValidate.isNotEmpty(byMonthDayList)) { |
| Iterator<String> iter = byMonthDayList.iterator(); |
| boolean foundDay = false; |
| |
| while (iter.hasNext() && !foundDay) { |
| int day = 0; |
| String dayStr = iter.next(); |
| |
| try { |
| day = Integer.parseInt(dayStr); |
| } catch (NumberFormatException nfe) { |
| Debug.logError(nfe, "Error parsing day string " + dayStr + ": " + nfe.toString(), module); |
| } |
| int maxDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH); |
| int currentDay = cal.get(Calendar.DAY_OF_MONTH); |
| |
| if (day > 0 && day == currentDay) { |
| foundDay = true; |
| } |
| if (day < 0 && day == ((currentDay - maxDay) - 1)) { |
| foundDay = true; |
| } |
| } |
| if (!foundDay) { |
| return false; |
| } |
| } |
| if (UtilValidate.isNotEmpty(byYearDayList)) { |
| Iterator<String> iter = byYearDayList.iterator(); |
| boolean foundDay = false; |
| |
| while (iter.hasNext() && !foundDay) { |
| int day = 0; |
| String dayStr = iter.next(); |
| |
| try { |
| day = Integer.parseInt(dayStr); |
| } catch (NumberFormatException nfe) { |
| Debug.logError(nfe, "Error parsing day string " + dayStr + ": " + nfe.toString(), module); |
| } |
| int maxDay = cal.getActualMaximum(Calendar.DAY_OF_YEAR); |
| int currentDay = cal.get(Calendar.DAY_OF_YEAR); |
| |
| if (day > 0 && day == currentDay) |
| foundDay = true; |
| if (day < 0 && day == ((currentDay - maxDay) - 1)) |
| foundDay = true; |
| } |
| if (!foundDay) |
| return false; |
| } |
| if (UtilValidate.isNotEmpty(byWeekNoList)) { |
| Iterator<String> iter = byWeekNoList.iterator(); |
| boolean foundWeek = false; |
| |
| while (iter.hasNext() && !foundWeek) { |
| int week = 0; |
| String weekStr = iter.next(); |
| |
| try { |
| week = Integer.parseInt(weekStr); |
| } catch (NumberFormatException nfe) { |
| Debug.logError(nfe, "Error parsing week string " + weekStr + ": " + nfe.toString(), module); |
| } |
| int maxWeek = cal.getActualMaximum(Calendar.WEEK_OF_YEAR); |
| int currentWeek = cal.get(Calendar.WEEK_OF_YEAR); |
| |
| if (week > 0 && week == currentWeek) |
| foundWeek = true; |
| if (week < 0 && week == ((currentWeek - maxWeek) - 1)) |
| foundWeek = true; |
| } |
| if (!foundWeek) |
| return false; |
| } |
| if (UtilValidate.isNotEmpty(byMonthList)) { |
| Iterator<String> iter = byMonthList.iterator(); |
| boolean foundMonth = false; |
| |
| while (iter.hasNext() && !foundMonth) { |
| int month = 0; |
| String monthStr = iter.next(); |
| |
| try { |
| month = Integer.parseInt(monthStr); |
| } catch (NumberFormatException nfe) { |
| Debug.logError(nfe, "Error parsing month string " + monthStr + ": " + nfe.toString(), module); |
| } |
| if (month == cal.get(Calendar.MONTH)) { |
| foundMonth = true; |
| } |
| } |
| if (!foundMonth) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| // Tests a string for the contents of a number at the beginning |
| private boolean hasNumber(String str) { |
| String list[] = {"+", "-", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"}; |
| List<String> numberList = Arrays.asList(list); |
| String firstChar = str.substring(0, 1); |
| |
| if (numberList.contains(firstChar)) |
| return true; |
| return false; |
| } |
| |
| // Gets the numeric value of the number at the beginning of the string |
| private int getDailyNumber(String str) { |
| int number = 0; |
| StringBuilder numberBuf = new StringBuilder(); |
| |
| for (int i = 0; i < str.length(); i++) { |
| String thisChar = str.substring(i, i); |
| |
| if (hasNumber(thisChar)) |
| numberBuf.append(thisChar); |
| } |
| String numberStr = numberBuf.toString(); |
| |
| if (numberStr.length() > 0 && (numberStr.length() > 1 || |
| (numberStr.charAt(0) != '+' && numberStr.charAt(0) != '-'))) { |
| try { |
| number = Integer.parseInt(numberStr); |
| } catch (NumberFormatException nfe) { |
| Debug.logError(nfe, "Error parsing daily number string " + numberStr + ": " + nfe.toString(), module); |
| } |
| } |
| return number; |
| } |
| |
| // Gets the string part of the combined number+string |
| private String getDailyString(String str) { |
| StringBuilder sBuf = new StringBuilder(); |
| |
| for (int i = 0; i < str.length(); i++) { |
| String thisChar = str.substring(i, i+1); |
| |
| if (!hasNumber(thisChar)) { |
| sBuf.append(thisChar); |
| } |
| } |
| return sBuf.toString(); |
| } |
| |
| // Returns the Calendar day of the rule day string |
| private int getCalendarDay(String day) { |
| if (day != null) day = day.trim(); |
| if (day.equalsIgnoreCase("MO")) |
| return Calendar.MONDAY; |
| if (day.equalsIgnoreCase("TU")) |
| return Calendar.TUESDAY; |
| if (day.equalsIgnoreCase("WE")) |
| return Calendar.WEDNESDAY; |
| if (day.equalsIgnoreCase("TH")) |
| return Calendar.THURSDAY; |
| if (day.equalsIgnoreCase("FR")) |
| return Calendar.FRIDAY; |
| if (day.equalsIgnoreCase("SA")) |
| return Calendar.SATURDAY; |
| if (day.equalsIgnoreCase("SU")) |
| return Calendar.SUNDAY; |
| return 0; |
| } |
| |
| public String primaryKey() { |
| return rule.getString("recurrenceRuleId"); |
| } |
| |
| public static RecurrenceRule makeRule(Delegator delegator, int frequency, int interval, int count) |
| throws RecurrenceRuleException { |
| return makeRule(delegator, frequency, interval, count, 0); |
| } |
| |
| public static RecurrenceRule makeRule(Delegator delegator, int frequency, int interval, long endTime) |
| throws RecurrenceRuleException { |
| return makeRule(delegator, frequency, interval, -1, endTime); |
| } |
| |
| public static RecurrenceRule makeRule(Delegator delegator, int frequency, int interval, int count, long endTime) |
| throws RecurrenceRuleException { |
| String freq[] = {"", "SECONDLY", "MINUTELY", "HOURLY", "DAILY", "WEEKLY", "MONTHLY", "YEARLY"}; |
| |
| if (frequency < 1 || frequency > 7) |
| throw new RecurrenceRuleException("Invalid frequency"); |
| if (interval < 0) |
| throw new RecurrenceRuleException("Invalid interval"); |
| |
| String freqStr = freq[frequency]; |
| |
| try { |
| GenericValue value = delegator.makeValue("RecurrenceRule"); |
| |
| value.set("frequency", freqStr); |
| value.set("intervalNumber", Long.valueOf(interval)); |
| value.set("countNumber", Long.valueOf(count)); |
| if (endTime > 0) { |
| value.set("untilDateTime", new java.sql.Timestamp(endTime)); |
| } |
| delegator.createSetNextSeqId(value); |
| RecurrenceRule newRule = new RecurrenceRule(value); |
| return newRule; |
| } catch (GenericEntityException ee) { |
| throw new RecurrenceRuleException(ee.getMessage(), ee); |
| } catch (RecurrenceRuleException re) { |
| throw re; |
| } |
| } |
| } |