001: package org.obe.engine.calendar;
002:
003: import java.util.BitSet;
004: import java.util.Calendar;
005: import java.util.GregorianCalendar;
006: import java.util.TimeZone;
007:
008: public class MonthRule extends CalendarRule {
009: // private static final long serialVersionUID = 4565221466107361462L;
010:
011: /**
012: * The month to which this rule applies.
013: */
014: private int _month;
015:
016: /**
017: * Specifies a particular occurrence of a day-of-the-week.
018: */
019: private Ordinal _ordinal;
020:
021: /**
022: * The day-of-the-month or day-of-the-week to which this rule applies.
023: */
024: private int _day;
025:
026: /**
027: * If this and day are both set, the rule applies to every occurrence of the
028: * specified day-of-the-week in that month.
029: */
030: private boolean _every;
031:
032: public MonthRule() {
033: }
034:
035: public MonthRule(int month, int day, Ordinal ordinal) {
036: _month = month;
037: _ordinal = ordinal;
038: _day = day;
039: }
040:
041: public MonthRule(int month, int day, boolean every) {
042: _month = month;
043: _day = day;
044: _every = every;
045: }
046:
047: public int getMonth() {
048: return _month;
049: }
050:
051: public Ordinal getOrdinal() {
052: return _ordinal;
053: }
054:
055: public int getDay() {
056: return _day;
057: }
058:
059: public boolean isEvery() {
060: return _every;
061: }
062:
063: public void setMonth(int month) {
064: _month = month;
065: }
066:
067: public void setOrdinal(Ordinal ordinal) {
068: _ordinal = ordinal;
069: }
070:
071: public void setDay(int day) {
072: _day = day;
073: }
074:
075: public void setEvery(boolean every) {
076: _every = every;
077: }
078:
079: /**
080: * Month is a bit trickier than the rest. It is such a long object that it
081: * can be both in and out of a BusinessCalendar. The code here may seem
082: * excessive, but it has to be to handle this case.
083: *
084: * @param mask
085: * @param length
086: * @param startDate
087: * @param endDate
088: * @param tz
089: */
090: public void applyRule(BitSet mask, int length,
091: GregorianCalendar startDate, GregorianCalendar endDate,
092: TimeZone tz) {
093:
094: GregorianCalendar calendar = (GregorianCalendar) startDate
095: .clone();
096: calendar.set(Calendar.MONTH, _month);
097: calendar.set(Calendar.DAY_OF_MONTH, 1);
098:
099: while (calendar.get(Calendar.MONTH) != _month)
100: calendar.add(Calendar.MONTH, 1);
101:
102: // Set the calendar to the start of the day.
103: calendar.set(Calendar.HOUR, 0);
104: calendar.set(Calendar.MINUTE, 0);
105: calendar.set(Calendar.SECOND, 0);
106:
107: // The month is after the end of the BC
108: // TODO: SHOULD THIS THROW AN EXCEPTION?
109: if (calendar.after(endDate)) {
110: if (_LOGGER.isDebugEnabled())
111: _LOGGER.debug("Out of scope");
112: return;
113: }
114:
115: if (_ordinal == null && !_every) {
116: // This is the entire month rule
117: int daysInMonth = calendar
118: .getActualMaximum(Calendar.DAY_OF_MONTH);
119: int startIndex = BusinessCalendarUtilities
120: .getIntervalIndex(startDate.getTime(), calendar
121: .getTime(), tz);
122: int ruleLength = BusinessCalendarUtilities
123: .getIntervalsInDate(calendar);
124: if (_LOGGER.isDebugEnabled()) {
125: _LOGGER
126: .debug("applyRule("
127: + "StartIndex: "
128: + startIndex
129: + ", RuleLength: "
130: + ruleLength
131: + ", MaxDays:"
132: + calendar
133: .getActualMaximum(Calendar.DAY_OF_MONTH)
134: + ", Month: "
135: + calendar.get(Calendar.MONTH) + ')');
136: }
137:
138: for (int i = 0; i < daysInMonth; i++) {
139: BusinessCalendarUtilities.setBitSetBits(mask,
140: startIndex, ruleLength);
141: calendar.add(Calendar.DATE, 1);
142: ruleLength = BusinessCalendarUtilities
143: .getIntervalsInDate(calendar);
144: startIndex = BusinessCalendarUtilities
145: .getIntervalIndex(startDate.getTime(), calendar
146: .getTime(), tz);
147: }
148: } else if (_ordinal != null && !_every) {
149: // This is a rule like 'third Monday of May'
150: while (calendar.get(Calendar.DAY_OF_WEEK) != _day)
151: calendar.add(Calendar.DATE, 1);
152:
153: // Now add the number of weeks to bring it up to the ordinal value
154: calendar.add(Calendar.DATE, _ordinal.value() * 7);
155:
156: int ruleLength = BusinessCalendarUtilities
157: .getIntervalsInDate(calendar);
158: int startIndex = BusinessCalendarUtilities
159: .getIntervalIndex(startDate.getTime(), calendar
160: .getTime(), tz);
161: BusinessCalendarUtilities.setBitSetBits(mask, startIndex,
162: ruleLength);
163: } else if (_every) {
164: // This is a rule like 'every Monday of May'
165: while (calendar.get(Calendar.DAY_OF_WEEK) != _day)
166: calendar.add(Calendar.DATE, 1);
167:
168: while (calendar.get(Calendar.MONTH) == _month) {
169: int ruleLength = BusinessCalendarUtilities
170: .getIntervalsInDate(calendar);
171: int startIndex = BusinessCalendarUtilities
172: .getIntervalIndex(startDate.getTime(), calendar
173: .getTime(), tz);
174: if (_LOGGER.isDebugEnabled()) {
175: _LOGGER.debug("EveryRule - ruleLength: "
176: + ruleLength + ", startIndex: "
177: + startIndex + ", date: "
178: + calendar.getTime());
179: }
180: BusinessCalendarUtilities.setBitSetBits(mask,
181: startIndex, ruleLength);
182:
183: // Add a week.
184: calendar.add(Calendar.DATE, 7);
185: }
186: }
187:
188: }
189:
190: public String toString() {
191: return "MonthRule[" + "_month=" + _month + ", _ordinal='"
192: + _ordinal + '\'' + ", _day=" + _day + ", _every="
193: + _every + ']';
194: }
195: }
|