001: /*
002: *
003: *
004: * Portions Copyright 2000-2007 Sun Microsystems, Inc. All Rights
005: * Reserved. Use is subject to license terms.
006: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
007: *
008: * This program is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public License version
010: * 2 only, as published by the Free Software Foundation.
011: *
012: * This program is distributed in the hope that it will be useful, but
013: * WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * General Public License version 2 for more details (a copy is
016: * included at /legal/license.txt).
017: *
018: * You should have received a copy of the GNU General Public License
019: * version 2 along with this work; if not, write to the Free Software
020: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
021: * 02110-1301 USA
022: *
023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
024: * Clara, CA 95054 or visit www.sun.com if you need additional
025: * information or have any questions.
026: */
027:
028: /*
029: * Copyright (C) 2002-2003 PalmSource, Inc. All Rights Reserved.
030: */
031:
032: package javax.microedition.pim;
033:
034: import com.sun.kvem.midp.pim.PIMHandler;
035: import java.util.Calendar;
036: import java.util.Enumeration;
037: import java.util.Date;
038: import java.util.Hashtable;
039: import java.util.Vector;
040:
041: /**
042: * This class is defined by the JSR-75 specification
043: * <em>PDA Optional Packages for the J2ME™ Platform</em>
044: */
045: // JAVADOC COMMENT ELIDED
046: public class RepeatRule {
047: /** Fields in the rule. */
048: private Hashtable fields = new Hashtable();
049: /** Exceptions caused by the rule. */
050: private Vector exceptions = new Vector();
051:
052: // JAVADOC COMMENT ELIDED
053: public RepeatRule() {
054: }
055:
056: // JAVADOC COMMENT ELIDED
057: public static final int FREQUENCY = 0;
058: // JAVADOC COMMENT ELIDED
059: public static final int DAY_IN_MONTH = 1;
060: // JAVADOC COMMENT ELIDED
061: public static final int DAY_IN_WEEK = 2;
062: // JAVADOC COMMENT ELIDED
063: public static final int DAY_IN_YEAR = 4;
064: // JAVADOC COMMENT ELIDED
065: public static final int MONTH_IN_YEAR = 8;
066: // JAVADOC COMMENT ELIDED
067: public static final int WEEK_IN_MONTH = 16;
068: // JAVADOC COMMENT ELIDED
069: public static final int COUNT = 32;
070: // JAVADOC COMMENT ELIDED
071: public static final int END = 64;
072: // JAVADOC COMMENT ELIDED
073: public static final int INTERVAL = 128;
074: // JAVADOC COMMENT ELIDED
075: public static final int DAILY = 0x10;
076: // JAVADOC COMMENT ELIDED
077: public static final int WEEKLY = 0x11;
078: // JAVADOC COMMENT ELIDED
079: public static final int MONTHLY = 0x12;
080: // JAVADOC COMMENT ELIDED
081: public static final int YEARLY = 0x13;
082: // JAVADOC COMMENT ELIDED
083: public static final int FIRST = 0x1;
084: // JAVADOC COMMENT ELIDED
085: public static final int SECOND = 0x2;
086: // JAVADOC COMMENT ELIDED
087: public static final int THIRD = 0x4;
088: // JAVADOC COMMENT ELIDED
089: public static final int FOURTH = 0x8;
090: // JAVADOC COMMENT ELIDED
091: public static final int FIFTH = 0x10;
092: // JAVADOC COMMENT ELIDED
093: public static final int LAST = 0x20;
094: // JAVADOC COMMENT ELIDED
095: public static final int SECONDLAST = 0x40;
096: // JAVADOC COMMENT ELIDED
097: public static final int THIRDLAST = 0x80;
098: // JAVADOC COMMENT ELIDED
099: public static final int FOURTHLAST = 0x100;
100: // JAVADOC COMMENT ELIDED
101: public static final int FIFTHLAST = 0x200;
102: // JAVADOC COMMENT ELIDED
103: public static final int SATURDAY = 0x400;
104: // JAVADOC COMMENT ELIDED
105: public static final int FRIDAY = 0x800;
106: // JAVADOC COMMENT ELIDED
107: public static final int THURSDAY = 0x1000;
108: // JAVADOC COMMENT ELIDED
109: public static final int WEDNESDAY = 0x2000;
110: // JAVADOC COMMENT ELIDED
111: public static final int TUESDAY = 0x4000;
112: // JAVADOC COMMENT ELIDED
113: public static final int MONDAY = 0x8000;
114: // JAVADOC COMMENT ELIDED
115: public static final int SUNDAY = 0x10000;
116: // JAVADOC COMMENT ELIDED
117: public static final int JANUARY = 0x20000;
118: // JAVADOC COMMENT ELIDED
119: public static final int FEBRUARY = 0x40000;
120: // JAVADOC COMMENT ELIDED
121: public static final int MARCH = 0x80000;
122: // JAVADOC COMMENT ELIDED
123: public static final int APRIL = 0x100000;
124: // JAVADOC COMMENT ELIDED
125: public static final int MAY = 0x200000;
126: // JAVADOC COMMENT ELIDED
127: public static final int JUNE = 0x400000;
128: // JAVADOC COMMENT ELIDED
129: public static final int JULY = 0x800000;
130: // JAVADOC COMMENT ELIDED
131: public static final int AUGUST = 0x1000000;
132: // JAVADOC COMMENT ELIDED
133: public static final int SEPTEMBER = 0x2000000;
134: // JAVADOC COMMENT ELIDED
135: public static final int OCTOBER = 0x4000000;
136: // JAVADOC COMMENT ELIDED
137: public static final int NOVEMBER = 0x8000000;
138: // JAVADOC COMMENT ELIDED
139: public static final int DECEMBER = 0x10000000;
140:
141: /** Months of the year. */
142: private static final int[] MONTHS = { JANUARY, FEBRUARY, MARCH,
143: APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER,
144: NOVEMBER, DECEMBER };
145: /** DAY_INCREMENT = 86400000l. */
146: private static final long DAY_INCREMENT = 86400000l;
147: /** DAY_IN_WEEK_MASK = 0x1fc00l. */
148: private static final long DAY_IN_WEEK_MASK = 0x1fc00l;
149: /** WEEK_IN_MONTH_MASK = 0x3ffl. */
150: private static final long WEEK_IN_MONTH_MASK = 0x3ffl;
151: /** MONTH_IN_YEAR_MASK = 0x1ffe0000. */
152: private static final long MONTH_IN_YEAR_MASK = 0x1ffe0000;
153: /** Days of the week. */
154: private static final int[] DAYS = { SUNDAY, MONDAY, TUESDAY,
155: WEDNESDAY, THURSDAY, FRIDAY };
156: /** DAY_LENGTH = 86400000L. */
157: private static final long DAY_LENGTH = 86400000L;
158:
159: // JAVADOC COMMENT ELIDED
160: public Enumeration dates(long startDate, long subsetBeginning,
161: long subsetEnding) {
162: if (subsetBeginning > subsetEnding) {
163: throw new IllegalArgumentException("Bad range: "
164: + subsetBeginning
165: + "("
166: + PIMHandler.getInstance().composeDateTime(
167: subsetBeginning)
168: + ") to "
169: + subsetEnding
170: + "("
171: + PIMHandler.getInstance().composeDateTime(
172: subsetEnding));
173: }
174: Calendar calendar = Calendar.getInstance();
175: Date dateObj = new Date(startDate);
176: calendar.setTime(dateObj);
177: Vector dates = new Vector();
178: long date = startDate;
179: Integer frequency = (Integer) getField(FREQUENCY, null);
180: int interval = ((Integer) getField(INTERVAL, new Integer(1)))
181: .intValue();
182: int count = ((Integer) getField(COUNT, new Integer(
183: Integer.MAX_VALUE))).intValue();
184: long end = ((Long) getField(END, new Long(Long.MAX_VALUE)))
185: .longValue();
186: Integer dayInWeek = (Integer) getField(DAY_IN_WEEK, null);
187: Integer dayInMonth = (Integer) getField(DAY_IN_MONTH, null);
188: Integer dayInYear = (Integer) getField(DAY_IN_YEAR, null);
189: Integer weekInMonth = (Integer) getField(WEEK_IN_MONTH, null);
190: Integer monthInYear = (Integer) getField(MONTH_IN_YEAR, null);
191: // set defaults, based on starting date
192: if (dayInMonth == null && weekInMonth == null) {
193: dayInMonth = new Integer(calendar
194: .get(Calendar.DAY_OF_MONTH));
195: }
196: if (dayInWeek == null) {
197: switch (calendar.get(Calendar.DAY_OF_WEEK)) {
198: case Calendar.SUNDAY:
199: dayInWeek = new Integer(SUNDAY);
200: break;
201: case Calendar.MONDAY:
202: dayInWeek = new Integer(MONDAY);
203: break;
204: case Calendar.TUESDAY:
205: dayInWeek = new Integer(TUESDAY);
206: break;
207: case Calendar.WEDNESDAY:
208: dayInWeek = new Integer(WEDNESDAY);
209: break;
210: case Calendar.THURSDAY:
211: dayInWeek = new Integer(THURSDAY);
212: break;
213: case Calendar.FRIDAY:
214: dayInWeek = new Integer(FRIDAY);
215: break;
216: case Calendar.SATURDAY:
217: dayInWeek = new Integer(SATURDAY);
218: break;
219: }
220: }
221: long rangeStart = Math.max(subsetBeginning, startDate);
222: long rangeEnd = Math.min(subsetEnding, end);
223: for (int i = 0; date <= subsetEnding && date <= end
224: && i < count; i++) {
225: if (frequency == null) {
226: // no repetitions
227: storeDate(dates, startDate, rangeStart, rangeEnd);
228: break;
229: }
230: switch (frequency.intValue()) {
231: case DAILY:
232: storeDate(dates, date, rangeStart, rangeEnd);
233: date += DAY_INCREMENT * interval;
234: dateObj.setTime(date);
235: calendar.setTime(dateObj);
236: break;
237: case WEEKLY:
238: if (dayInWeek == null) {
239: storeDate(dates, date, rangeStart, rangeEnd);
240: } else {
241: // shift date to the beginning of the week
242: date -= DAY_INCREMENT
243: * (calendar.get(Calendar.DAY_OF_WEEK) - Calendar.SUNDAY);
244: dateObj.setTime(date);
245: calendar.setTime(dateObj);
246: storeDays(dates, date, rangeStart, rangeEnd,
247: dayInWeek.intValue());
248: }
249: // increment the week
250: date += DAY_INCREMENT * 7;
251: dateObj.setTime(date);
252: calendar.setTime(dateObj);
253: break;
254: case MONTHLY: {
255: storeDaysByMonth(dates, date, rangeStart, rangeEnd,
256: dayInWeek, dayInMonth, weekInMonth);
257: // increment the month
258: int currentMonth = calendar.get(Calendar.MONTH);
259: if (currentMonth == Calendar.DECEMBER) {
260: int currentYear = calendar.get(Calendar.YEAR);
261: calendar.set(Calendar.YEAR, currentYear + 1);
262: calendar.set(Calendar.MONTH, Calendar.JANUARY);
263: } else {
264: calendar.set(Calendar.MONTH, currentMonth + 1);
265: }
266: dateObj = calendar.getTime();
267: date = dateObj.getTime();
268: break;
269: }
270: case YEARLY: {
271: if (monthInYear == null && dayInYear == null) {
272: storeDate(dates, date, rangeStart, rangeEnd);
273: } else {
274: // shift to January
275: calendar.set(Calendar.MONTH, Calendar.JANUARY);
276: dateObj = calendar.getTime();
277: date = dateObj.getTime();
278: if (monthInYear != null) {
279: int months = monthInYear.intValue();
280: for (int m = 0; m < MONTHS.length; m++) {
281: if ((months & MONTHS[m]) != 0) {
282: calendar.set(Calendar.MONTH, m);
283: storeDaysByMonth(dates, calendar
284: .getTime().getTime(),
285: rangeStart, rangeEnd,
286: dayInWeek, dayInMonth,
287: weekInMonth);
288: }
289: }
290: } else {
291: // dayInYear is non-null
292: // shift to the first of January
293: calendar.set(Calendar.DAY_OF_MONTH, 1);
294: dateObj = calendar.getTime();
295: date = dateObj.getTime();
296: storeDate(dates, date
297: + (dayInYear.intValue() - 1)
298: * DAY_INCREMENT, rangeStart, rangeEnd);
299: }
300: }
301: // increment the year
302: calendar.set(Calendar.YEAR,
303: calendar.get(Calendar.YEAR) + 1);
304: dateObj = calendar.getTime();
305: date = dateObj.getTime();
306: break;
307: }
308: default:
309: throw new IllegalArgumentException(
310: "Unrecognized value for frequency: "
311: + frequency);
312: } // end switch
313: } // end for
314: return dates.elements();
315: }
316:
317: /**
318: * Stores a date.
319: * @param dates array to extend
320: * @param date to be stored
321: * @param rangeStart beginning of range
322: * @param rangeEnd end of range
323: */
324: private void storeDate(Vector dates, long date, long rangeStart,
325: long rangeEnd) {
326: if (date >= rangeStart && date <= rangeEnd) {
327: Date dateObj = new Date(date);
328: if (!exceptions.contains(dateObj)) {
329: dates.addElement(new Date(date));
330: }
331: }
332: }
333:
334: /**
335: * Store days.
336: * @param dates array to extend
337: * @param date to be stored
338: * @param rangeStart beginning of range
339: * @param rangeEnd end of range
340: * @param days filter by specific days
341: */
342: private void storeDays(Vector dates, long date, long rangeStart,
343: long rangeEnd, int days) {
344: // shift date back to Sunday, if it is not already Sunday
345: Calendar cal = Calendar.getInstance();
346: cal.setTime(new Date(date));
347: int dayShift = cal.get(Calendar.DAY_OF_WEEK) - Calendar.SUNDAY;
348: date -= dayShift * DAY_INCREMENT;
349: long dateNextWeek = dayShift + DAY_INCREMENT * 7;
350: for (int i = 0; i < DAYS.length; i++) {
351: if ((days & DAYS[i]) != 0) {
352: long targetDate = (dayShift > i) ? dateNextWeek : date;
353: storeDate(dates, targetDate + DAY_INCREMENT * i,
354: rangeStart, rangeEnd);
355: }
356: }
357: }
358:
359: /**
360: * Store days by month.
361: * @param dates array to be extended
362: * @param date date to be added.
363: * @param rangeStart beginning of range
364: * @param rangeEnd end of range
365: * @param dayInWeek filter for day in the week
366: * @param dayInMonth filter for day in the month
367: * @param weekInMonth filter for week in the month
368: */
369: private void storeDaysByMonth(Vector dates, long date,
370: long rangeStart, long rangeEnd, Integer dayInWeek,
371: Integer dayInMonth, Integer weekInMonth) {
372: // move date to the first of the month
373: Calendar calendar = Calendar.getInstance();
374: calendar.setTime(new Date(date));
375: date -= DAY_INCREMENT
376: * (calendar.get(Calendar.DAY_OF_MONTH) - 1);
377: if (dayInMonth != null) {
378: storeDate(dates, date + DAY_INCREMENT
379: * (dayInMonth.intValue() - 1), rangeStart, rangeEnd);
380: } else if (weekInMonth != null) {
381: // get a limited range, containing only this month.
382: long monthRangeStart = Math.max(rangeStart, date);
383: // find the end of the month, assuming no month is longer
384: // than 31 days
385: long monthEnd = date + DAY_INCREMENT * 31;
386: calendar.setTime(new Date(monthEnd));
387: while (calendar.get(Calendar.DAY_OF_MONTH) > 1) {
388: monthEnd -= DAY_INCREMENT;
389: calendar.setTime(new Date(monthEnd));
390: }
391: monthEnd -= DAY_INCREMENT;
392: long monthRangeEnd = Math.min(rangeEnd, monthEnd);
393: int weeks = weekInMonth.intValue();
394: if ((weeks & FIRST) != 0) {
395: storeDays(dates, date, monthRangeStart, monthRangeEnd,
396: dayInWeek.intValue());
397: }
398: if ((weeks & SECOND) != 0) {
399: storeDays(dates, date + DAY_INCREMENT * 7,
400: monthRangeStart, monthRangeEnd, dayInWeek
401: .intValue());
402: }
403: if ((weeks & THIRD) != 0) {
404: storeDays(dates, date + DAY_INCREMENT * 14,
405: monthRangeStart, monthRangeEnd, dayInWeek
406: .intValue());
407: }
408: if ((weeks & FOURTH) != 0) {
409: storeDays(dates, date + DAY_INCREMENT * 21,
410: monthRangeStart, monthRangeEnd, dayInWeek
411: .intValue());
412: }
413: if ((weeks & FIFTH) != 0) {
414: storeDays(dates, date + DAY_INCREMENT * 28,
415: monthRangeStart, monthRangeEnd, dayInWeek
416: .intValue());
417: }
418: if ((weeks & LAST) != 0) {
419: storeDays(dates, monthEnd - DAY_INCREMENT * 6,
420: monthRangeStart, monthRangeEnd, dayInWeek
421: .intValue());
422: }
423: if ((weeks & LAST) != 0) {
424: storeDays(dates, monthEnd - DAY_INCREMENT * 6,
425: monthRangeStart, monthRangeEnd, dayInWeek
426: .intValue());
427: }
428: if ((weeks & SECONDLAST) != 0) {
429: storeDays(dates, monthEnd - DAY_INCREMENT * 13,
430: monthRangeStart, monthRangeEnd, dayInWeek
431: .intValue());
432: }
433: if ((weeks & THIRDLAST) != 0) {
434: storeDays(dates, monthEnd - DAY_INCREMENT * 20,
435: monthRangeStart, monthRangeEnd, dayInWeek
436: .intValue());
437: }
438: if ((weeks & FOURTHLAST) != 0) {
439: storeDays(dates, monthEnd - DAY_INCREMENT * 27,
440: monthRangeStart, monthRangeEnd, dayInWeek
441: .intValue());
442: }
443: if ((weeks & FIFTHLAST) != 0) {
444: storeDays(dates, monthEnd - DAY_INCREMENT * 34,
445: monthRangeStart, monthRangeEnd, dayInWeek
446: .intValue());
447: }
448: }
449: }
450:
451: // JAVADOC COMMENT ELIDED
452: public void addExceptDate(long date) {
453: exceptions.addElement(new Date(date));
454: }
455:
456: // JAVADOC COMMENT ELIDED
457: public void removeExceptDate(long date) {
458: exceptions.removeElement(new Date(date));
459: }
460:
461: // JAVADOC COMMENT ELIDED
462: public Enumeration getExceptDates() {
463: Vector results = new Vector();
464: for (Enumeration e = exceptions.elements(); e.hasMoreElements();) {
465: Date date = (Date) e.nextElement();
466: results.addElement(new Date(date.getTime()));
467: }
468: return results.elements();
469: }
470:
471: // JAVADOC COMMENT ELIDED
472: public int getInt(int field) {
473: validateDataType(field, PIMItem.INT);
474: return ((Integer) getField(field, NO_DEFAULT)).intValue();
475: }
476:
477: /** NO_DEFAULT = "". */
478: private static final Object NO_DEFAULT = "";
479:
480: /**
481: * Gets the requested field contents.
482: * @param field identifier for the requested field
483: * @param defaultValue value to return if field is not found
484: * @return requetsed field contents
485: */
486: private Object getField(int field, Object defaultValue) {
487: Integer fieldKey = new Integer(field);
488: Object fieldValue = fields.get(fieldKey);
489: if (fieldValue == null) {
490: if (defaultValue == NO_DEFAULT) {
491: throw new FieldEmptyException();
492: } else {
493: return defaultValue;
494: }
495: }
496: return fieldValue;
497: }
498:
499: // JAVADOC COMMENT ELIDED
500: public void setInt(int field, int value) {
501: validateDataType(field, PIMItem.INT);
502: boolean isValid;
503: switch (field) {
504: case COUNT:
505: isValid = (value >= 1);
506: break;
507: case DAY_IN_MONTH:
508: isValid = (value >= 1 && value <= 31);
509: break;
510: case DAY_IN_WEEK:
511: isValid = (value & ~DAY_IN_WEEK_MASK) == 0;
512: break;
513: case FREQUENCY:
514: switch (value) {
515: case DAILY:
516: case WEEKLY:
517: case MONTHLY:
518: case YEARLY:
519: isValid = true;
520: break;
521: default:
522: isValid = false;
523: }
524: break;
525: case INTERVAL:
526: isValid = (value >= 1);
527: break;
528: case MONTH_IN_YEAR:
529: isValid = (value & ~MONTH_IN_YEAR_MASK) == 0;
530: break;
531: case WEEK_IN_MONTH:
532: isValid = (value & ~WEEK_IN_MONTH_MASK) == 0;
533: break;
534: case DAY_IN_YEAR:
535: isValid = (value >= 1 && value <= 366);
536: break;
537: default:
538: isValid = false;
539: }
540: if (!isValid) {
541: throw new IllegalArgumentException("Field value is invalid");
542: }
543: Integer fieldKey = new Integer(field);
544: fields.put(fieldKey, new Integer(value));
545: }
546:
547: // JAVADOC COMMENT ELIDED
548: public long getDate(int field) {
549: validateDataType(field, PIMItem.DATE);
550: return ((Long) getField(field, NO_DEFAULT)).longValue();
551: }
552:
553: // JAVADOC COMMENT ELIDED
554: public void setDate(int field, long value) {
555: validateDataType(field, PIMItem.DATE);
556: Integer fieldKey = new Integer(field);
557: fields.put(fieldKey, new Long(value));
558: }
559:
560: // JAVADOC COMMENT ELIDED
561: public int[] getFields() {
562: int[] result = new int[fields.size()];
563: int i = 0;
564: for (Enumeration e = fields.keys(); e.hasMoreElements();) {
565: Integer fieldKey = (Integer) e.nextElement();
566: result[i++] = fieldKey.intValue();
567: }
568: return result;
569: }
570:
571: // JAVADOC COMMENT ELIDED
572: public boolean equals(Object obj) {
573: if (obj == null || !(obj instanceof RepeatRule)) {
574: return false;
575: }
576: RepeatRule rule = (RepeatRule) obj;
577: Calendar cal = Calendar.getInstance();
578: int[] ruleFields = rule.getFields();
579: for (int i = 0; i < ruleFields.length; i++) {
580: int field = ruleFields[i];
581: Object value = fields.get(new Integer(field));
582: if (value == null) {
583: // field in other rule is defined, but in this rule is not
584: return false;
585: }
586: switch (getDataType(field)) {
587: case PIMItem.INT: {
588: int iValue = ((Integer) value).intValue();
589: if (rule.getInt(field) != iValue) {
590: return false;
591: }
592: break;
593: }
594: case PIMItem.DATE: {
595: // dates match if they are on the same day
596: long this Date = ((Long) value).longValue();
597: long ruleDate = rule.getDate(field);
598: if (this Date == ruleDate) {
599: return true;
600: }
601: if (Math.abs(this Date - ruleDate) >= DAY_LENGTH) {
602: return false;
603: }
604: cal.setTime(new Date(this Date));
605: int day = cal.get(Calendar.DATE);
606: cal.setTime(new Date(ruleDate));
607: if (day != cal.get(Calendar.DATE)) {
608: return false;
609: }
610: break;
611: }
612: default:
613: return false; // unreachable
614: }
615:
616: }
617: // see if this rule defines any fields that the other rule does not
618: for (Enumeration e = fields.keys(); e.hasMoreElements();) {
619: Integer fieldKey = (Integer) e.nextElement();
620: int field = fieldKey.intValue();
621: boolean match = false;
622: for (int i = 0; i < ruleFields.length && !match; i++) {
623: if (ruleFields[i] == field) {
624: match = true;
625: }
626: }
627: if (!match) {
628: return false;
629: }
630: }
631: // check exception dates
632: // normalize the list of exception dates to represent only the date
633: // and not the time of day
634: int[] exceptionDates = new int[exceptions.size()];
635: for (int i = 0; i < exceptionDates.length; i++) {
636: Date date = (Date) exceptions.elementAt(i);
637: cal.setTime(date);
638: exceptionDates[i] = cal.get(Calendar.DAY_OF_MONTH) + 100
639: * cal.get(Calendar.MONTH) + 10000
640: * cal.get(Calendar.YEAR);
641: }
642: boolean[] matchedExceptionDates = new boolean[exceptionDates.length];
643: for (Enumeration e = rule.getExceptDates(); e.hasMoreElements();) {
644: Date date = (Date) e.nextElement();
645: cal.setTime(date);
646: int day = cal.get(Calendar.DAY_OF_MONTH) + 100
647: * cal.get(Calendar.MONTH) + 10000
648: * cal.get(Calendar.YEAR);
649: boolean match = false;
650: for (int i = 0; i < exceptionDates.length && !match; i++) {
651: if (exceptionDates[i] == day) {
652: match = true;
653: matchedExceptionDates[i] = true;
654: }
655: }
656: if (!match) {
657: return false;
658: }
659: }
660: // are there unmatched exception dates?
661: for (int i = 0; i < matchedExceptionDates.length; i++) {
662: if (!matchedExceptionDates[i]) {
663: // make sure this isn't a duplicate of another date
664: boolean duplicate = false;
665: for (int j = 0; j < i && !duplicate; j++) {
666: duplicate = exceptionDates[j] == exceptionDates[i];
667: }
668: if (!duplicate) {
669: return false;
670: }
671: }
672: }
673: return true;
674: }
675:
676: /**
677: * Checks that data type is valid.
678: * @param field identifier of requested field
679: * @param dataType type of data to be checked
680: * @throws IllegalArgumentException if type is not appropriate
681: */
682: private void validateDataType(int field, int dataType) {
683: int correctDataType = getDataType(field);
684: if (dataType != correctDataType) {
685: throw new IllegalArgumentException("Invalid field type");
686: }
687: }
688:
689: /**
690: * Gets the data type for the requested field.
691: * @param field identifier of requested field
692: * @return data type of requested field
693: */
694: private int getDataType(int field) {
695: switch (field) {
696: case COUNT:
697: case DAY_IN_MONTH:
698: case DAY_IN_WEEK:
699: case DAY_IN_YEAR:
700: case FREQUENCY:
701: case INTERVAL:
702: case MONTH_IN_YEAR:
703: case WEEK_IN_MONTH:
704: return PIMItem.INT;
705: case END:
706: return PIMItem.DATE;
707: default:
708: throw new IllegalArgumentException("Unrecognized field: "
709: + field);
710: }
711: }
712: }
|