001package biweekly.component; 002 003import java.util.List; 004 005import biweekly.ICalVersion; 006import biweekly.Warning; 007import biweekly.property.Comment; 008import biweekly.property.DateStart; 009import biweekly.property.ExceptionDates; 010import biweekly.property.RecurrenceDates; 011import biweekly.property.RecurrenceRule; 012import biweekly.property.TimezoneName; 013import biweekly.property.TimezoneOffsetFrom; 014import biweekly.property.TimezoneOffsetTo; 015import biweekly.util.DateTimeComponents; 016import biweekly.util.ICalDate; 017import biweekly.util.Recurrence; 018import biweekly.util.UtcOffset; 019 020/* 021 Copyright (c) 2013-2015, Michael Angstadt 022 All rights reserved. 023 024 Redistribution and use in source and binary forms, with or without 025 modification, are permitted provided that the following conditions are met: 026 027 1. Redistributions of source code must retain the above copyright notice, this 028 list of conditions and the following disclaimer. 029 2. Redistributions in binary form must reproduce the above copyright notice, 030 this list of conditions and the following disclaimer in the documentation 031 and/or other materials provided with the distribution. 032 033 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 034 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 035 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 036 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 037 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 038 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 039 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 040 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 041 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 042 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 043 */ 044 045/** 046 * Represents a timezone observance (i.e. "daylight savings" and "standard" 047 * times). 048 * @author Michael Angstadt 049 * @see DaylightSavingsTime 050 * @see StandardTime 051 * @see <a href="http://tools.ietf.org/html/rfc5545#page-62">RFC 5545 052 * p.62-71</a> 053 * @see <a href="http://tools.ietf.org/html/rfc2445#page-60">RFC 2445 p.60-7</a> 054 */ 055public class Observance extends ICalComponent { 056 /** 057 * Gets the date that the timezone observance starts. 058 * @return the start date or null if not set 059 * @see <a href="http://tools.ietf.org/html/rfc5545#page-97">RFC 5545 060 * p.97-8</a> 061 */ 062 public DateStart getDateStart() { 063 return getProperty(DateStart.class); 064 } 065 066 /** 067 * Sets the date that the timezone observance starts. 068 * @param dateStart the start date or null to remove 069 * @see <a href="http://tools.ietf.org/html/rfc5545#page-97">RFC 5545 070 * p.97-8</a> 071 */ 072 public void setDateStart(DateStart dateStart) { 073 setProperty(DateStart.class, dateStart); 074 } 075 076 /** 077 * Sets the date that the timezone observance starts. 078 * @param date the start date or null to remove 079 * @return the property that was created 080 * @see <a href="http://tools.ietf.org/html/rfc5545#page-97">RFC 5545 081 * p.97-8</a> 082 */ 083 public DateStart setDateStart(ICalDate date) { 084 DateStart prop = (date == null) ? null : new DateStart(date); 085 setDateStart(prop); 086 return prop; 087 } 088 089 /** 090 * Sets the date that the timezone observance starts. 091 * @param rawComponents the start date or null to remove 092 * @return the property that was created 093 * @see <a href="http://tools.ietf.org/html/rfc5545#page-97">RFC 5545 094 * p.97-8</a> 095 */ 096 public DateStart setDateStart(DateTimeComponents rawComponents) { 097 return setDateStart((rawComponents == null) ? null : new ICalDate(rawComponents, true)); 098 } 099 100 /** 101 * Gets the UTC offset that the timezone observance transitions to. 102 * @return the UTC offset or null if not set 103 * @see <a href="http://tools.ietf.org/html/rfc5545#page-105">RFC 5545 104 * p.105-6</a> 105 */ 106 public TimezoneOffsetTo getTimezoneOffsetTo() { 107 return getProperty(TimezoneOffsetTo.class); 108 } 109 110 /** 111 * Sets the UTC offset that the timezone observance transitions to. 112 * @param timezoneOffsetTo the UTC offset or null to remove 113 * @see <a href="http://tools.ietf.org/html/rfc5545#page-105">RFC 5545 114 * p.105-6</a> 115 */ 116 public void setTimezoneOffsetTo(TimezoneOffsetTo timezoneOffsetTo) { 117 setProperty(TimezoneOffsetTo.class, timezoneOffsetTo); 118 } 119 120 /** 121 * Sets the UTC offset that the timezone observance transitions to. 122 * @param offset the offset 123 * @return the property that was created 124 * @see <a href="http://tools.ietf.org/html/rfc5545#page-105">RFC 5545 125 * p.105-6</a> 126 */ 127 public TimezoneOffsetTo setTimezoneOffsetTo(UtcOffset offset) { 128 TimezoneOffsetTo prop = new TimezoneOffsetTo(offset); 129 setTimezoneOffsetTo(prop); 130 return prop; 131 } 132 133 /** 134 * Gets the UTC offset that the timezone observance transitions from. 135 * @return the UTC offset or null if not set 136 * @see <a href="http://tools.ietf.org/html/rfc5545#page-104">RFC 5545 137 * p.104-5</a> 138 */ 139 public TimezoneOffsetFrom getTimezoneOffsetFrom() { 140 return getProperty(TimezoneOffsetFrom.class); 141 } 142 143 /** 144 * Sets the UTC offset that the timezone observance transitions from. 145 * @param timezoneOffsetFrom the UTC offset or null to remove 146 * @see <a href="http://tools.ietf.org/html/rfc5545#page-104">RFC 5545 147 * p.104-5</a> 148 */ 149 public void setTimezoneOffsetFrom(TimezoneOffsetFrom timezoneOffsetFrom) { 150 setProperty(TimezoneOffsetFrom.class, timezoneOffsetFrom); 151 } 152 153 /** 154 * Sets the UTC offset that the timezone observance transitions from. 155 * @param offset the offset 156 * @return the property that was created 157 * @see <a href="http://tools.ietf.org/html/rfc5545#page-104">RFC 5545 158 * p.104-5</a> 159 */ 160 public TimezoneOffsetFrom setTimezoneOffsetFrom(UtcOffset offset) { 161 TimezoneOffsetFrom prop = new TimezoneOffsetFrom(offset); 162 setTimezoneOffsetFrom(prop); 163 return prop; 164 } 165 166 /** 167 * Gets how often the timezone observance repeats. 168 * @return the recurrence rule or null if not set 169 * @see <a href="http://tools.ietf.org/html/rfc5545#page-122">RFC 5545 170 * p.122-32</a> 171 */ 172 public RecurrenceRule getRecurrenceRule() { 173 return getProperty(RecurrenceRule.class); 174 } 175 176 /** 177 * Sets how often the timezone observance repeats. 178 * @param recur the recurrence rule or null to remove 179 * @return the property that was created 180 * @see <a href="http://tools.ietf.org/html/rfc5545#page-122">RFC 5545 181 * p.122-32</a> 182 */ 183 public RecurrenceRule setRecurrenceRule(Recurrence recur) { 184 RecurrenceRule prop = (recur == null) ? null : new RecurrenceRule(recur); 185 setRecurrenceRule(prop); 186 return prop; 187 } 188 189 /** 190 * Sets how often the timezone observance repeats. 191 * @param recurrenceRule the recurrence rule or null to remove 192 * @see <a href="http://tools.ietf.org/html/rfc5545#page-122">RFC 5545 193 * p.122-32</a> 194 */ 195 public void setRecurrenceRule(RecurrenceRule recurrenceRule) { 196 setProperty(RecurrenceRule.class, recurrenceRule); 197 } 198 199 /** 200 * Gets the comments attached to the timezone observance. 201 * @return the comments 202 * @see <a href="http://tools.ietf.org/html/rfc5545#page-83">RFC 5545 203 * p.83-4</a> 204 */ 205 public List<Comment> getComments() { 206 return getProperties(Comment.class); 207 } 208 209 /** 210 * Adds a comment to the timezone observance. 211 * @param comment the comment to add 212 * @see <a href="http://tools.ietf.org/html/rfc5545#page-83">RFC 5545 213 * p.83-4</a> 214 */ 215 public void addComment(Comment comment) { 216 addProperty(comment); 217 } 218 219 /** 220 * Adds a comment to the timezone observance. 221 * @param comment the comment to add 222 * @return the property that was created 223 * @see <a href="http://tools.ietf.org/html/rfc5545#page-83">RFC 5545 224 * p.83-4</a> 225 */ 226 public Comment addComment(String comment) { 227 Comment prop = new Comment(comment); 228 addComment(prop); 229 return prop; 230 } 231 232 /** 233 * Gets the list of dates/periods that help define the recurrence rule of 234 * this timezone observance (if one is defined). 235 * @return the recurrence dates 236 * @see <a href="http://tools.ietf.org/html/rfc5545#page-120">RFC 5545 237 * p.120-2</a> 238 */ 239 public List<RecurrenceDates> getRecurrenceDates() { 240 return getProperties(RecurrenceDates.class); 241 } 242 243 /** 244 * Adds a list of dates/periods that help define the recurrence rule of this 245 * timezone observance (if one is defined). 246 * @param recurrenceDates the recurrence dates 247 * @see <a href="http://tools.ietf.org/html/rfc5545#page-120">RFC 5545 248 * p.120-2</a> 249 */ 250 public void addRecurrenceDates(RecurrenceDates recurrenceDates) { 251 addProperty(recurrenceDates); 252 } 253 254 /** 255 * Gets the traditional, non-standard names for the timezone observance. 256 * @return the timezone observance names 257 * @see <a href="http://tools.ietf.org/html/rfc5545#page-103">RFC 5545 258 * p.103-4</a> 259 */ 260 public List<TimezoneName> getTimezoneNames() { 261 return getProperties(TimezoneName.class); 262 } 263 264 /** 265 * Adds a traditional, non-standard name for the timezone observance. 266 * @param timezoneName the timezone observance name 267 * @see <a href="http://tools.ietf.org/html/rfc5545#page-103">RFC 5545 268 * p.103-4</a> 269 */ 270 public void addTimezoneName(TimezoneName timezoneName) { 271 addProperty(timezoneName); 272 } 273 274 /** 275 * Adds a traditional, non-standard name for the timezone observance. 276 * @param timezoneName the timezone observance name (e.g. "EST") 277 * @return the property that was created 278 * @see <a href="http://tools.ietf.org/html/rfc5545#page-103">RFC 5545 279 * p.103-4</a> 280 */ 281 public TimezoneName addTimezoneName(String timezoneName) { 282 TimezoneName prop = new TimezoneName(timezoneName); 283 addTimezoneName(prop); 284 return prop; 285 } 286 287 /** 288 * Gets the list of exceptions to the timezone observance. 289 * @return the list of exceptions 290 * @see <a href="http://tools.ietf.org/html/rfc5545#page-118">RFC 5545 291 * p.118-20</a> 292 */ 293 public List<ExceptionDates> getExceptionDates() { 294 return getProperties(ExceptionDates.class); 295 } 296 297 /** 298 * Adds a list of exceptions to the timezone observance. Note that this 299 * property can contain multiple dates. 300 * @param exceptionDates the list of exceptions 301 * @see <a href="http://tools.ietf.org/html/rfc5545#page-118">RFC 5545 302 * p.118-20</a> 303 */ 304 public void addExceptionDates(ExceptionDates exceptionDates) { 305 addProperty(exceptionDates); 306 } 307 308 @SuppressWarnings("unchecked") 309 @Override 310 protected void validate(List<ICalComponent> components, ICalVersion version, List<Warning> warnings) { 311 if (version == ICalVersion.V1_0) { 312 warnings.add(Warning.validate(48, version)); 313 } 314 315 checkRequiredCardinality(warnings, DateStart.class, TimezoneOffsetTo.class, TimezoneOffsetFrom.class); 316 317 //BYHOUR, BYMINUTE, and BYSECOND cannot be specified in RRULE if DTSTART's data type is "date" 318 //RFC 5545 p. 167 319 DateStart dateStart = getDateStart(); 320 RecurrenceRule rrule = getRecurrenceRule(); 321 if (dateStart != null && rrule != null) { 322 ICalDate start = dateStart.getValue(); 323 Recurrence recur = rrule.getValue(); 324 if (start != null && recur != null) { 325 if (!start.hasTime() && (!recur.getByHour().isEmpty() || !recur.getByMinute().isEmpty() || !recur.getBySecond().isEmpty())) { 326 warnings.add(Warning.validate(5)); 327 } 328 } 329 } 330 331 //there *should* be only 1 instance of RRULE 332 //RFC 5545 p. 167 333 if (getProperties(RecurrenceRule.class).size() > 1) { 334 warnings.add(Warning.validate(6)); 335 } 336 } 337}