FileDocCategorySizeDatePackage
RepeatRule.javaAPI DocphoneME MR2 API (J2ME)27067Wed May 02 18:00:28 BST 2007javax.microedition.pim

RepeatRule

public class RepeatRule extends Object
This class is defined by the JSR-75 specification PDA Optional Packages for the J2ME™ Platform

Fields Summary
private Hashtable
fields
Fields in the rule.
private Vector
exceptions
Exceptions caused by the rule.
public static final int
FREQUENCY
public static final int
DAY_IN_MONTH
public static final int
DAY_IN_WEEK
public static final int
DAY_IN_YEAR
public static final int
MONTH_IN_YEAR
public static final int
WEEK_IN_MONTH
public static final int
COUNT
public static final int
END
public static final int
INTERVAL
public static final int
DAILY
public static final int
WEEKLY
public static final int
MONTHLY
public static final int
YEARLY
public static final int
FIRST
public static final int
SECOND
public static final int
THIRD
public static final int
FOURTH
public static final int
FIFTH
public static final int
LAST
public static final int
SECONDLAST
public static final int
THIRDLAST
public static final int
FOURTHLAST
public static final int
FIFTHLAST
public static final int
SATURDAY
public static final int
FRIDAY
public static final int
THURSDAY
public static final int
WEDNESDAY
public static final int
TUESDAY
public static final int
MONDAY
public static final int
SUNDAY
public static final int
JANUARY
public static final int
FEBRUARY
public static final int
MARCH
public static final int
APRIL
public static final int
MAY
public static final int
JUNE
public static final int
JULY
public static final int
AUGUST
public static final int
SEPTEMBER
public static final int
OCTOBER
public static final int
NOVEMBER
public static final int
DECEMBER
private static final int[]
MONTHS
Months of the year.
private static final long
DAY_INCREMENT
DAY_INCREMENT = 86400000l.
private static final long
DAY_IN_WEEK_MASK
DAY_IN_WEEK_MASK = 0x1fc00l.
private static final long
WEEK_IN_MONTH_MASK
WEEK_IN_MONTH_MASK = 0x3ffl.
private static final long
MONTH_IN_YEAR_MASK
MONTH_IN_YEAR_MASK = 0x1ffe0000.
private static final int[]
DAYS
Days of the week.
private static final long
DAY_LENGTH
DAY_LENGTH = 86400000L.
private static final Object
NO_DEFAULT
NO_DEFAULT = "".
Constructors Summary
public RepeatRule()

    // JAVADOC COMMENT ELIDED
       
Methods Summary
public voidaddExceptDate(long date)

        exceptions.addElement(new Date(date));
    
public java.util.Enumerationdates(long startDate, long subsetBeginning, long subsetEnding)


    // JAVADOC COMMENT ELIDED
         
			       
        if (subsetBeginning > subsetEnding) {
            throw new IllegalArgumentException("Bad range: "
                + subsetBeginning + "("
                + PIMHandler.getInstance().composeDateTime(subsetBeginning)
                + ") to " + subsetEnding + "("
                + PIMHandler.getInstance().composeDateTime(subsetEnding));
        }
        Calendar calendar = Calendar.getInstance();
        Date dateObj = new Date(startDate);
        calendar.setTime(dateObj);
        Vector dates = new Vector();
        long date = startDate;
        Integer frequency = (Integer) getField(FREQUENCY, null);
        int interval = ((Integer) getField(INTERVAL,
					   new Integer(1))).intValue();
        int count = ((Integer) 
		     getField(COUNT, 
			      new Integer(Integer.MAX_VALUE))).intValue();
        long end = ((Long) getField(END, new Long(Long.MAX_VALUE))).longValue();
        Integer dayInWeek = (Integer) getField(DAY_IN_WEEK, null);
        Integer dayInMonth = (Integer) getField(DAY_IN_MONTH, null);
        Integer dayInYear = (Integer) getField(DAY_IN_YEAR, null);
        Integer weekInMonth = (Integer) getField(WEEK_IN_MONTH, null);
        Integer monthInYear = (Integer) getField(MONTH_IN_YEAR, null);
        // set defaults, based on starting date
        if (dayInMonth == null && weekInMonth == null) {
            dayInMonth = new Integer(calendar.get(Calendar.DAY_OF_MONTH));
        }
        if (dayInWeek == null) {
            switch (calendar.get(Calendar.DAY_OF_WEEK)) {
                case Calendar.SUNDAY:
		    dayInWeek = new Integer(SUNDAY);
		    break;
                case Calendar.MONDAY:
		    dayInWeek = new Integer(MONDAY);
		    break;
                case Calendar.TUESDAY:
		    dayInWeek = new Integer(TUESDAY);
		    break;
                case Calendar.WEDNESDAY:
		    dayInWeek = new Integer(WEDNESDAY);
		    break;
                case Calendar.THURSDAY:
		    dayInWeek = new Integer(THURSDAY);
		    break;
                case Calendar.FRIDAY: 
		    dayInWeek = new Integer(FRIDAY);
		    break;
                case Calendar.SATURDAY: 
		    dayInWeek = new Integer(SATURDAY);
		    break;
            }
        }
        long rangeStart = Math.max(subsetBeginning, startDate);
        long rangeEnd = Math.min(subsetEnding, end);
        for (int i = 0; date <= subsetEnding && date <= end && i < count; i++) {
            if (frequency == null) {
                // no repetitions
                storeDate(dates, startDate, rangeStart, rangeEnd);
                break;
            }
            switch (frequency.intValue()) {
                case DAILY:
                    storeDate(dates, date, rangeStart, rangeEnd);
                    date += DAY_INCREMENT * interval;
                    dateObj.setTime(date);
                    calendar.setTime(dateObj);
                    break;
                case WEEKLY:
                    if (dayInWeek == null) {
                        storeDate(dates, date, rangeStart, rangeEnd);
                    } else {
                        // shift date to the beginning of the week
                        date -= DAY_INCREMENT * 
                            (calendar.get(Calendar.DAY_OF_WEEK) -
			     Calendar.SUNDAY);
                        dateObj.setTime(date);
                        calendar.setTime(dateObj);
                        storeDays(dates, date, rangeStart, rangeEnd,
				  dayInWeek.intValue());
                    }
                    // increment the week
                    date += DAY_INCREMENT * 7;
                    dateObj.setTime(date);
                    calendar.setTime(dateObj);
                    break;
                case MONTHLY: {
                    storeDaysByMonth(dates, date, rangeStart, rangeEnd,
                        dayInWeek, dayInMonth, weekInMonth);
                    // increment the month
                    int currentMonth = calendar.get(Calendar.MONTH);
                    if (currentMonth == Calendar.DECEMBER) {
                        int currentYear = calendar.get(Calendar.YEAR);
                        calendar.set(Calendar.YEAR, currentYear + 1);
                        calendar.set(Calendar.MONTH, Calendar.JANUARY);
                    } else {
                        calendar.set(Calendar.MONTH, currentMonth + 1);
                    }
                    dateObj = calendar.getTime();
                    date = dateObj.getTime();
                    break;
                }
                case YEARLY: {
                    if (monthInYear == null && dayInYear == null) {
                        storeDate(dates, date, rangeStart, rangeEnd);
                    } else {
                        // shift to January
                        calendar.set(Calendar.MONTH, Calendar.JANUARY);
                        dateObj = calendar.getTime();
                        date = dateObj.getTime();
                        if (monthInYear != null) {
                            int months = monthInYear.intValue();
                            for (int m = 0; m < MONTHS.length; m++) {
                                if ((months & MONTHS[m]) != 0) {
                                    calendar.set(Calendar.MONTH, m);
                                    storeDaysByMonth(dates,
                                        calendar.getTime().getTime(),
                                        rangeStart, rangeEnd,
                                        dayInWeek, dayInMonth, weekInMonth);
                                }
                            }
                        } else {
                            // dayInYear is non-null
                            // shift to the first of January
                            calendar.set(Calendar.DAY_OF_MONTH, 1);
                            dateObj = calendar.getTime();
                            date = dateObj.getTime();
                            storeDate(dates,
                                date + (dayInYear.intValue() - 1)
				      * DAY_INCREMENT,
                                rangeStart,
                                rangeEnd);
                        }
                    }
                    // increment the year
                    calendar.set(Calendar.YEAR, 
				 calendar.get(Calendar.YEAR) + 1);
                    dateObj = calendar.getTime();
                    date = dateObj.getTime();
                    break;
                }
                default:
                    throw new IllegalArgumentException(
                        "Unrecognized value for frequency: " + frequency);
            } // end switch
        } // end for
        return dates.elements();
    
public booleanequals(java.lang.Object obj)

        if (obj == null || !(obj instanceof RepeatRule)) {
            return false;
        }
        RepeatRule rule = (RepeatRule) obj;
        Calendar cal = Calendar.getInstance();
        int[] ruleFields = rule.getFields();
        for (int i = 0; i < ruleFields.length; i++) {
            int field = ruleFields[i];
            Object value = fields.get(new Integer(field));
            if (value == null) {
                // field in other rule is defined, but in this rule is not
                return false;
            }
            switch (getDataType(field)) {
                case PIMItem.INT: {
                    int iValue = ((Integer) value).intValue();
                    if (rule.getInt(field) != iValue) {
                        return false;
                    }
                    break;
                }
                case PIMItem.DATE: {
                    // dates match if they are on the same day
                    long thisDate = ((Long) value).longValue();
                    long ruleDate = rule.getDate(field);
                    if (thisDate == ruleDate) {
                        return true;
                    }
                    if (Math.abs(thisDate - ruleDate) >= DAY_LENGTH) {
                        return false;
                    }
                    cal.setTime(new Date(thisDate));
                    int day = cal.get(Calendar.DATE);
                    cal.setTime(new Date(ruleDate));
                    if (day != cal.get(Calendar.DATE)) {
                        return false;
                    }
                    break;
                }
                default:
                    return false; // unreachable
            }
            
        }
        // see if this rule defines any fields that the other rule does not
        for (Enumeration e = fields.keys(); e.hasMoreElements(); ) {
            Integer fieldKey = (Integer) e.nextElement();
            int field = fieldKey.intValue();
            boolean match = false;
            for (int i = 0; i < ruleFields.length && !match; i++) {
                if (ruleFields[i] == field) {
                    match = true;
                }
            }
            if (!match) {
                return false;
            }
        }
        // check exception dates
        // normalize the list of exception dates to represent only the date
        // and not the time of day
        int[] exceptionDates = new int[exceptions.size()];
        for (int i = 0; i < exceptionDates.length; i++) {
            Date date = (Date) exceptions.elementAt(i);
            cal.setTime(date);
            exceptionDates[i] = cal.get(Calendar.DAY_OF_MONTH)
                + 100 * cal.get(Calendar.MONTH)
                + 10000 * cal.get(Calendar.YEAR);
        }
        boolean[] matchedExceptionDates = new boolean[exceptionDates.length];
        for (Enumeration e = rule.getExceptDates(); e.hasMoreElements(); ) {
            Date date = (Date) e.nextElement();
            cal.setTime(date);
            int day = cal.get(Calendar.DAY_OF_MONTH)
                + 100 * cal.get(Calendar.MONTH)
                + 10000 * cal.get(Calendar.YEAR);
            boolean match = false;
            for (int i = 0; i < exceptionDates.length && !match; i++) {
                if (exceptionDates[i] == day) {
                    match = true;
                    matchedExceptionDates[i] = true;
                }
            }
            if (!match) {
                return false;
            }
        }
        // are there unmatched exception dates?
        for (int i = 0; i < matchedExceptionDates.length; i++) {
            if (!matchedExceptionDates[i]) {
                // make sure this isn't a duplicate of another date
                boolean duplicate = false;
                for (int j = 0; j < i && !duplicate; j++) {
                    duplicate = exceptionDates[j] == exceptionDates[i];
                }
                if (!duplicate) {
                    return false;
                }
            }
        }
        return true;
    
private intgetDataType(int field)
Gets the data type for the requested field.

param
field identifier of requested field
return
data type of requested field

        switch (field) {
            case COUNT:
            case DAY_IN_MONTH:
            case DAY_IN_WEEK:
            case DAY_IN_YEAR:
            case FREQUENCY:
            case INTERVAL:
            case MONTH_IN_YEAR:
            case WEEK_IN_MONTH:
                return PIMItem.INT;
            case END:
                return PIMItem.DATE;
            default:
                throw new IllegalArgumentException("Unrecognized field: "
						   + field);
        }
    
public longgetDate(int field)

        validateDataType(field, PIMItem.DATE);
        return ((Long) getField(field, NO_DEFAULT)).longValue();
    
public java.util.EnumerationgetExceptDates()

        Vector results = new Vector();
        for (Enumeration e = exceptions.elements();
	    e.hasMoreElements(); ) {
            Date date = (Date) e.nextElement();
            results.addElement(new Date(date.getTime()));
        }
        return results.elements();
    
private java.lang.ObjectgetField(int field, java.lang.Object defaultValue)
Gets the requested field contents.

param
field identifier for the requested field
param
defaultValue value to return if field is not found
return
requetsed field contents

    
                                   
          
        Integer fieldKey = new Integer(field);
        Object fieldValue = fields.get(fieldKey);
        if (fieldValue == null) {
            if (defaultValue == NO_DEFAULT) {
                throw new FieldEmptyException();
            } else {
                return defaultValue;
            }
        }
        return fieldValue;
    
public int[]getFields()

        int[] result = new int[fields.size()];
        int i = 0;
        for (Enumeration e = fields.keys(); e.hasMoreElements(); ) {
            Integer fieldKey = (Integer) e.nextElement();
            result[i++] = fieldKey.intValue();
        }
        return result;
    
public intgetInt(int field)

        validateDataType(field, PIMItem.INT);
        return ((Integer) getField(field, NO_DEFAULT)).intValue();
    
public voidremoveExceptDate(long date)

        exceptions.removeElement(new Date(date));
    
public voidsetDate(int field, long value)

        validateDataType(field, PIMItem.DATE);
        Integer fieldKey = new Integer(field);
        fields.put(fieldKey, new Long(value));
    
public voidsetInt(int field, int value)

        validateDataType(field, PIMItem.INT);
        boolean isValid;
        switch (field) {
            case COUNT:
                isValid = (value >= 1);
                break;
            case DAY_IN_MONTH:
                isValid = (value >= 1 && value <= 31);
                break;
            case DAY_IN_WEEK:
                isValid = (value & ~DAY_IN_WEEK_MASK) == 0;
                break;
            case FREQUENCY:
                switch (value) {
                    case DAILY:
                    case WEEKLY:
                    case MONTHLY:
                    case YEARLY:
                        isValid = true;
                        break;
                    default:
                        isValid = false;
                }
                break;
            case INTERVAL:
                isValid = (value >= 1);
                break;
            case MONTH_IN_YEAR:
                isValid = (value & ~MONTH_IN_YEAR_MASK) == 0;
                break;
            case WEEK_IN_MONTH:
                isValid = (value & ~WEEK_IN_MONTH_MASK) == 0;
                break;
            case DAY_IN_YEAR:
                isValid = (value >= 1 && value <= 366);
                break;
            default:
                isValid = false;
        }
        if (!isValid) {
            throw new IllegalArgumentException("Field value is invalid");
        }
        Integer fieldKey = new Integer(field);
        fields.put(fieldKey, new Integer(value));
    
private voidstoreDate(java.util.Vector dates, long date, long rangeStart, long rangeEnd)
Stores a date.

param
dates array to extend
param
date to be stored
param
rangeStart beginning of range
param
rangeEnd end of range

        if (date >= rangeStart && date <= rangeEnd) {
            Date dateObj = new Date(date);
            if (!exceptions.contains(dateObj)) {
                dates.addElement(new Date(date));
            }
        }
    
private voidstoreDays(java.util.Vector dates, long date, long rangeStart, long rangeEnd, int days)
Store days.

param
dates array to extend
param
date to be stored
param
rangeStart beginning of range
param
rangeEnd end of range
param
days filter by specific days

        // shift date back to Sunday, if it is not already Sunday
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date(date));
        int dayShift = cal.get(Calendar.DAY_OF_WEEK) - Calendar.SUNDAY;
        date -= dayShift * DAY_INCREMENT;
        long dateNextWeek = dayShift + DAY_INCREMENT * 7;
        for (int i = 0; i < DAYS.length; i++) {
            if ((days & DAYS[i]) != 0) {
                long targetDate = (dayShift > i) ? dateNextWeek : date;
                storeDate(dates,
                    targetDate + DAY_INCREMENT * i,
                    rangeStart, rangeEnd);
            }
        }
    
private voidstoreDaysByMonth(java.util.Vector dates, long date, long rangeStart, long rangeEnd, java.lang.Integer dayInWeek, java.lang.Integer dayInMonth, java.lang.Integer weekInMonth)
Store days by month.

param
dates array to be extended
param
date date to be added.
param
rangeStart beginning of range
param
rangeEnd end of range
param
dayInWeek filter for day in the week
param
dayInMonth filter for day in the month
param
weekInMonth filter for week in the month

        // move date to the first of the month
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(date));
        date -= DAY_INCREMENT *
            (calendar.get(Calendar.DAY_OF_MONTH) - 1);
        if (dayInMonth != null) {
            storeDate(dates,
            date + DAY_INCREMENT * (dayInMonth.intValue() - 1),
            rangeStart, rangeEnd);
        } else if (weekInMonth != null) {
            // get a limited range, containing only this month.
            long monthRangeStart = Math.max(rangeStart, date);
            // find the end of the month, assuming no month is longer
            // than 31 days
            long monthEnd = date + DAY_INCREMENT * 31;
            calendar.setTime(new Date(monthEnd));
            while (calendar.get(Calendar.DAY_OF_MONTH) > 1) {
                monthEnd -= DAY_INCREMENT;
                calendar.setTime(new Date(monthEnd));
            }
            monthEnd -= DAY_INCREMENT;
            long monthRangeEnd = Math.min(rangeEnd, monthEnd);
            int weeks = weekInMonth.intValue();
            if ((weeks & FIRST) != 0) {
                storeDays(dates, date,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & SECOND) != 0) {
                storeDays(dates, date + DAY_INCREMENT * 7,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & THIRD) != 0) {
                storeDays(dates, date +  DAY_INCREMENT * 14,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & FOURTH) != 0) {
                storeDays(dates, date +  DAY_INCREMENT * 21,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & FIFTH) != 0) {
                storeDays(dates, date +  DAY_INCREMENT * 28,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & LAST) != 0) {
                storeDays(dates, monthEnd - DAY_INCREMENT * 6,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & LAST) != 0) {
                storeDays(dates, monthEnd - DAY_INCREMENT * 6,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & SECONDLAST) != 0) {
                storeDays(dates, monthEnd - DAY_INCREMENT * 13,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & THIRDLAST) != 0) {
                storeDays(dates, monthEnd - DAY_INCREMENT * 20,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & FOURTHLAST) != 0) {
                storeDays(dates, monthEnd - DAY_INCREMENT * 27,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
            if ((weeks & FIFTHLAST) != 0) {
                storeDays(dates, monthEnd - DAY_INCREMENT * 34,
                monthRangeStart, monthRangeEnd,
                dayInWeek.intValue());
            }
        }
    
private voidvalidateDataType(int field, int dataType)
Checks that data type is valid.

param
field identifier of requested field
param
dataType type of data to be checked
throws
IllegalArgumentException if type is not appropriate

        int correctDataType = getDataType(field);
        if (dataType != correctDataType) {
            throw new IllegalArgumentException("Invalid field type");
        }