001 package biweekly.component; 002 003 import java.util.Date; 004 import java.util.List; 005 006 import biweekly.parameter.FreeBusyType; 007 import biweekly.property.Attendee; 008 import biweekly.property.Comment; 009 import biweekly.property.Contact; 010 import biweekly.property.DateEnd; 011 import biweekly.property.DateStart; 012 import biweekly.property.DateTimeStamp; 013 import biweekly.property.FreeBusy; 014 import biweekly.property.LastModified; 015 import biweekly.property.Method; 016 import biweekly.property.Organizer; 017 import biweekly.property.RequestStatus; 018 import biweekly.property.Uid; 019 import biweekly.property.Url; 020 import biweekly.util.Duration; 021 022 /* 023 Copyright (c) 2013, Michael Angstadt 024 All rights reserved. 025 026 Redistribution and use in source and binary forms, with or without 027 modification, are permitted provided that the following conditions are met: 028 029 1. Redistributions of source code must retain the above copyright notice, this 030 list of conditions and the following disclaimer. 031 2. Redistributions in binary form must reproduce the above copyright notice, 032 this list of conditions and the following disclaimer in the documentation 033 and/or other materials provided with the distribution. 034 035 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 036 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 037 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 038 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 039 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 040 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 041 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 042 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 043 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 044 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 045 */ 046 047 /** 048 * Defines a set of free/busy data. 049 * @author Michael Angstadt 050 * @see <a href="http://tools.ietf.org/html/rfc5545#page-59">RFC 5545 051 * p.59-62</a> 052 */ 053 public class VFreeBusy extends ICalComponent { 054 /** 055 * <p> 056 * Creates a new free/busy component. 057 * </p> 058 * <p> 059 * The following properties are auto-generated on object creation. These 060 * properties <b>must</b> be present in order for the free/busy component to 061 * be valid: 062 * <ul> 063 * <li>{@link Uid} - Set to a UUID.</li> 064 * <li>{@link DateTimeStamp} - Set to the current date-time.</li> 065 * </ul> 066 * </p> 067 */ 068 public VFreeBusy() { 069 setUid(Uid.random()); 070 setDateTimeStamp(new Date()); 071 } 072 073 /** 074 * Gets the unique identifier for this free/busy entry. This component 075 * object comes populated with a UID on creation. This is a <b>required</b> 076 * property. 077 * @return the UID or null if not set 078 * @see <a href="http://tools.ietf.org/html/rfc5545#page-117">RFC 5545 079 * p.117-8</a> 080 */ 081 public Uid getUid() { 082 return getProperty(Uid.class); 083 } 084 085 /** 086 * Sets the unique identifier for this free/busy entry. This component 087 * object comes populated with a UID on creation. This is a <b>required</b> 088 * property. 089 * @param uid the UID or null to remove 090 * @see <a href="http://tools.ietf.org/html/rfc5545#page-117">RFC 5545 091 * p.117-8</a> 092 */ 093 public void setUid(Uid uid) { 094 setProperty(Uid.class, uid); 095 } 096 097 /** 098 * Sets the unique identifier for this free/busy entry. This component 099 * object comes populated with a UID on creation. This is a <b>required</b> 100 * property. 101 * @param uid the UID or null to remove 102 * @return the property that was created 103 * @see <a href="http://tools.ietf.org/html/rfc5545#page-117">RFC 5545 104 * p.117-8</a> 105 */ 106 public Uid setUid(String uid) { 107 Uid prop = (uid == null) ? null : new Uid(uid); 108 setUid(prop); 109 return prop; 110 } 111 112 /** 113 * Gets either (a) the creation date of the iCalendar object (if the 114 * {@link Method} property is defined) or (b) the date that the free/busy 115 * entry was last modified (the {@link LastModified} property also holds 116 * this information). This free/busy object comes populated with a 117 * {@link DateTimeStamp} property that is set to the current time. This is a 118 * <b>required</b> property. 119 * @return the date time stamp or null if not set 120 * @see <a href="http://tools.ietf.org/html/rfc5545#page-137">RFC 5545 121 * p.137-8</a> 122 */ 123 public DateTimeStamp getDateTimeStamp() { 124 return getProperty(DateTimeStamp.class); 125 } 126 127 /** 128 * Sets either (a) the creation date of the iCalendar object (if the 129 * {@link Method} property is defined) or (b) the date that the free/busy 130 * entry was last modified (the {@link LastModified} property also holds 131 * this information). This free/busy object comes populated with a 132 * {@link DateTimeStamp} property that is set to the current time. This is a 133 * <b>required</b> property. 134 * @param dateTimeStamp the date time stamp or null to remove 135 * @see <a href="http://tools.ietf.org/html/rfc5545#page-137">RFC 5545 136 * p.137-8</a> 137 */ 138 public void setDateTimeStamp(DateTimeStamp dateTimeStamp) { 139 setProperty(DateTimeStamp.class, dateTimeStamp); 140 } 141 142 /** 143 * Sets either (a) the creation date of the iCalendar object (if the 144 * {@link Method} property is defined) or (b) the date that the free/busy 145 * entry was last modified (the {@link LastModified} property also holds 146 * this information). This free/busy object comes populated with a 147 * {@link DateTimeStamp} property that is set to the current time. This is a 148 * <b>required</b> property. 149 * @param dateTimeStamp the date time stamp or null to remove 150 * @return the property that was created 151 * @see <a href="http://tools.ietf.org/html/rfc5545#page-137">RFC 5545 152 * p.137-8</a> 153 */ 154 public DateTimeStamp setDateTimeStamp(Date dateTimeStamp) { 155 DateTimeStamp prop = (dateTimeStamp == null) ? null : new DateTimeStamp(dateTimeStamp); 156 setDateTimeStamp(prop); 157 return prop; 158 } 159 160 /** 161 * Gets the contact associated with the free/busy entry. 162 * @return the contact or null if not set 163 * @see <a href="http://tools.ietf.org/html/rfc5545#page-109">RFC 5545 164 * p.109-11</a> 165 */ 166 public Contact getContact() { 167 return getProperty(Contact.class); 168 } 169 170 /** 171 * Sets the contact for the free/busy entry. 172 * @param contact the contact or null to remove 173 * @see <a href="http://tools.ietf.org/html/rfc5545#page-109">RFC 5545 174 * p.109-11</a> 175 */ 176 public void setContact(Contact contact) { 177 setProperty(Contact.class, contact); 178 } 179 180 /** 181 * Sets the contact for the free/busy entry. 182 * @param contact the contact (e.g. "ACME Co - (123) 555-1234") 183 * @return the property that was created 184 * @see <a href="http://tools.ietf.org/html/rfc5545#page-109">RFC 5545 185 * p.109-11</a> 186 */ 187 public Contact addContact(String contact) { 188 Contact prop = new Contact(contact); 189 setContact(prop); 190 return prop; 191 } 192 193 /** 194 * Gets the date that the free/busy entry starts. 195 * @return the start date or null if not set 196 * @see <a href="http://tools.ietf.org/html/rfc5545#page-97">RFC 5545 197 * p.97-8</a> 198 */ 199 public DateStart getDateStart() { 200 return getProperty(DateStart.class); 201 } 202 203 /** 204 * Sets the date that the free/busy entry starts. 205 * @param dateStart the start date or null to remove 206 * @see <a href="http://tools.ietf.org/html/rfc5545#page-97">RFC 5545 207 * p.97-8</a> 208 */ 209 public void setDateStart(DateStart dateStart) { 210 setProperty(DateStart.class, dateStart); 211 } 212 213 /** 214 * Sets the date that the free/busy entry starts. 215 * @param dateStart the start date or null to remove 216 * @return the property that was created 217 * @see <a href="http://tools.ietf.org/html/rfc5545#page-97">RFC 5545 218 * p.97-8</a> 219 */ 220 public DateStart setDateStart(Date dateStart) { 221 DateStart prop = (dateStart == null) ? null : new DateStart(dateStart); 222 setDateStart(prop); 223 return prop; 224 } 225 226 /** 227 * Gets the date that the free/busy entry ends. 228 * @return the end date or null if not set 229 * @see <a href="http://tools.ietf.org/html/rfc5545#page-95">RFC 5545 230 * p.95-6</a> 231 */ 232 public DateEnd getDateEnd() { 233 return getProperty(DateEnd.class); 234 } 235 236 /** 237 * Sets the date that the free/busy entry ends. 238 * @param dateEnd the end date or null to remove 239 * @see <a href="http://tools.ietf.org/html/rfc5545#page-95">RFC 5545 240 * p.95-6</a> 241 */ 242 public void setDateEnd(DateEnd dateEnd) { 243 setProperty(DateEnd.class, dateEnd); 244 } 245 246 /** 247 * Sets the date that the free/busy entry ends. 248 * @param dateEnd the end date or null to remove 249 * @return the property that was created 250 * @see <a href="http://tools.ietf.org/html/rfc5545#page-95">RFC 5545 251 * p.95-6</a> 252 */ 253 public DateEnd setDateEnd(Date dateEnd) { 254 DateEnd prop = (dateEnd == null) ? null : new DateEnd(dateEnd); 255 setDateEnd(prop); 256 return prop; 257 } 258 259 /** 260 * Gets the person requesting the free/busy time. 261 * @return the person requesting the free/busy time or null if not set 262 * @see <a href="http://tools.ietf.org/html/rfc5545#page-111">RFC 5545 263 * p.111-2</a> 264 */ 265 public Organizer getOrganizer() { 266 return getProperty(Organizer.class); 267 } 268 269 /** 270 * Sets the person requesting the free/busy time. 271 * @param organizer the person requesting the free/busy time or null to 272 * remove 273 * @see <a href="http://tools.ietf.org/html/rfc5545#page-111">RFC 5545 274 * p.111-2</a> 275 */ 276 public void setOrganizer(Organizer organizer) { 277 setProperty(Organizer.class, organizer); 278 } 279 280 /** 281 * Sets the person requesting the free/busy time. 282 * @param email the email address of the person requesting the free/busy 283 * time (e.g. "johndoe@example.com") or null to remove 284 * @return the property that was created 285 * @see <a href="http://tools.ietf.org/html/rfc5545#page-111">RFC 5545 286 * p.111-2</a> 287 */ 288 public Organizer setOrganizer(String email) { 289 Organizer prop = (email == null) ? null : Organizer.email(email); 290 setOrganizer(prop); 291 return prop; 292 } 293 294 /** 295 * Gets a URL to a resource that contains additional information about the 296 * free/busy entry. 297 * @return the URL or null if not set 298 * @see <a href="http://tools.ietf.org/html/rfc5545#page-116">RFC 5545 299 * p.116-7</a> 300 */ 301 public Url getUrl() { 302 return getProperty(Url.class); 303 } 304 305 /** 306 * Sets a URL to a resource that contains additional information about the 307 * free/busy entry. 308 * @param url the URL or null to remove 309 * @see <a href="http://tools.ietf.org/html/rfc5545#page-116">RFC 5545 310 * p.116-7</a> 311 */ 312 public void setUrl(Url url) { 313 setProperty(Url.class, url); 314 } 315 316 /** 317 * Sets a URL to a resource that contains additional information about the 318 * free/busy entry. 319 * @param url the URL (e.g. "http://example.com/resource.ics") or null to 320 * remove 321 * @return the property that was created 322 * @see <a href="http://tools.ietf.org/html/rfc5545#page-116">RFC 5545 323 * p.116-7</a> 324 */ 325 public Url setUrl(String url) { 326 Url prop = (url == null) ? null : new Url(url); 327 setUrl(prop); 328 return prop; 329 } 330 331 // 332 //zero or more 333 // private List<Attendee> attendees; 334 // private List<Comment> comments; 335 // private List<FreeBusy> freeBusy; 336 // private List<Rstatus> rstatus; 337 338 /** 339 * Gets the people who are involved in the free/busy entry. 340 * @return the attendees 341 * @see <a href="http://tools.ietf.org/html/rfc5545#page-107">RFC 5545 342 * p.107-9</a> 343 */ 344 public List<Attendee> getAttendees() { 345 return getProperties(Attendee.class); 346 } 347 348 /** 349 * Adds a person who is involved in the free/busy entry. 350 * @param attendee the attendee 351 * @see <a href="http://tools.ietf.org/html/rfc5545#page-107">RFC 5545 352 * p.107-9</a> 353 */ 354 public void addAttendee(Attendee attendee) { 355 addProperty(attendee); 356 } 357 358 /** 359 * Gets the comments attached to the free/busy entry. 360 * @return the comments 361 * @see <a href="http://tools.ietf.org/html/rfc5545#page-83">RFC 5545 362 * p.83-4</a> 363 */ 364 public List<Comment> getComments() { 365 return getProperties(Comment.class); 366 } 367 368 /** 369 * Adds a comment to the free/busy entry. 370 * @param comment the comment to add 371 * @see <a href="http://tools.ietf.org/html/rfc5545#page-83">RFC 5545 372 * p.83-4</a> 373 */ 374 public void addComment(Comment comment) { 375 addProperty(comment); 376 } 377 378 /** 379 * Adds a comment to the free/busy entry. 380 * @param comment the comment to add 381 * @return the property that was created 382 * @see <a href="http://tools.ietf.org/html/rfc5545#page-83">RFC 5545 383 * p.83-4</a> 384 */ 385 public Comment addComment(String comment) { 386 Comment prop = new Comment(comment); 387 addComment(prop); 388 return prop; 389 } 390 391 /** 392 * Gets the person's availabilities over certain time periods (for example, 393 * "free" between 1pm-3pm, but "busy" between 3pm-4pm). 394 * @return the availabilities 395 * @see <a href="http://tools.ietf.org/html/rfc5545#page-100">RFC 5545 396 * p.100-1</a> 397 */ 398 public List<FreeBusy> getFreeBusy() { 399 return getProperties(FreeBusy.class); 400 } 401 402 /** 403 * Adds a list of time periods for which the person is free or busy (for 404 * example, "free" between 1pm-3pm and 4pm-5pm). Note that a 405 * {@link FreeBusy} property can contain multiple time periods, but only one 406 * availability type (e.g. "busy"). 407 * @param freeBusy the availabilities 408 * @see <a href="http://tools.ietf.org/html/rfc5545#page-100">RFC 5545 409 * p.100-1</a> 410 */ 411 public void addFreeBusy(FreeBusy freeBusy) { 412 addProperty(freeBusy); 413 } 414 415 /** 416 * Adds a single time period for which the person is free or busy (for 417 * example, "free" between 1pm-3pm). This method will look for an existing 418 * property that has the given {@link FreeBusyType} and add the time period 419 * to it, or create a new property is one cannot be found. 420 * @param type the availability type (e.g. "free" or "busy") 421 * @param start the start date-time 422 * @param end the end date-time 423 * @return the property that was created/modified 424 * @see <a href="http://tools.ietf.org/html/rfc5545#page-100">RFC 5545 425 * p.100-1</a> 426 */ 427 public FreeBusy addFreeBusy(FreeBusyType type, Date start, Date end) { 428 FreeBusy found = findByFbType(type); 429 found.addValue(start, end); 430 return found; 431 } 432 433 /** 434 * Adds a single time period for which the person is free or busy (for 435 * example, "free" for 2 hours after 1pm). This method will look for an 436 * existing property that has the given {@link FreeBusyType} and add the 437 * time period to it, or create a new property is one cannot be found. 438 * @param type the availability type (e.g. "free" or "busy") 439 * @param start the start date-time 440 * @param duration the length of time 441 * @return the property that was created/modified 442 * @see <a href="http://tools.ietf.org/html/rfc5545#page-100">RFC 5545 443 * p.100-1</a> 444 */ 445 public FreeBusy addFreeBusy(FreeBusyType type, Date start, Duration duration) { 446 FreeBusy found = findByFbType(type); 447 found.addValue(start, duration); 448 return found; 449 } 450 451 private FreeBusy findByFbType(FreeBusyType type) { 452 FreeBusy found = null; 453 454 for (FreeBusy fb : getFreeBusy()) { 455 if (fb.getType() == type) { 456 found = fb; 457 break; 458 } 459 } 460 461 if (found == null) { 462 found = new FreeBusy(); 463 found.setType(type); 464 addFreeBusy(found); 465 } 466 return found; 467 } 468 469 /** 470 * Gets the response to a scheduling request. 471 * @return the response 472 * @see <a href="http://tools.ietf.org/html/rfc5545#page-141">RFC 5545 473 * p.141-3</a> 474 */ 475 public RequestStatus getRequestStatus() { 476 return getProperty(RequestStatus.class); 477 } 478 479 /** 480 * Sets the response to a scheduling request. 481 * @param requestStatus the response 482 * @see <a href="http://tools.ietf.org/html/rfc5545#page-141">RFC 5545 483 * p.141-3</a> 484 */ 485 public void setRequestStatus(RequestStatus requestStatus) { 486 setProperty(RequestStatus.class, requestStatus); 487 } 488 489 @SuppressWarnings("unchecked") 490 @Override 491 protected void validate(List<ICalComponent> components, List<String> warnings) { 492 checkRequiredCardinality(warnings, Uid.class, DateTimeStamp.class); 493 checkOptionalCardinality(warnings, Contact.class, DateStart.class, DateEnd.class, Organizer.class, Url.class); 494 495 DateStart dateStart = getDateStart(); 496 DateEnd dateEnd = getDateEnd(); 497 498 if (dateEnd != null && dateStart == null) { 499 warnings.add("A " + DateStart.class.getSimpleName() + " property must be defined if a " + DateEnd.class.getSimpleName() + " property is defined."); 500 } 501 502 if (dateStart != null && dateStart.getValue() != null && !dateStart.hasTime()) { 503 warnings.add(DateStart.class.getSimpleName() + " properties in free/busy components must always have a time component."); 504 } 505 506 if (dateEnd != null && dateEnd.getValue() != null && !dateEnd.hasTime()) { 507 warnings.add(DateEnd.class.getSimpleName() + " properties in free/busy components must always have a time component."); 508 } 509 510 if (dateStart != null && dateEnd != null) { 511 Date start = dateStart.getValue(); 512 Date end = dateEnd.getValue(); 513 if (start != null && end != null && start.compareTo(end) >= 0) { 514 warnings.add(DateStart.class.getSimpleName() + " must come before " + DateEnd.class.getSimpleName() + "."); 515 } 516 } 517 } 518 }