1.1 --- a/src/net/fortuna/ical4j/model/Recur.java Thu Feb 12 18:02:00 2015 +0100 1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 1.3 @@ -1,1266 +0,0 @@ 1.4 -/** 1.5 - * Copyright (c) 2012, Ben Fortuna 1.6 - * All rights reserved. 1.7 - * 1.8 - * Redistribution and use in source and binary forms, with or without 1.9 - * modification, are permitted provided that the following conditions 1.10 - * are met: 1.11 - * 1.12 - * o Redistributions of source code must retain the above copyright 1.13 - * notice, this list of conditions and the following disclaimer. 1.14 - * 1.15 - * o Redistributions in binary form must reproduce the above copyright 1.16 - * notice, this list of conditions and the following disclaimer in the 1.17 - * documentation and/or other materials provided with the distribution. 1.18 - * 1.19 - * o Neither the name of Ben Fortuna nor the names of any other contributors 1.20 - * may be used to endorse or promote products derived from this software 1.21 - * without specific prior written permission. 1.22 - * 1.23 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.24 - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.25 - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.26 - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 1.27 - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 1.28 - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 1.29 - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 1.30 - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 1.31 - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 1.32 - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 1.33 - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.34 - */ 1.35 -package net.fortuna.ical4j.model; 1.36 - 1.37 -import java.io.IOException; 1.38 -import java.io.Serializable; 1.39 -import java.text.ParseException; 1.40 -import java.util.Calendar; 1.41 -import java.util.Collections; 1.42 -import java.util.HashMap; 1.43 -import java.util.Iterator; 1.44 -import java.util.List; 1.45 -import java.util.Map; 1.46 -import java.util.NoSuchElementException; 1.47 -import java.util.StringTokenizer; 1.48 - 1.49 -import net.fortuna.ical4j.model.parameter.Value; 1.50 -import net.fortuna.ical4j.util.CompatibilityHints; 1.51 -import net.fortuna.ical4j.util.Configurator; 1.52 -import net.fortuna.ical4j.util.Dates; 1.53 - 1.54 -import org.apache.commons.logging.Log; 1.55 -import org.apache.commons.logging.LogFactory; 1.56 - 1.57 -/** 1.58 - * $Id$ [18-Apr-2004] 1.59 - * 1.60 - * Defines a recurrence. 1.61 - * @version 2.0 1.62 - * @author Ben Fortuna 1.63 - */ 1.64 -public class Recur implements Serializable { 1.65 - 1.66 - private static final long serialVersionUID = -7333226591784095142L; 1.67 - 1.68 - private static final String FREQ = "FREQ"; 1.69 - 1.70 - private static final String UNTIL = "UNTIL"; 1.71 - 1.72 - private static final String COUNT = "COUNT"; 1.73 - 1.74 - private static final String INTERVAL = "INTERVAL"; 1.75 - 1.76 - private static final String BYSECOND = "BYSECOND"; 1.77 - 1.78 - private static final String BYMINUTE = "BYMINUTE"; 1.79 - 1.80 - private static final String BYHOUR = "BYHOUR"; 1.81 - 1.82 - private static final String BYDAY = "BYDAY"; 1.83 - 1.84 - private static final String BYMONTHDAY = "BYMONTHDAY"; 1.85 - 1.86 - private static final String BYYEARDAY = "BYYEARDAY"; 1.87 - 1.88 - private static final String BYWEEKNO = "BYWEEKNO"; 1.89 - 1.90 - private static final String BYMONTH = "BYMONTH"; 1.91 - 1.92 - private static final String BYSETPOS = "BYSETPOS"; 1.93 - 1.94 - private static final String WKST = "WKST"; 1.95 - 1.96 - /** 1.97 - * Second frequency resolution. 1.98 - */ 1.99 - public static final String SECONDLY = "SECONDLY"; 1.100 - 1.101 - /** 1.102 - * Minute frequency resolution. 1.103 - */ 1.104 - public static final String MINUTELY = "MINUTELY"; 1.105 - 1.106 - /** 1.107 - * Hour frequency resolution. 1.108 - */ 1.109 - public static final String HOURLY = "HOURLY"; 1.110 - 1.111 - /** 1.112 - * Day frequency resolution. 1.113 - */ 1.114 - public static final String DAILY = "DAILY"; 1.115 - 1.116 - /** 1.117 - * Week frequency resolution. 1.118 - */ 1.119 - public static final String WEEKLY = "WEEKLY"; 1.120 - 1.121 - /** 1.122 - * Month frequency resolution. 1.123 - */ 1.124 - public static final String MONTHLY = "MONTHLY"; 1.125 - 1.126 - /** 1.127 - * Year frequency resolution. 1.128 - */ 1.129 - public static final String YEARLY = "YEARLY"; 1.130 - 1.131 - /** 1.132 - * When calculating dates matching this recur ({@code getDates()} or {@code getNextDate}), 1.133 - * this property defines the maximum number of attempt to find a matching date by 1.134 - * incrementing the seed. 1.135 - * <p>The default value is 1000. A value of -1 corresponds to no maximum.</p> 1.136 - */ 1.137 - public static final String KEY_MAX_INCREMENT_COUNT = "net.fortuna.ical4j.recur.maxincrementcount"; 1.138 - 1.139 - private static int maxIncrementCount; 1.140 - static { 1.141 - final String value = Configurator.getProperty(KEY_MAX_INCREMENT_COUNT); 1.142 - if (value != null && value.length() > 0) { 1.143 - maxIncrementCount = Integer.parseInt(value); 1.144 - } else { 1.145 - maxIncrementCount = 1000; 1.146 - } 1.147 - } 1.148 - 1.149 - private transient Log log = LogFactory.getLog(Recur.class); 1.150 - 1.151 - private String frequency; 1.152 - 1.153 - private Date until; 1.154 - 1.155 - private int count = -1; 1.156 - 1.157 - private int interval = -1; 1.158 - 1.159 - private NumberList secondList; 1.160 - 1.161 - private NumberList minuteList; 1.162 - 1.163 - private NumberList hourList; 1.164 - 1.165 - private WeekDayList dayList; 1.166 - 1.167 - private NumberList monthDayList; 1.168 - 1.169 - private NumberList yearDayList; 1.170 - 1.171 - private NumberList weekNoList; 1.172 - 1.173 - private NumberList monthList; 1.174 - 1.175 - private NumberList setPosList; 1.176 - 1.177 - private String weekStartDay; 1.178 - 1.179 - private int calendarWeekStartDay; 1.180 - 1.181 - private Map experimentalValues = new HashMap(); 1.182 - 1.183 - // Calendar field we increment based on frequency. 1.184 - private int calIncField; 1.185 - 1.186 - /** 1.187 - * Default constructor. 1.188 - */ 1.189 - public Recur() { 1.190 - // default week start is Monday per RFC5545 1.191 - calendarWeekStartDay = Calendar.MONDAY; 1.192 - } 1.193 - 1.194 - /** 1.195 - * Constructs a new instance from the specified string value. 1.196 - * @param aValue a string representation of a recurrence. 1.197 - * @throws ParseException thrown when the specified string contains an invalid representation of an UNTIL date value 1.198 - */ 1.199 - public Recur(final String aValue) throws ParseException { 1.200 - // default week start is Monday per RFC5545 1.201 - calendarWeekStartDay = Calendar.MONDAY; 1.202 - final StringTokenizer t = new StringTokenizer(aValue, ";="); 1.203 - while (t.hasMoreTokens()) { 1.204 - final String token = t.nextToken(); 1.205 - if (FREQ.equals(token)) { 1.206 - frequency = nextToken(t, token); 1.207 - } 1.208 - else if (UNTIL.equals(token)) { 1.209 - final String untilString = nextToken(t, token); 1.210 - if (untilString != null && untilString.indexOf("T") >= 0) { 1.211 - until = new DateTime(untilString); 1.212 - // UNTIL must be specified in UTC time.. 1.213 - ((DateTime) until).setUtc(true); 1.214 - } 1.215 - else { 1.216 - until = new Date(untilString); 1.217 - } 1.218 - } 1.219 - else if (COUNT.equals(token)) { 1.220 - count = Integer.parseInt(nextToken(t, token)); 1.221 - } 1.222 - else if (INTERVAL.equals(token)) { 1.223 - interval = Integer.parseInt(nextToken(t, token)); 1.224 - } 1.225 - else if (BYSECOND.equals(token)) { 1.226 - secondList = new NumberList(nextToken(t, token), 0, 59, false); 1.227 - } 1.228 - else if (BYMINUTE.equals(token)) { 1.229 - minuteList = new NumberList(nextToken(t, token), 0, 59, false); 1.230 - } 1.231 - else if (BYHOUR.equals(token)) { 1.232 - hourList = new NumberList(nextToken(t, token), 0, 23, false); 1.233 - } 1.234 - else if (BYDAY.equals(token)) { 1.235 - dayList = new WeekDayList(nextToken(t, token)); 1.236 - } 1.237 - else if (BYMONTHDAY.equals(token)) { 1.238 - monthDayList = new NumberList(nextToken(t, token), 1, 31, true); 1.239 - } 1.240 - else if (BYYEARDAY.equals(token)) { 1.241 - yearDayList = new NumberList(nextToken(t, token), 1, 366, true); 1.242 - } 1.243 - else if (BYWEEKNO.equals(token)) { 1.244 - weekNoList = new NumberList(nextToken(t, token), 1, 53, true); 1.245 - } 1.246 - else if (BYMONTH.equals(token)) { 1.247 - monthList = new NumberList(nextToken(t, token), 1, 12, false); 1.248 - } 1.249 - else if (BYSETPOS.equals(token)) { 1.250 - setPosList = new NumberList(nextToken(t, token), 1, 366, true); 1.251 - } 1.252 - else if (WKST.equals(token)) { 1.253 - weekStartDay = nextToken(t, token); 1.254 - calendarWeekStartDay = WeekDay.getCalendarDay(new WeekDay(weekStartDay)); 1.255 - } 1.256 - else { 1.257 - if (CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING)) { 1.258 - // assume experimental value.. 1.259 - experimentalValues.put(token, nextToken(t, token)); 1.260 - } 1.261 - else { 1.262 - throw new IllegalArgumentException("Invalid recurrence rule part: " + 1.263 - token + "=" + nextToken(t, token)); 1.264 - } 1.265 - } 1.266 - } 1.267 - validateFrequency(); 1.268 - } 1.269 - 1.270 - private String nextToken(StringTokenizer t, String lastToken) { 1.271 - try { 1.272 - return t.nextToken(); 1.273 - } 1.274 - catch (NoSuchElementException e) { 1.275 - throw new IllegalArgumentException("Missing expected token, last token: " + lastToken); 1.276 - } 1.277 - } 1.278 - 1.279 - /** 1.280 - * @param frequency a recurrence frequency string 1.281 - * @param until maximum recurrence date 1.282 - */ 1.283 - public Recur(final String frequency, final Date until) { 1.284 - // default week start is Monday per RFC5545 1.285 - calendarWeekStartDay = Calendar.MONDAY; 1.286 - this.frequency = frequency; 1.287 - this.until = until; 1.288 - validateFrequency(); 1.289 - } 1.290 - 1.291 - /** 1.292 - * @param frequency a recurrence frequency string 1.293 - * @param count maximum recurrence count 1.294 - */ 1.295 - public Recur(final String frequency, final int count) { 1.296 - // default week start is Monday per RFC5545 1.297 - calendarWeekStartDay = Calendar.MONDAY; 1.298 - this.frequency = frequency; 1.299 - this.count = count; 1.300 - validateFrequency(); 1.301 - } 1.302 - 1.303 - /** 1.304 - * @return Returns the dayList. 1.305 - */ 1.306 - public final WeekDayList getDayList() { 1.307 - if (dayList == null) { 1.308 - dayList = new WeekDayList(); 1.309 - } 1.310 - return dayList; 1.311 - } 1.312 - 1.313 - /** 1.314 - * @return Returns the hourList. 1.315 - */ 1.316 - public final NumberList getHourList() { 1.317 - if (hourList == null) { 1.318 - hourList = new NumberList(0, 23, false); 1.319 - } 1.320 - return hourList; 1.321 - } 1.322 - 1.323 - /** 1.324 - * @return Returns the minuteList. 1.325 - */ 1.326 - public final NumberList getMinuteList() { 1.327 - if (minuteList == null) { 1.328 - minuteList = new NumberList(0, 59, false); 1.329 - } 1.330 - return minuteList; 1.331 - } 1.332 - 1.333 - /** 1.334 - * @return Returns the monthDayList. 1.335 - */ 1.336 - public final NumberList getMonthDayList() { 1.337 - if (monthDayList == null) { 1.338 - monthDayList = new NumberList(1, 31, true); 1.339 - } 1.340 - return monthDayList; 1.341 - } 1.342 - 1.343 - /** 1.344 - * @return Returns the monthList. 1.345 - */ 1.346 - public final NumberList getMonthList() { 1.347 - if (monthList == null) { 1.348 - monthList = new NumberList(1, 12, false); 1.349 - } 1.350 - return monthList; 1.351 - } 1.352 - 1.353 - /** 1.354 - * @return Returns the secondList. 1.355 - */ 1.356 - public final NumberList getSecondList() { 1.357 - if (secondList == null) { 1.358 - secondList = new NumberList(0, 59, false); 1.359 - } 1.360 - return secondList; 1.361 - } 1.362 - 1.363 - /** 1.364 - * @return Returns the setPosList. 1.365 - */ 1.366 - public final NumberList getSetPosList() { 1.367 - if (setPosList == null) { 1.368 - setPosList = new NumberList(1, 366, true); 1.369 - } 1.370 - return setPosList; 1.371 - } 1.372 - 1.373 - /** 1.374 - * @return Returns the weekNoList. 1.375 - */ 1.376 - public final NumberList getWeekNoList() { 1.377 - if (weekNoList == null) { 1.378 - weekNoList = new NumberList(1, 53, true); 1.379 - } 1.380 - return weekNoList; 1.381 - } 1.382 - 1.383 - /** 1.384 - * @return Returns the yearDayList. 1.385 - */ 1.386 - public final NumberList getYearDayList() { 1.387 - if (yearDayList == null) { 1.388 - yearDayList = new NumberList(1, 366, true); 1.389 - } 1.390 - return yearDayList; 1.391 - } 1.392 - 1.393 - /** 1.394 - * @return Returns the count or -1 if the rule does not have a count. 1.395 - */ 1.396 - public final int getCount() { 1.397 - return count; 1.398 - } 1.399 - 1.400 - /** 1.401 - * @return Returns the experimentalValues. 1.402 - */ 1.403 - public final Map getExperimentalValues() { 1.404 - return experimentalValues; 1.405 - } 1.406 - 1.407 - /** 1.408 - * @return Returns the frequency. 1.409 - */ 1.410 - public final String getFrequency() { 1.411 - return frequency; 1.412 - } 1.413 - 1.414 - /** 1.415 - * @return Returns the interval or -1 if the rule does not have an interval defined. 1.416 - */ 1.417 - public final int getInterval() { 1.418 - return interval; 1.419 - } 1.420 - 1.421 - /** 1.422 - * @return Returns the until or null if there is none. 1.423 - */ 1.424 - public final Date getUntil() { 1.425 - return until; 1.426 - } 1.427 - 1.428 - /** 1.429 - * @return Returns the weekStartDay or null if there is none. 1.430 - */ 1.431 - public final String getWeekStartDay() { 1.432 - return weekStartDay; 1.433 - } 1.434 - 1.435 - /** 1.436 - * @param weekStartDay The weekStartDay to set. 1.437 - */ 1.438 - public final void setWeekStartDay(final String weekStartDay) { 1.439 - this.weekStartDay = weekStartDay; 1.440 - if (weekStartDay != null) { 1.441 - calendarWeekStartDay = WeekDay.getCalendarDay(new WeekDay(weekStartDay)); 1.442 - } 1.443 - } 1.444 - 1.445 - /** 1.446 - * {@inheritDoc} 1.447 - */ 1.448 - public final String toString() { 1.449 - final StringBuffer b = new StringBuffer(); 1.450 - b.append(FREQ); 1.451 - b.append('='); 1.452 - b.append(frequency); 1.453 - if (weekStartDay != null) { 1.454 - b.append(';'); 1.455 - b.append(WKST); 1.456 - b.append('='); 1.457 - b.append(weekStartDay); 1.458 - } 1.459 - if (until != null) { 1.460 - b.append(';'); 1.461 - b.append(UNTIL); 1.462 - b.append('='); 1.463 - // Note: date-time representations should always be in UTC time. 1.464 - b.append(until); 1.465 - } 1.466 - if (count >= 1) { 1.467 - b.append(';'); 1.468 - b.append(COUNT); 1.469 - b.append('='); 1.470 - b.append(count); 1.471 - } 1.472 - if (interval >= 1) { 1.473 - b.append(';'); 1.474 - b.append(INTERVAL); 1.475 - b.append('='); 1.476 - b.append(interval); 1.477 - } 1.478 - if (!getMonthList().isEmpty()) { 1.479 - b.append(';'); 1.480 - b.append(BYMONTH); 1.481 - b.append('='); 1.482 - b.append(monthList); 1.483 - } 1.484 - if (!getWeekNoList().isEmpty()) { 1.485 - b.append(';'); 1.486 - b.append(BYWEEKNO); 1.487 - b.append('='); 1.488 - b.append(weekNoList); 1.489 - } 1.490 - if (!getYearDayList().isEmpty()) { 1.491 - b.append(';'); 1.492 - b.append(BYYEARDAY); 1.493 - b.append('='); 1.494 - b.append(yearDayList); 1.495 - } 1.496 - if (!getMonthDayList().isEmpty()) { 1.497 - b.append(';'); 1.498 - b.append(BYMONTHDAY); 1.499 - b.append('='); 1.500 - b.append(monthDayList); 1.501 - } 1.502 - if (!getDayList().isEmpty()) { 1.503 - b.append(';'); 1.504 - b.append(BYDAY); 1.505 - b.append('='); 1.506 - b.append(dayList); 1.507 - } 1.508 - if (!getHourList().isEmpty()) { 1.509 - b.append(';'); 1.510 - b.append(BYHOUR); 1.511 - b.append('='); 1.512 - b.append(hourList); 1.513 - } 1.514 - if (!getMinuteList().isEmpty()) { 1.515 - b.append(';'); 1.516 - b.append(BYMINUTE); 1.517 - b.append('='); 1.518 - b.append(minuteList); 1.519 - } 1.520 - if (!getSecondList().isEmpty()) { 1.521 - b.append(';'); 1.522 - b.append(BYSECOND); 1.523 - b.append('='); 1.524 - b.append(secondList); 1.525 - } 1.526 - if (!getSetPosList().isEmpty()) { 1.527 - b.append(';'); 1.528 - b.append(BYSETPOS); 1.529 - b.append('='); 1.530 - b.append(setPosList); 1.531 - } 1.532 - return b.toString(); 1.533 - } 1.534 - 1.535 - /** 1.536 - * Returns a list of start dates in the specified period represented by this recur. Any date fields not specified by 1.537 - * this recur are retained from the period start, and as such you should ensure the period start is initialised 1.538 - * correctly. 1.539 - * @param periodStart the start of the period 1.540 - * @param periodEnd the end of the period 1.541 - * @param value the type of dates to generate (i.e. date/date-time) 1.542 - * @return a list of dates 1.543 - */ 1.544 - public final DateList getDates(final Date periodStart, 1.545 - final Date periodEnd, final Value value) { 1.546 - return getDates(periodStart, periodStart, periodEnd, value, -1); 1.547 - } 1.548 - 1.549 - /** 1.550 - * Convenience method for retrieving recurrences in a specified period. 1.551 - * @param seed a seed date for generating recurrence instances 1.552 - * @param period the period of returned recurrence dates 1.553 - * @param value type of dates to generate 1.554 - * @return a list of dates 1.555 - */ 1.556 - public final DateList getDates(final Date seed, final Period period, 1.557 - final Value value) { 1.558 - return getDates(seed, period.getStart(), period.getEnd(), value, -1); 1.559 - } 1.560 - 1.561 - /** 1.562 - * Returns a list of start dates in the specified period represented by this recur. This method includes a base date 1.563 - * argument, which indicates the start of the fist occurrence of this recurrence. The base date is used to inject 1.564 - * default values to return a set of dates in the correct format. For example, if the search start date (start) is 1.565 - * Wed, Mar 23, 12:19PM, but the recurrence is Mon - Fri, 9:00AM - 5:00PM, the start dates returned should all be at 1.566 - * 9:00AM, and not 12:19PM. 1.567 - * @return a list of dates represented by this recur instance 1.568 - * @param seed the start date of this Recurrence's first instance 1.569 - * @param periodStart the start of the period 1.570 - * @param periodEnd the end of the period 1.571 - * @param value the type of dates to generate (i.e. date/date-time) 1.572 - */ 1.573 - public final DateList getDates(final Date seed, final Date periodStart, 1.574 - final Date periodEnd, final Value value) { 1.575 - return getDates(seed, periodStart, periodEnd, value, -1); 1.576 - } 1.577 - 1.578 - /** 1.579 - * Returns a list of start dates in the specified period represented by this recur. This method includes a base date 1.580 - * argument, which indicates the start of the fist occurrence of this recurrence. The base date is used to inject 1.581 - * default values to return a set of dates in the correct format. For example, if the search start date (start) is 1.582 - * Wed, Mar 23, 12:19PM, but the recurrence is Mon - Fri, 9:00AM - 5:00PM, the start dates returned should all be at 1.583 - * 9:00AM, and not 12:19PM. 1.584 - * @return a list of dates represented by this recur instance 1.585 - * @param seed the start date of this Recurrence's first instance 1.586 - * @param periodStart the start of the period 1.587 - * @param periodEnd the end of the period 1.588 - * @param value the type of dates to generate (i.e. date/date-time) 1.589 - * @param maxCount limits the number of instances returned. Up to one years 1.590 - * worth extra may be returned. Less than 0 means no limit 1.591 - */ 1.592 - public final DateList getDates(final Date seed, final Date periodStart, 1.593 - final Date periodEnd, final Value value, 1.594 - final int maxCount) { 1.595 - 1.596 - final DateList dates = new DateList(value); 1.597 - if (seed instanceof DateTime) { 1.598 - if (((DateTime) seed).isUtc()) { 1.599 - dates.setUtc(true); 1.600 - } 1.601 - else { 1.602 - dates.setTimeZone(((DateTime) seed).getTimeZone()); 1.603 - } 1.604 - } 1.605 - final Calendar cal = getCalendarInstance(seed, true); 1.606 - 1.607 - // optimize the start time for selecting candidates 1.608 - // (only applicable where a COUNT is not specified) 1.609 - if (getCount() < 1) { 1.610 - final Calendar seededCal = (Calendar) cal.clone(); 1.611 - while (seededCal.getTime().before(periodStart)) { 1.612 - cal.setTime(seededCal.getTime()); 1.613 - increment(seededCal); 1.614 - } 1.615 - } 1.616 - 1.617 - int invalidCandidateCount = 0; 1.618 - int noCandidateIncrementCount = 0; 1.619 - Date candidate = null; 1.620 - while ((maxCount < 0) || (dates.size() < maxCount)) { 1.621 - final Date candidateSeed = Dates.getInstance(cal.getTime(), value); 1.622 - 1.623 - if (getUntil() != null && candidate != null 1.624 - && candidate.after(getUntil())) { 1.625 - 1.626 - break; 1.627 - } 1.628 - if (periodEnd != null && candidate != null 1.629 - && candidate.after(periodEnd)) { 1.630 - 1.631 - break; 1.632 - } 1.633 - if (getCount() >= 1 1.634 - && (dates.size() + invalidCandidateCount) >= getCount()) { 1.635 - 1.636 - break; 1.637 - } 1.638 - 1.639 -// if (Value.DATE_TIME.equals(value)) { 1.640 - if (candidateSeed instanceof DateTime) { 1.641 - if (dates.isUtc()) { 1.642 - ((DateTime) candidateSeed).setUtc(true); 1.643 - } 1.644 - else { 1.645 - ((DateTime) candidateSeed).setTimeZone(dates.getTimeZone()); 1.646 - } 1.647 - } 1.648 - 1.649 - final DateList candidates = getCandidates(candidateSeed, value); 1.650 - if (!candidates.isEmpty()) { 1.651 - noCandidateIncrementCount = 0; 1.652 - // sort candidates for identifying when UNTIL date is exceeded.. 1.653 - Collections.sort(candidates); 1.654 - for (final Iterator i = candidates.iterator(); i.hasNext();) { 1.655 - candidate = (Date) i.next(); 1.656 - // don't count candidates that occur before the seed date.. 1.657 - if (!candidate.before(seed)) { 1.658 - // candidates exclusive of periodEnd.. 1.659 - if (candidate.before(periodStart) 1.660 - || !candidate.before(periodEnd)) { 1.661 - invalidCandidateCount++; 1.662 - } else if (getCount() >= 1 1.663 - && (dates.size() + invalidCandidateCount) >= getCount()) { 1.664 - break; 1.665 - } else if (!(getUntil() != null 1.666 - && candidate.after(getUntil()))) { 1.667 - dates.add(candidate); 1.668 - } 1.669 - } 1.670 - } 1.671 - } else { 1.672 - noCandidateIncrementCount++; 1.673 - if ((maxIncrementCount > 0) && (noCandidateIncrementCount > maxIncrementCount)) { 1.674 - break; 1.675 - } 1.676 - } 1.677 - increment(cal); 1.678 - } 1.679 - // sort final list.. 1.680 - Collections.sort(dates); 1.681 - return dates; 1.682 - } 1.683 - 1.684 - /** 1.685 - * Returns the the next date of this recurrence given a seed date 1.686 - * and start date. The seed date indicates the start of the fist 1.687 - * occurrence of this recurrence. The start date is the 1.688 - * starting date to search for the next recurrence. Return null 1.689 - * if there is no occurrence date after start date. 1.690 - * @return the next date in the recurrence series after startDate 1.691 - * @param seed the start date of this Recurrence's first instance 1.692 - * @param startDate the date to start the search 1.693 - */ 1.694 - public final Date getNextDate(final Date seed, final Date startDate) { 1.695 - 1.696 - final Calendar cal = getCalendarInstance(seed, true); 1.697 - 1.698 - // optimize the start time for selecting candidates 1.699 - // (only applicable where a COUNT is not specified) 1.700 - if (getCount() < 1) { 1.701 - final Calendar seededCal = (Calendar) cal.clone(); 1.702 - while (seededCal.getTime().before(startDate)) { 1.703 - cal.setTime(seededCal.getTime()); 1.704 - increment(seededCal); 1.705 - } 1.706 - } 1.707 - 1.708 - int invalidCandidateCount = 0; 1.709 - int noCandidateIncrementCount = 0; 1.710 - Date candidate = null; 1.711 - final Value value = seed instanceof DateTime ? Value.DATE_TIME : Value.DATE; 1.712 - 1.713 - while (true) { 1.714 - final Date candidateSeed = Dates.getInstance(cal.getTime(), value); 1.715 - 1.716 - if (getUntil() != null && candidate != null && candidate.after(getUntil())) { 1.717 - break; 1.718 - } 1.719 - 1.720 - if (getCount() > 0 && invalidCandidateCount >= getCount()) { 1.721 - break; 1.722 - } 1.723 - 1.724 - if (Value.DATE_TIME.equals(value)) { 1.725 - if (((DateTime) seed).isUtc()) { 1.726 - ((DateTime) candidateSeed).setUtc(true); 1.727 - } 1.728 - else { 1.729 - ((DateTime) candidateSeed).setTimeZone(((DateTime) seed).getTimeZone()); 1.730 - } 1.731 - } 1.732 - 1.733 - final DateList candidates = getCandidates(candidateSeed, value); 1.734 - if (!candidates.isEmpty()) { 1.735 - noCandidateIncrementCount = 0; 1.736 - // sort candidates for identifying when UNTIL date is exceeded.. 1.737 - Collections.sort(candidates); 1.738 - 1.739 - for (final Iterator i = candidates.iterator(); i.hasNext();) { 1.740 - candidate = (Date) i.next(); 1.741 - // don't count candidates that occur before the seed date.. 1.742 - if (!candidate.before(seed)) { 1.743 - // Candidate must be after startDate because 1.744 - // we want the NEXT occurrence 1.745 - if (!candidate.after(startDate)) { 1.746 - invalidCandidateCount++; 1.747 - } else if (getCount() > 0 1.748 - && invalidCandidateCount >= getCount()) { 1.749 - break; 1.750 - } else if (!(getUntil() != null 1.751 - && candidate.after(getUntil()))) { 1.752 - return candidate; 1.753 - } 1.754 - } 1.755 - } 1.756 - } else { 1.757 - noCandidateIncrementCount++; 1.758 - if ((maxIncrementCount > 0) && (noCandidateIncrementCount > maxIncrementCount)) { 1.759 - break; 1.760 - } 1.761 - } 1.762 - increment(cal); 1.763 - } 1.764 - return null; 1.765 - } 1.766 - 1.767 - /** 1.768 - * Increments the specified calendar according to the frequency and interval specified in this recurrence rule. 1.769 - * @param cal a java.util.Calendar to increment 1.770 - */ 1.771 - private void increment(final Calendar cal) { 1.772 - // initialise interval.. 1.773 - final int calInterval = (getInterval() >= 1) ? getInterval() : 1; 1.774 - cal.add(calIncField, calInterval); 1.775 - } 1.776 - 1.777 - /** 1.778 - * Returns a list of possible dates generated from the applicable BY* rules, using the specified date as a seed. 1.779 - * @param date the seed date 1.780 - * @param value the type of date list to return 1.781 - * @return a DateList 1.782 - */ 1.783 - private DateList getCandidates(final Date date, final Value value) { 1.784 - DateList dates = new DateList(value); 1.785 - if (date instanceof DateTime) { 1.786 - if (((DateTime) date).isUtc()) { 1.787 - dates.setUtc(true); 1.788 - } 1.789 - else { 1.790 - dates.setTimeZone(((DateTime) date).getTimeZone()); 1.791 - } 1.792 - } 1.793 - dates.add(date); 1.794 - dates = getMonthVariants(dates); 1.795 - // debugging.. 1.796 - if (log.isDebugEnabled()) { 1.797 - log.debug("Dates after BYMONTH processing: " + dates); 1.798 - } 1.799 - dates = getWeekNoVariants(dates); 1.800 - // debugging.. 1.801 - if (log.isDebugEnabled()) { 1.802 - log.debug("Dates after BYWEEKNO processing: " + dates); 1.803 - } 1.804 - dates = getYearDayVariants(dates); 1.805 - // debugging.. 1.806 - if (log.isDebugEnabled()) { 1.807 - log.debug("Dates after BYYEARDAY processing: " + dates); 1.808 - } 1.809 - dates = getMonthDayVariants(dates); 1.810 - // debugging.. 1.811 - if (log.isDebugEnabled()) { 1.812 - log.debug("Dates after BYMONTHDAY processing: " + dates); 1.813 - } 1.814 - dates = getDayVariants(dates); 1.815 - // debugging.. 1.816 - if (log.isDebugEnabled()) { 1.817 - log.debug("Dates after BYDAY processing: " + dates); 1.818 - } 1.819 - dates = getHourVariants(dates); 1.820 - // debugging.. 1.821 - if (log.isDebugEnabled()) { 1.822 - log.debug("Dates after BYHOUR processing: " + dates); 1.823 - } 1.824 - dates = getMinuteVariants(dates); 1.825 - // debugging.. 1.826 - if (log.isDebugEnabled()) { 1.827 - log.debug("Dates after BYMINUTE processing: " + dates); 1.828 - } 1.829 - dates = getSecondVariants(dates); 1.830 - // debugging.. 1.831 - if (log.isDebugEnabled()) { 1.832 - log.debug("Dates after BYSECOND processing: " + dates); 1.833 - } 1.834 - dates = applySetPosRules(dates); 1.835 - // debugging.. 1.836 - if (log.isDebugEnabled()) { 1.837 - log.debug("Dates after SETPOS processing: " + dates); 1.838 - } 1.839 - return dates; 1.840 - } 1.841 - 1.842 - /** 1.843 - * Applies BYSETPOS rules to <code>dates</code>. Valid positions are from 1 to the size of the date list. Invalid 1.844 - * positions are ignored. 1.845 - * @param dates 1.846 - */ 1.847 - private DateList applySetPosRules(final DateList dates) { 1.848 - // return if no SETPOS rules specified.. 1.849 - if (getSetPosList().isEmpty()) { 1.850 - return dates; 1.851 - } 1.852 - // sort the list before processing.. 1.853 - Collections.sort(dates); 1.854 - final DateList setPosDates = getDateListInstance(dates); 1.855 - final int size = dates.size(); 1.856 - for (final Iterator i = getSetPosList().iterator(); i.hasNext();) { 1.857 - final Integer setPos = (Integer) i.next(); 1.858 - final int pos = setPos.intValue(); 1.859 - if (pos > 0 && pos <= size) { 1.860 - setPosDates.add(dates.get(pos - 1)); 1.861 - } 1.862 - else if (pos < 0 && pos >= -size) { 1.863 - setPosDates.add(dates.get(size + pos)); 1.864 - } 1.865 - } 1.866 - return setPosDates; 1.867 - } 1.868 - 1.869 - /** 1.870 - * Applies BYMONTH rules specified in this Recur instance to the specified date list. If no BYMONTH rules are 1.871 - * specified the date list is returned unmodified. 1.872 - * @param dates 1.873 - * @return 1.874 - */ 1.875 - private DateList getMonthVariants(final DateList dates) { 1.876 - if (getMonthList().isEmpty()) { 1.877 - return dates; 1.878 - } 1.879 - final DateList monthlyDates = getDateListInstance(dates); 1.880 - for (final Iterator i = dates.iterator(); i.hasNext();) { 1.881 - final Date date = (Date) i.next(); 1.882 - final Calendar cal = getCalendarInstance(date, true); 1.883 - 1.884 - for (final Iterator j = getMonthList().iterator(); j.hasNext();) { 1.885 - final Integer month = (Integer) j.next(); 1.886 - // Java months are zero-based.. 1.887 -// cal.set(Calendar.MONTH, month.intValue() - 1); 1.888 - cal.roll(Calendar.MONTH, (month.intValue() - 1) - cal.get(Calendar.MONTH)); 1.889 - monthlyDates.add(Dates.getInstance(cal.getTime(), monthlyDates.getType())); 1.890 - } 1.891 - } 1.892 - return monthlyDates; 1.893 - } 1.894 - 1.895 - /** 1.896 - * Applies BYWEEKNO rules specified in this Recur instance to the specified date list. If no BYWEEKNO rules are 1.897 - * specified the date list is returned unmodified. 1.898 - * @param dates 1.899 - * @return 1.900 - */ 1.901 - private DateList getWeekNoVariants(final DateList dates) { 1.902 - if (getWeekNoList().isEmpty()) { 1.903 - return dates; 1.904 - } 1.905 - final DateList weekNoDates = getDateListInstance(dates); 1.906 - for (final Iterator i = dates.iterator(); i.hasNext();) { 1.907 - final Date date = (Date) i.next(); 1.908 - final Calendar cal = getCalendarInstance(date, true); 1.909 - for (final Iterator j = getWeekNoList().iterator(); j.hasNext();) { 1.910 - final Integer weekNo = (Integer) j.next(); 1.911 - cal.set(Calendar.WEEK_OF_YEAR, Dates.getAbsWeekNo(cal.getTime(), weekNo.intValue())); 1.912 - weekNoDates.add(Dates.getInstance(cal.getTime(), weekNoDates.getType())); 1.913 - } 1.914 - } 1.915 - return weekNoDates; 1.916 - } 1.917 - 1.918 - /** 1.919 - * Applies BYYEARDAY rules specified in this Recur instance to the specified date list. If no BYYEARDAY rules are 1.920 - * specified the date list is returned unmodified. 1.921 - * @param dates 1.922 - * @return 1.923 - */ 1.924 - private DateList getYearDayVariants(final DateList dates) { 1.925 - if (getYearDayList().isEmpty()) { 1.926 - return dates; 1.927 - } 1.928 - final DateList yearDayDates = getDateListInstance(dates); 1.929 - for (final Iterator i = dates.iterator(); i.hasNext();) { 1.930 - final Date date = (Date) i.next(); 1.931 - final Calendar cal = getCalendarInstance(date, true); 1.932 - for (final Iterator j = getYearDayList().iterator(); j.hasNext();) { 1.933 - final Integer yearDay = (Integer) j.next(); 1.934 - cal.set(Calendar.DAY_OF_YEAR, Dates.getAbsYearDay(cal.getTime(), yearDay.intValue())); 1.935 - yearDayDates.add(Dates.getInstance(cal.getTime(), yearDayDates.getType())); 1.936 - } 1.937 - } 1.938 - return yearDayDates; 1.939 - } 1.940 - 1.941 - /** 1.942 - * Applies BYMONTHDAY rules specified in this Recur instance to the specified date list. If no BYMONTHDAY rules are 1.943 - * specified the date list is returned unmodified. 1.944 - * @param dates 1.945 - * @return 1.946 - */ 1.947 - private DateList getMonthDayVariants(final DateList dates) { 1.948 - if (getMonthDayList().isEmpty()) { 1.949 - return dates; 1.950 - } 1.951 - final DateList monthDayDates = getDateListInstance(dates); 1.952 - for (final Iterator i = dates.iterator(); i.hasNext();) { 1.953 - final Date date = (Date) i.next(); 1.954 - final Calendar cal = getCalendarInstance(date, false); 1.955 - for (final Iterator j = getMonthDayList().iterator(); j.hasNext();) { 1.956 - final Integer monthDay = (Integer) j.next(); 1.957 - try { 1.958 - cal.set(Calendar.DAY_OF_MONTH, Dates.getAbsMonthDay(cal.getTime(), monthDay.intValue())); 1.959 - monthDayDates.add(Dates.getInstance(cal.getTime(), monthDayDates.getType())); 1.960 - } 1.961 - catch (IllegalArgumentException iae) { 1.962 - if (log.isTraceEnabled()) { 1.963 - log.trace("Invalid day of month: " + Dates.getAbsMonthDay(cal 1.964 - .getTime(), monthDay.intValue())); 1.965 - } 1.966 - } 1.967 - } 1.968 - } 1.969 - return monthDayDates; 1.970 - } 1.971 - 1.972 - /** 1.973 - * Applies BYDAY rules specified in this Recur instance to the specified date list. If no BYDAY rules are specified 1.974 - * the date list is returned unmodified. 1.975 - * @param dates 1.976 - * @return 1.977 - */ 1.978 - private DateList getDayVariants(final DateList dates) { 1.979 - if (getDayList().isEmpty()) { 1.980 - return dates; 1.981 - } 1.982 - final DateList weekDayDates = getDateListInstance(dates); 1.983 - for (final Iterator i = dates.iterator(); i.hasNext();) { 1.984 - final Date date = (Date) i.next(); 1.985 - for (final Iterator j = getDayList().iterator(); j.hasNext();) { 1.986 - final WeekDay weekDay = (WeekDay) j.next(); 1.987 - // if BYYEARDAY or BYMONTHDAY is specified filter existing 1.988 - // list.. 1.989 - if (!getYearDayList().isEmpty() || !getMonthDayList().isEmpty()) { 1.990 - final Calendar cal = getCalendarInstance(date, true); 1.991 - if (weekDay.equals(WeekDay.getWeekDay(cal))) { 1.992 - weekDayDates.add(date); 1.993 - } 1.994 - } 1.995 - else { 1.996 - weekDayDates.addAll(getAbsWeekDays(date, dates.getType(), weekDay)); 1.997 - } 1.998 - } 1.999 - } 1.1000 - return weekDayDates; 1.1001 - } 1.1002 - 1.1003 - /** 1.1004 - * Returns a list of applicable dates corresponding to the specified week day in accordance with the frequency 1.1005 - * specified by this recurrence rule. 1.1006 - * @param date 1.1007 - * @param weekDay 1.1008 - * @return 1.1009 - */ 1.1010 - private List getAbsWeekDays(final Date date, final Value type, final WeekDay weekDay) { 1.1011 - final Calendar cal = getCalendarInstance(date, true); 1.1012 - final DateList days = new DateList(type); 1.1013 - if (date instanceof DateTime) { 1.1014 - if (((DateTime) date).isUtc()) { 1.1015 - days.setUtc(true); 1.1016 - } 1.1017 - else { 1.1018 - days.setTimeZone(((DateTime) date).getTimeZone()); 1.1019 - } 1.1020 - } 1.1021 - final int calDay = WeekDay.getCalendarDay(weekDay); 1.1022 - if (calDay == -1) { 1.1023 - // a matching weekday cannot be identified.. 1.1024 - return days; 1.1025 - } 1.1026 - if (DAILY.equals(getFrequency())) { 1.1027 - if (cal.get(Calendar.DAY_OF_WEEK) == calDay) { 1.1028 - days.add(Dates.getInstance(cal.getTime(), type)); 1.1029 - } 1.1030 - } 1.1031 - else if (WEEKLY.equals(getFrequency()) || !getWeekNoList().isEmpty()) { 1.1032 - final int weekNo = cal.get(Calendar.WEEK_OF_YEAR); 1.1033 - // construct a list of possible week days.. 1.1034 - cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek()); 1.1035 - while (cal.get(Calendar.DAY_OF_WEEK) != calDay) { 1.1036 - cal.add(Calendar.DAY_OF_WEEK, 1); 1.1037 - } 1.1038 -// final int weekNo = cal.get(Calendar.WEEK_OF_YEAR); 1.1039 - if (cal.get(Calendar.WEEK_OF_YEAR) == weekNo) { 1.1040 - days.add(Dates.getInstance(cal.getTime(), type)); 1.1041 -// cal.add(Calendar.DAY_OF_WEEK, Dates.DAYS_PER_WEEK); 1.1042 - } 1.1043 - } 1.1044 - else if (MONTHLY.equals(getFrequency()) || !getMonthList().isEmpty()) { 1.1045 - final int month = cal.get(Calendar.MONTH); 1.1046 - // construct a list of possible month days.. 1.1047 - cal.set(Calendar.DAY_OF_MONTH, 1); 1.1048 - while (cal.get(Calendar.DAY_OF_WEEK) != calDay) { 1.1049 - cal.add(Calendar.DAY_OF_MONTH, 1); 1.1050 - } 1.1051 - while (cal.get(Calendar.MONTH) == month) { 1.1052 - days.add(Dates.getInstance(cal.getTime(), type)); 1.1053 - cal.add(Calendar.DAY_OF_MONTH, Dates.DAYS_PER_WEEK); 1.1054 - } 1.1055 - } 1.1056 - else if (YEARLY.equals(getFrequency())) { 1.1057 - final int year = cal.get(Calendar.YEAR); 1.1058 - // construct a list of possible year days.. 1.1059 - cal.set(Calendar.DAY_OF_YEAR, 1); 1.1060 - while (cal.get(Calendar.DAY_OF_WEEK) != calDay) { 1.1061 - cal.add(Calendar.DAY_OF_YEAR, 1); 1.1062 - } 1.1063 - while (cal.get(Calendar.YEAR) == year) { 1.1064 - days.add(Dates.getInstance(cal.getTime(), type)); 1.1065 - cal.add(Calendar.DAY_OF_YEAR, Dates.DAYS_PER_WEEK); 1.1066 - } 1.1067 - } 1.1068 - return getOffsetDates(days, weekDay.getOffset()); 1.1069 - } 1.1070 - 1.1071 - /** 1.1072 - * Returns a single-element sublist containing the element of <code>list</code> at <code>offset</code>. Valid 1.1073 - * offsets are from 1 to the size of the list. If an invalid offset is supplied, all elements from <code>list</code> 1.1074 - * are added to <code>sublist</code>. 1.1075 - * @param list 1.1076 - * @param offset 1.1077 - * @param sublist 1.1078 - */ 1.1079 - private List getOffsetDates(final DateList dates, final int offset) { 1.1080 - if (offset == 0) { 1.1081 - return dates; 1.1082 - } 1.1083 - final List offsetDates = getDateListInstance(dates); 1.1084 - final int size = dates.size(); 1.1085 - if (offset < 0 && offset >= -size) { 1.1086 - offsetDates.add(dates.get(size + offset)); 1.1087 - } 1.1088 - else if (offset > 0 && offset <= size) { 1.1089 - offsetDates.add(dates.get(offset - 1)); 1.1090 - } 1.1091 - return offsetDates; 1.1092 - } 1.1093 - 1.1094 - /** 1.1095 - * Applies BYHOUR rules specified in this Recur instance to the specified date list. If no BYHOUR rules are 1.1096 - * specified the date list is returned unmodified. 1.1097 - * @param dates 1.1098 - * @return 1.1099 - */ 1.1100 - private DateList getHourVariants(final DateList dates) { 1.1101 - if (getHourList().isEmpty()) { 1.1102 - return dates; 1.1103 - } 1.1104 - final DateList hourlyDates = getDateListInstance(dates); 1.1105 - for (final Iterator i = dates.iterator(); i.hasNext();) { 1.1106 - final Date date = (Date) i.next(); 1.1107 - final Calendar cal = getCalendarInstance(date, true); 1.1108 - for (final Iterator j = getHourList().iterator(); j.hasNext();) { 1.1109 - final Integer hour = (Integer) j.next(); 1.1110 - cal.set(Calendar.HOUR_OF_DAY, hour.intValue()); 1.1111 - hourlyDates.add(Dates.getInstance(cal.getTime(), hourlyDates.getType())); 1.1112 - } 1.1113 - } 1.1114 - return hourlyDates; 1.1115 - } 1.1116 - 1.1117 - /** 1.1118 - * Applies BYMINUTE rules specified in this Recur instance to the specified date list. If no BYMINUTE rules are 1.1119 - * specified the date list is returned unmodified. 1.1120 - * @param dates 1.1121 - * @return 1.1122 - */ 1.1123 - private DateList getMinuteVariants(final DateList dates) { 1.1124 - if (getMinuteList().isEmpty()) { 1.1125 - return dates; 1.1126 - } 1.1127 - final DateList minutelyDates = getDateListInstance(dates); 1.1128 - for (final Iterator i = dates.iterator(); i.hasNext();) { 1.1129 - final Date date = (Date) i.next(); 1.1130 - final Calendar cal = getCalendarInstance(date, true); 1.1131 - for (final Iterator j = getMinuteList().iterator(); j.hasNext();) { 1.1132 - final Integer minute = (Integer) j.next(); 1.1133 - cal.set(Calendar.MINUTE, minute.intValue()); 1.1134 - minutelyDates.add(Dates.getInstance(cal.getTime(), minutelyDates.getType())); 1.1135 - } 1.1136 - } 1.1137 - return minutelyDates; 1.1138 - } 1.1139 - 1.1140 - /** 1.1141 - * Applies BYSECOND rules specified in this Recur instance to the specified date list. If no BYSECOND rules are 1.1142 - * specified the date list is returned unmodified. 1.1143 - * @param dates 1.1144 - * @return 1.1145 - */ 1.1146 - private DateList getSecondVariants(final DateList dates) { 1.1147 - if (getSecondList().isEmpty()) { 1.1148 - return dates; 1.1149 - } 1.1150 - final DateList secondlyDates = getDateListInstance(dates); 1.1151 - for (final Iterator i = dates.iterator(); i.hasNext();) { 1.1152 - final Date date = (Date) i.next(); 1.1153 - final Calendar cal = getCalendarInstance(date, true); 1.1154 - for (final Iterator j = getSecondList().iterator(); j.hasNext();) { 1.1155 - final Integer second = (Integer) j.next(); 1.1156 - cal.set(Calendar.SECOND, second.intValue()); 1.1157 - secondlyDates.add(Dates.getInstance(cal.getTime(), secondlyDates.getType())); 1.1158 - } 1.1159 - } 1.1160 - return secondlyDates; 1.1161 - } 1.1162 - 1.1163 - private void validateFrequency() { 1.1164 - if (frequency == null) { 1.1165 - throw new IllegalArgumentException( 1.1166 - "A recurrence rule MUST contain a FREQ rule part."); 1.1167 - } 1.1168 - if (SECONDLY.equals(getFrequency())) { 1.1169 - calIncField = Calendar.SECOND; 1.1170 - } 1.1171 - else if (MINUTELY.equals(getFrequency())) { 1.1172 - calIncField = Calendar.MINUTE; 1.1173 - } 1.1174 - else if (HOURLY.equals(getFrequency())) { 1.1175 - calIncField = Calendar.HOUR_OF_DAY; 1.1176 - } 1.1177 - else if (DAILY.equals(getFrequency())) { 1.1178 - calIncField = Calendar.DAY_OF_YEAR; 1.1179 - } 1.1180 - else if (WEEKLY.equals(getFrequency())) { 1.1181 - calIncField = Calendar.WEEK_OF_YEAR; 1.1182 - } 1.1183 - else if (MONTHLY.equals(getFrequency())) { 1.1184 - calIncField = Calendar.MONTH; 1.1185 - } 1.1186 - else if (YEARLY.equals(getFrequency())) { 1.1187 - calIncField = Calendar.YEAR; 1.1188 - } 1.1189 - else { 1.1190 - throw new IllegalArgumentException("Invalid FREQ rule part '" 1.1191 - + frequency + "' in recurrence rule"); 1.1192 - } 1.1193 - } 1.1194 - 1.1195 - /** 1.1196 - * @param count The count to set. 1.1197 - */ 1.1198 - public final void setCount(final int count) { 1.1199 - this.count = count; 1.1200 - this.until = null; 1.1201 - } 1.1202 - 1.1203 - /** 1.1204 - * @param frequency The frequency to set. 1.1205 - */ 1.1206 - public final void setFrequency(final String frequency) { 1.1207 - this.frequency = frequency; 1.1208 - validateFrequency(); 1.1209 - } 1.1210 - 1.1211 - /** 1.1212 - * @param interval The interval to set. 1.1213 - */ 1.1214 - public final void setInterval(final int interval) { 1.1215 - this.interval = interval; 1.1216 - } 1.1217 - 1.1218 - /** 1.1219 - * @param until The until to set. 1.1220 - */ 1.1221 - public final void setUntil(final Date until) { 1.1222 - this.until = until; 1.1223 - this.count = -1; 1.1224 - } 1.1225 - 1.1226 - /** 1.1227 - * Construct a Calendar object and sets the time. 1.1228 - * @param date 1.1229 - * @param lenient 1.1230 - * @return 1.1231 - */ 1.1232 - private Calendar getCalendarInstance(final Date date, final boolean lenient) { 1.1233 - Calendar cal = Dates.getCalendarInstance(date); 1.1234 - // A week should have at least 4 days to be considered as such per RFC5545 1.1235 - cal.setMinimalDaysInFirstWeek(4); 1.1236 - cal.setFirstDayOfWeek(calendarWeekStartDay); 1.1237 - cal.setLenient(lenient); 1.1238 - cal.setTime(date); 1.1239 - 1.1240 - return cal; 1.1241 - } 1.1242 - 1.1243 - /** 1.1244 - * @param stream 1.1245 - * @throws IOException 1.1246 - * @throws ClassNotFoundException 1.1247 - */ 1.1248 - private void readObject(final java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { 1.1249 - stream.defaultReadObject(); 1.1250 - log = LogFactory.getLog(Recur.class); 1.1251 - } 1.1252 - 1.1253 - /** 1.1254 - * Instantiate a new datelist with the same type, timezone and utc settings 1.1255 - * as the origList. 1.1256 - * @param origList 1.1257 - * @return a new empty list. 1.1258 - */ 1.1259 - private static DateList getDateListInstance(final DateList origList) { 1.1260 - final DateList list = new DateList(origList.getType()); 1.1261 - if (origList.isUtc()) { 1.1262 - list.setUtc(true); 1.1263 - } else { 1.1264 - list.setTimeZone(origList.getTimeZone()); 1.1265 - } 1.1266 - return list; 1.1267 - } 1.1268 - 1.1269 -}