src/net/fortuna/ical4j/model/component/VEvent.java

Tue, 10 Feb 2015 18:12:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 10 Feb 2015 18:12:00 +0100
changeset 0
fb9019fb1bf7
child 3
73bdfa70b04e
permissions
-rw-r--r--

Import initial revisions of existing project AndroidCaldavSyncAdapater,
forked from upstream repository at 27e8a0f8495c92e0780d450bdf0c7cec77a03a55.

michael@0 1 /**
michael@0 2 * Copyright (c) 2012, Ben Fortuna
michael@0 3 * All rights reserved.
michael@0 4 *
michael@0 5 * Redistribution and use in source and binary forms, with or without
michael@0 6 * modification, are permitted provided that the following conditions
michael@0 7 * are met:
michael@0 8 *
michael@0 9 * o Redistributions of source code must retain the above copyright
michael@0 10 * notice, this list of conditions and the following disclaimer.
michael@0 11 *
michael@0 12 * o Redistributions in binary form must reproduce the above copyright
michael@0 13 * notice, this list of conditions and the following disclaimer in the
michael@0 14 * documentation and/or other materials provided with the distribution.
michael@0 15 *
michael@0 16 * o Neither the name of Ben Fortuna nor the names of any other contributors
michael@0 17 * may be used to endorse or promote products derived from this software
michael@0 18 * without specific prior written permission.
michael@0 19 *
michael@0 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
michael@0 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
michael@0 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
michael@0 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
michael@0 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
michael@0 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
michael@0 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
michael@0 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 31 */
michael@0 32 package net.fortuna.ical4j.model.component;
michael@0 33
michael@0 34 import java.io.IOException;
michael@0 35 import java.net.URISyntaxException;
michael@0 36 import java.text.ParseException;
michael@0 37 import java.util.HashMap;
michael@0 38 import java.util.Iterator;
michael@0 39 import java.util.Map;
michael@0 40
michael@0 41 import net.fortuna.ical4j.model.Component;
michael@0 42 import net.fortuna.ical4j.model.ComponentList;
michael@0 43 import net.fortuna.ical4j.model.Date;
michael@0 44 import net.fortuna.ical4j.model.DateTime;
michael@0 45 import net.fortuna.ical4j.model.Dur;
michael@0 46 import net.fortuna.ical4j.model.Parameter;
michael@0 47 import net.fortuna.ical4j.model.Period;
michael@0 48 import net.fortuna.ical4j.model.PeriodList;
michael@0 49 import net.fortuna.ical4j.model.Property;
michael@0 50 import net.fortuna.ical4j.model.PropertyList;
michael@0 51 import net.fortuna.ical4j.model.ValidationException;
michael@0 52 import net.fortuna.ical4j.model.Validator;
michael@0 53 import net.fortuna.ical4j.model.parameter.Value;
michael@0 54 import net.fortuna.ical4j.model.property.Clazz;
michael@0 55 import net.fortuna.ical4j.model.property.Created;
michael@0 56 import net.fortuna.ical4j.model.property.Description;
michael@0 57 import net.fortuna.ical4j.model.property.DtEnd;
michael@0 58 import net.fortuna.ical4j.model.property.DtStamp;
michael@0 59 import net.fortuna.ical4j.model.property.DtStart;
michael@0 60 import net.fortuna.ical4j.model.property.Duration;
michael@0 61 import net.fortuna.ical4j.model.property.Geo;
michael@0 62 import net.fortuna.ical4j.model.property.LastModified;
michael@0 63 import net.fortuna.ical4j.model.property.Location;
michael@0 64 import net.fortuna.ical4j.model.property.Method;
michael@0 65 import net.fortuna.ical4j.model.property.Organizer;
michael@0 66 import net.fortuna.ical4j.model.property.Priority;
michael@0 67 import net.fortuna.ical4j.model.property.RecurrenceId;
michael@0 68 import net.fortuna.ical4j.model.property.Sequence;
michael@0 69 import net.fortuna.ical4j.model.property.Status;
michael@0 70 import net.fortuna.ical4j.model.property.Summary;
michael@0 71 import net.fortuna.ical4j.model.property.Transp;
michael@0 72 import net.fortuna.ical4j.model.property.Uid;
michael@0 73 import net.fortuna.ical4j.model.property.Url;
michael@0 74 import net.fortuna.ical4j.util.CompatibilityHints;
michael@0 75 import net.fortuna.ical4j.util.ComponentValidator;
michael@0 76 import net.fortuna.ical4j.util.Dates;
michael@0 77 import net.fortuna.ical4j.util.PropertyValidator;
michael@0 78 import net.fortuna.ical4j.util.Strings;
michael@0 79
michael@0 80 import org.apache.commons.lang.ObjectUtils;
michael@0 81 import org.apache.commons.lang.builder.HashCodeBuilder;
michael@0 82
michael@0 83 /**
michael@0 84 * $Id$ [Apr 5, 2004]
michael@0 85 *
michael@0 86 * Defines an iCalendar VEVENT component.
michael@0 87 *
michael@0 88 * <pre>
michael@0 89 * 4.6.1 Event Component
michael@0 90 *
michael@0 91 * Component Name: &quot;VEVENT&quot;
michael@0 92 *
michael@0 93 * Purpose: Provide a grouping of component properties that describe an
michael@0 94 * event.
michael@0 95 *
michael@0 96 * Format Definition: A &quot;VEVENT&quot; calendar component is defined by the
michael@0 97 * following notation:
michael@0 98 *
michael@0 99 * eventc = &quot;BEGIN&quot; &quot;:&quot; &quot;VEVENT&quot; CRLF
michael@0 100 * eventprop *alarmc
michael@0 101 * &quot;END&quot; &quot;:&quot; &quot;VEVENT&quot; CRLF
michael@0 102 *
michael@0 103 * eventprop = *(
michael@0 104 *
michael@0 105 * ; the following are optional,
michael@0 106 * ; but MUST NOT occur more than once
michael@0 107 *
michael@0 108 * class / created / description / dtstart / geo /
michael@0 109 * last-mod / location / organizer / priority /
michael@0 110 * dtstamp / seq / status / summary / transp /
michael@0 111 * uid / url / recurid /
michael@0 112 *
michael@0 113 * ; either 'dtend' or 'duration' may appear in
michael@0 114 * ; a 'eventprop', but 'dtend' and 'duration'
michael@0 115 * ; MUST NOT occur in the same 'eventprop'
michael@0 116 *
michael@0 117 * dtend / duration /
michael@0 118 *
michael@0 119 * ; the following are optional,
michael@0 120 * ; and MAY occur more than once
michael@0 121 *
michael@0 122 * attach / attendee / categories / comment /
michael@0 123 * contact / exdate / exrule / rstatus / related /
michael@0 124 * resources / rdate / rrule / x-prop
michael@0 125 *
michael@0 126 * )
michael@0 127 * </pre>
michael@0 128 *
michael@0 129 * Example 1 - Creating a new all-day event:
michael@0 130 *
michael@0 131 * <pre><code>
michael@0 132 * java.util.Calendar cal = java.util.Calendar.getInstance();
michael@0 133 * cal.set(java.util.Calendar.MONTH, java.util.Calendar.DECEMBER);
michael@0 134 * cal.set(java.util.Calendar.DAY_OF_MONTH, 25);
michael@0 135 *
michael@0 136 * VEvent christmas = new VEvent(cal.getTime(), &quot;Christmas Day&quot;);
michael@0 137 *
michael@0 138 * // initialise as an all-day event..
michael@0 139 * christmas.getProperties().getProperty(Property.DTSTART).getParameters().add(
michael@0 140 * Value.DATE);
michael@0 141 *
michael@0 142 * // add timezone information..
michael@0 143 * VTimeZone tz = VTimeZone.getDefault();
michael@0 144 * TzId tzParam = new TzId(tz.getProperties().getProperty(Property.TZID)
michael@0 145 * .getValue());
michael@0 146 * christmas.getProperties().getProperty(Property.DTSTART).getParameters().add(
michael@0 147 * tzParam);
michael@0 148 * </code></pre>
michael@0 149 *
michael@0 150 * Example 2 - Creating an event of one (1) hour duration:
michael@0 151 *
michael@0 152 * <pre><code>
michael@0 153 * java.util.Calendar cal = java.util.Calendar.getInstance();
michael@0 154 * // tomorrow..
michael@0 155 * cal.add(java.util.Calendar.DAY_OF_MONTH, 1);
michael@0 156 * cal.set(java.util.Calendar.HOUR_OF_DAY, 9);
michael@0 157 * cal.set(java.util.Calendar.MINUTE, 30);
michael@0 158 *
michael@0 159 * VEvent meeting = new VEvent(cal.getTime(), 1000 * 60 * 60, &quot;Progress Meeting&quot;);
michael@0 160 *
michael@0 161 * // add timezone information..
michael@0 162 * VTimeZone tz = VTimeZone.getDefault();
michael@0 163 * TzId tzParam = new TzId(tz.getProperties().getProperty(Property.TZID)
michael@0 164 * .getValue());
michael@0 165 * meeting.getProperties().getProperty(Property.DTSTART).getParameters().add(
michael@0 166 * tzParam);
michael@0 167 * </code></pre>
michael@0 168 *
michael@0 169 * Example 3 - Retrieve a list of periods representing a recurring event in a specified range:
michael@0 170 *
michael@0 171 * <pre><code>
michael@0 172 * Calendar weekday9AM = Calendar.getInstance();
michael@0 173 * weekday9AM.set(2005, Calendar.MARCH, 7, 9, 0, 0);
michael@0 174 * weekday9AM.set(Calendar.MILLISECOND, 0);
michael@0 175 *
michael@0 176 * Calendar weekday5PM = Calendar.getInstance();
michael@0 177 * weekday5PM.set(2005, Calendar.MARCH, 7, 17, 0, 0);
michael@0 178 * weekday5PM.set(Calendar.MILLISECOND, 0);
michael@0 179 *
michael@0 180 * // Do the recurrence until December 31st.
michael@0 181 * Calendar untilCal = Calendar.getInstance();
michael@0 182 * untilCal.set(2005, Calendar.DECEMBER, 31);
michael@0 183 * untilCal.set(Calendar.MILLISECOND, 0);
michael@0 184 *
michael@0 185 * // 9:00AM to 5:00PM Rule
michael@0 186 * Recur recur = new Recur(Recur.WEEKLY, untilCal.getTime());
michael@0 187 * recur.getDayList().add(WeekDay.MO);
michael@0 188 * recur.getDayList().add(WeekDay.TU);
michael@0 189 * recur.getDayList().add(WeekDay.WE);
michael@0 190 * recur.getDayList().add(WeekDay.TH);
michael@0 191 * recur.getDayList().add(WeekDay.FR);
michael@0 192 * recur.setInterval(3);
michael@0 193 * recur.setWeekStartDay(WeekDay.MO.getDay());
michael@0 194 * RRule rrule = new RRule(recur);
michael@0 195 *
michael@0 196 * Summary summary = new Summary(&quot;TEST EVENTS THAT HAPPEN 9-5 MON-FRI&quot;);
michael@0 197 *
michael@0 198 * weekdayNineToFiveEvents = new VEvent();
michael@0 199 * weekdayNineToFiveEvents.getProperties().add(rrule);
michael@0 200 * weekdayNineToFiveEvents.getProperties().add(summary);
michael@0 201 * weekdayNineToFiveEvents.getProperties().add(new DtStart(weekday9AM.getTime()));
michael@0 202 * weekdayNineToFiveEvents.getProperties().add(new DtEnd(weekday5PM.getTime()));
michael@0 203 *
michael@0 204 * // Test Start 04/01/2005, End One month later.
michael@0 205 * // Query Calendar Start and End Dates.
michael@0 206 * Calendar queryStartDate = Calendar.getInstance();
michael@0 207 * queryStartDate.set(2005, Calendar.APRIL, 1, 14, 47, 0);
michael@0 208 * queryStartDate.set(Calendar.MILLISECOND, 0);
michael@0 209 * Calendar queryEndDate = Calendar.getInstance();
michael@0 210 * queryEndDate.set(2005, Calendar.MAY, 1, 11, 15, 0);
michael@0 211 * queryEndDate.set(Calendar.MILLISECOND, 0);
michael@0 212 *
michael@0 213 * // This range is monday to friday every three weeks, starting from
michael@0 214 * // March 7th 2005, which means for our query dates we need
michael@0 215 * // April 18th through to the 22nd.
michael@0 216 * PeriodList periods = weekdayNineToFiveEvents.getPeriods(queryStartDate
michael@0 217 * .getTime(), queryEndDate.getTime());
michael@0 218 * </code></pre>
michael@0 219 *
michael@0 220 * @author Ben Fortuna
michael@0 221 */
michael@0 222 public class VEvent extends CalendarComponent {
michael@0 223
michael@0 224 private static final long serialVersionUID = 2547948989200697335L;
michael@0 225
michael@0 226 private final Map methodValidators = new HashMap();
michael@0 227 {
michael@0 228 methodValidators.put(Method.ADD, new AddValidator());
michael@0 229 methodValidators.put(Method.CANCEL, new CancelValidator());
michael@0 230 methodValidators.put(Method.COUNTER, new CounterValidator());
michael@0 231 methodValidators.put(Method.DECLINE_COUNTER, new DeclineCounterValidator());
michael@0 232 methodValidators.put(Method.PUBLISH, new PublishValidator());
michael@0 233 methodValidators.put(Method.REFRESH, new RefreshValidator());
michael@0 234 methodValidators.put(Method.REPLY, new ReplyValidator());
michael@0 235 methodValidators.put(Method.REQUEST, new RequestValidator());
michael@0 236 }
michael@0 237
michael@0 238 private ComponentList alarms;
michael@0 239
michael@0 240 /**
michael@0 241 * Default constructor.
michael@0 242 */
michael@0 243 public VEvent() {
michael@0 244 super(VEVENT);
michael@0 245 this.alarms = new ComponentList();
michael@0 246 getProperties().add(new DtStamp());
michael@0 247 }
michael@0 248
michael@0 249 /**
michael@0 250 * Constructor.
michael@0 251 * @param properties a list of properties
michael@0 252 */
michael@0 253 public VEvent(final PropertyList properties) {
michael@0 254 super(VEVENT, properties);
michael@0 255 this.alarms = new ComponentList();
michael@0 256 }
michael@0 257
michael@0 258 /**
michael@0 259 * Constructor.
michael@0 260 * @param properties a list of properties
michael@0 261 * @param alarms a list of alarms
michael@0 262 */
michael@0 263 public VEvent(final PropertyList properties, final ComponentList alarms) {
michael@0 264 super(VEVENT, properties);
michael@0 265 this.alarms = alarms;
michael@0 266 }
michael@0 267
michael@0 268 /**
michael@0 269 * Constructs a new VEVENT instance starting at the specified time with the specified summary.
michael@0 270 * @param start the start date of the new event
michael@0 271 * @param summary the event summary
michael@0 272 */
michael@0 273 public VEvent(final Date start, final String summary) {
michael@0 274 this();
michael@0 275 getProperties().add(new DtStart(start));
michael@0 276 getProperties().add(new Summary(summary));
michael@0 277 }
michael@0 278
michael@0 279 /**
michael@0 280 * Constructs a new VEVENT instance starting and ending at the specified times with the specified summary.
michael@0 281 * @param start the start date of the new event
michael@0 282 * @param end the end date of the new event
michael@0 283 * @param summary the event summary
michael@0 284 */
michael@0 285 public VEvent(final Date start, final Date end, final String summary) {
michael@0 286 this();
michael@0 287 getProperties().add(new DtStart(start));
michael@0 288 getProperties().add(new DtEnd(end));
michael@0 289 getProperties().add(new Summary(summary));
michael@0 290 }
michael@0 291
michael@0 292 /**
michael@0 293 * Constructs a new VEVENT instance starting at the specified times, for the specified duration, with the specified
michael@0 294 * summary.
michael@0 295 * @param start the start date of the new event
michael@0 296 * @param duration the duration of the new event
michael@0 297 * @param summary the event summary
michael@0 298 */
michael@0 299 public VEvent(final Date start, final Dur duration, final String summary) {
michael@0 300 this();
michael@0 301 getProperties().add(new DtStart(start));
michael@0 302 getProperties().add(new Duration(duration));
michael@0 303 getProperties().add(new Summary(summary));
michael@0 304 }
michael@0 305
michael@0 306 /**
michael@0 307 * Returns the list of alarms for this event.
michael@0 308 * @return a component list
michael@0 309 */
michael@0 310 public final ComponentList getAlarms() {
michael@0 311 return alarms;
michael@0 312 }
michael@0 313
michael@0 314 /**
michael@0 315 * {@inheritDoc}
michael@0 316 */
michael@0 317 public final String toString() {
michael@0 318 final StringBuffer b = new StringBuffer();
michael@0 319 b.append(BEGIN);
michael@0 320 b.append(':');
michael@0 321 b.append(getName());
michael@0 322 b.append(Strings.LINE_SEPARATOR);
michael@0 323 b.append(getProperties());
michael@0 324 b.append(getAlarms());
michael@0 325 b.append(END);
michael@0 326 b.append(':');
michael@0 327 b.append(getName());
michael@0 328 b.append(Strings.LINE_SEPARATOR);
michael@0 329 return b.toString();
michael@0 330 }
michael@0 331
michael@0 332 /**
michael@0 333 * {@inheritDoc}
michael@0 334 */
michael@0 335 public final void validate(final boolean recurse) throws ValidationException {
michael@0 336
michael@0 337 // validate that getAlarms() only contains VAlarm components
michael@0 338 final Iterator iterator = getAlarms().iterator();
michael@0 339 while (iterator.hasNext()) {
michael@0 340 final Component component = (Component) iterator.next();
michael@0 341
michael@0 342 if (!(component instanceof VAlarm)) {
michael@0 343 throw new ValidationException("Component ["
michael@0 344 + component.getName() + "] may not occur in VEVENT");
michael@0 345 }
michael@0 346
michael@0 347 ((VAlarm) component).validate(recurse);
michael@0 348 }
michael@0 349
michael@0 350 if (!CompatibilityHints
michael@0 351 .isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) {
michael@0 352
michael@0 353 // From "4.8.4.7 Unique Identifier":
michael@0 354 // Conformance: The property MUST be specified in the "VEVENT", "VTODO",
michael@0 355 // "VJOURNAL" or "VFREEBUSY" calendar components.
michael@0 356 PropertyValidator.getInstance().assertOne(Property.UID,
michael@0 357 getProperties());
michael@0 358
michael@0 359 // From "4.8.7.2 Date/Time Stamp":
michael@0 360 // Conformance: This property MUST be included in the "VEVENT", "VTODO",
michael@0 361 // "VJOURNAL" or "VFREEBUSY" calendar components.
michael@0 362 PropertyValidator.getInstance().assertOne(Property.DTSTAMP,
michael@0 363 getProperties());
michael@0 364 }
michael@0 365
michael@0 366 /*
michael@0 367 * ; the following are optional, ; but MUST NOT occur more than once class / created / description / dtstart /
michael@0 368 * geo / last-mod / location / organizer / priority / dtstamp / seq / status / summary / transp / uid / url /
michael@0 369 * recurid /
michael@0 370 */
michael@0 371 PropertyValidator.getInstance().assertOneOrLess(Property.CLASS,
michael@0 372 getProperties());
michael@0 373 PropertyValidator.getInstance().assertOneOrLess(Property.CREATED,
michael@0 374 getProperties());
michael@0 375 PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION,
michael@0 376 getProperties());
michael@0 377 PropertyValidator.getInstance().assertOneOrLess(Property.DTSTART,
michael@0 378 getProperties());
michael@0 379 PropertyValidator.getInstance().assertOneOrLess(Property.GEO,
michael@0 380 getProperties());
michael@0 381 PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED,
michael@0 382 getProperties());
michael@0 383 PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION,
michael@0 384 getProperties());
michael@0 385 PropertyValidator.getInstance().assertOneOrLess(Property.ORGANIZER,
michael@0 386 getProperties());
michael@0 387 PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY,
michael@0 388 getProperties());
michael@0 389 PropertyValidator.getInstance().assertOneOrLess(Property.DTSTAMP,
michael@0 390 getProperties());
michael@0 391 PropertyValidator.getInstance().assertOneOrLess(Property.SEQUENCE,
michael@0 392 getProperties());
michael@0 393 PropertyValidator.getInstance().assertOneOrLess(Property.STATUS,
michael@0 394 getProperties());
michael@0 395 PropertyValidator.getInstance().assertOneOrLess(Property.SUMMARY,
michael@0 396 getProperties());
michael@0 397 PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP,
michael@0 398 getProperties());
michael@0 399 PropertyValidator.getInstance().assertOneOrLess(Property.UID,
michael@0 400 getProperties());
michael@0 401 PropertyValidator.getInstance().assertOneOrLess(Property.URL,
michael@0 402 getProperties());
michael@0 403 PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID,
michael@0 404 getProperties());
michael@0 405
michael@0 406 final Status status = (Status) getProperty(Property.STATUS);
michael@0 407 if (status != null && !Status.VEVENT_TENTATIVE.getValue().equals(status.getValue())
michael@0 408 && !Status.VEVENT_CONFIRMED.getValue().equals(status.getValue())
michael@0 409 && !Status.VEVENT_CANCELLED.getValue().equals(status.getValue())) {
michael@0 410 throw new ValidationException("Status property ["
michael@0 411 + status.toString() + "] is not applicable for VEVENT");
michael@0 412 }
michael@0 413
michael@0 414 /*
michael@0 415 * ; either 'dtend' or 'duration' may appear in ; a 'eventprop', but 'dtend' and 'duration' ; MUST NOT occur in
michael@0 416 * the same 'eventprop' dtend / duration /
michael@0 417 */
michael@0 418 try {
michael@0 419 PropertyValidator.getInstance().assertNone(Property.DTEND,
michael@0 420 getProperties());
michael@0 421 }
michael@0 422 catch (ValidationException ve) {
michael@0 423 PropertyValidator.getInstance().assertNone(Property.DURATION,
michael@0 424 getProperties());
michael@0 425 }
michael@0 426
michael@0 427 if (getProperty(Property.DTEND) != null) {
michael@0 428
michael@0 429 /*
michael@0 430 * The "VEVENT" is also the calendar component used to specify an anniversary or daily reminder within a
michael@0 431 * calendar. These events have a DATE value type for the "DTSTART" property instead of the default data type
michael@0 432 * of DATE-TIME. If such a "VEVENT" has a "DTEND" property, it MUST be specified as a DATE value also. The
michael@0 433 * anniversary type of "VEVENT" can span more than one date (i.e, "DTEND" property value is set to a
michael@0 434 * calendar date after the "DTSTART" property value).
michael@0 435 */
michael@0 436 final DtStart start = (DtStart) getProperty(Property.DTSTART);
michael@0 437 final DtEnd end = (DtEnd) getProperty(Property.DTEND);
michael@0 438
michael@0 439 if (start != null) {
michael@0 440 final Parameter startValue = start.getParameter(Parameter.VALUE);
michael@0 441 final Parameter endValue = end.getParameter(Parameter.VALUE);
michael@0 442
michael@0 443 boolean startEndValueMismatch = false;
michael@0 444 if (endValue != null) {
michael@0 445 if (startValue != null && !endValue.equals(startValue)) {
michael@0 446 // invalid..
michael@0 447 startEndValueMismatch = true;
michael@0 448 }
michael@0 449 else if (startValue == null && !Value.DATE_TIME.equals(endValue)) {
michael@0 450 // invalid..
michael@0 451 startEndValueMismatch = true;
michael@0 452 }
michael@0 453 }
michael@0 454 else if (startValue != null && !Value.DATE_TIME.equals(startValue)) {
michael@0 455 //invalid..
michael@0 456 startEndValueMismatch = true;
michael@0 457 }
michael@0 458 if (startEndValueMismatch) {
michael@0 459 throw new ValidationException("Property [" + Property.DTEND
michael@0 460 + "] must have the same [" + Parameter.VALUE
michael@0 461 + "] as [" + Property.DTSTART + "]");
michael@0 462 }
michael@0 463 }
michael@0 464 }
michael@0 465
michael@0 466 /*
michael@0 467 * ; the following are optional, ; and MAY occur more than once attach / attendee / categories / comment /
michael@0 468 * contact / exdate / exrule / rstatus / related / resources / rdate / rrule / x-prop
michael@0 469 */
michael@0 470
michael@0 471 if (recurse) {
michael@0 472 validateProperties();
michael@0 473 }
michael@0 474 }
michael@0 475
michael@0 476 /**
michael@0 477 * {@inheritDoc}
michael@0 478 */
michael@0 479 protected Validator getValidator(Method method) {
michael@0 480 return (Validator) methodValidators.get(method);
michael@0 481 }
michael@0 482
michael@0 483 /**
michael@0 484 * METHOD:ADD Validator.
michael@0 485 *
michael@0 486 * <pre>
michael@0 487 * Component/Property Presence
michael@0 488 * ------------------- ----------------------------------------------
michael@0 489 * METHOD 1 MUST be "ADD"
michael@0 490 * VEVENT 1
michael@0 491 * DTSTAMP 1
michael@0 492 * DTSTART 1
michael@0 493 * ORGANIZER 1
michael@0 494 * SEQUENCE 1 MUST be greater than 0
michael@0 495 * SUMMARY 1 Can be null
michael@0 496 * UID 1 MUST match that of the original event
michael@0 497 *
michael@0 498 * ATTACH 0+
michael@0 499 * ATTENDEE 0+
michael@0 500 * CATEGORIES 0 or 1 This property MAY contain a list of values
michael@0 501 * CLASS 0 or 1
michael@0 502 * COMMENT 0 or 1
michael@0 503 * CONTACT 0+
michael@0 504 * CREATED 0 or 1
michael@0 505 * DESCRIPTION 0 or 1 Can be null
michael@0 506 * DTEND 0 or 1 if present DURATION MUST NOT be present
michael@0 507 * DURATION 0 or 1 if present DTEND MUST NOT be present
michael@0 508 * EXDATE 0+
michael@0 509 * EXRULE 0+
michael@0 510 * GEO 0 or 1
michael@0 511 * LAST-MODIFIED 0 or 1
michael@0 512 * LOCATION 0 or 1
michael@0 513 * PRIORITY 0 or 1
michael@0 514 * RDATE 0+
michael@0 515 * RELATED-TO 0+
michael@0 516 * RESOURCES 0 or 1 This property MAY contain a list of values
michael@0 517 * RRULE 0+
michael@0 518 * STATUS 0 or 1 MAY be one of TENTATIVE/CONFIRMED
michael@0 519 * TRANSP 0 or 1
michael@0 520 * URL 0 or 1
michael@0 521 * X-PROPERTY 0+
michael@0 522 *
michael@0 523 * RECURRENCE-ID 0
michael@0 524 * REQUEST-STATUS 0
michael@0 525 *
michael@0 526 * VALARM 0+
michael@0 527 * VTIMEZONE 0+ MUST be present if any date/time refers to
michael@0 528 * a timezone
michael@0 529 * X-COMPONENT 0+
michael@0 530 *
michael@0 531 * VFREEBUSY 0
michael@0 532 * VTODO 0
michael@0 533 * VJOURNAL 0
michael@0 534 * </pre>
michael@0 535 *
michael@0 536 */
michael@0 537 private class AddValidator implements Validator {
michael@0 538
michael@0 539 private static final long serialVersionUID = 1L;
michael@0 540
michael@0 541 public void validate() throws ValidationException {
michael@0 542 PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
michael@0 543 PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties());
michael@0 544 PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
michael@0 545 PropertyValidator.getInstance().assertOne(Property.SEQUENCE, getProperties());
michael@0 546 PropertyValidator.getInstance().assertOne(Property.SUMMARY, getProperties());
michael@0 547 PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
michael@0 548
michael@0 549 PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties());
michael@0 550 PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties());
michael@0 551 PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, getProperties());
michael@0 552 PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties());
michael@0 553 PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties());
michael@0 554 PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties());
michael@0 555 PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties());
michael@0 556 PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties());
michael@0 557 PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties());
michael@0 558 PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties());
michael@0 559 PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties());
michael@0 560 PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties());
michael@0 561 PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties());
michael@0 562 PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties());
michael@0 563 PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties());
michael@0 564
michael@0 565 PropertyValidator.getInstance().assertNone(Property.RECURRENCE_ID, getProperties());
michael@0 566 PropertyValidator.getInstance().assertNone(Property.REQUEST_STATUS, getProperties());
michael@0 567
michael@0 568 for (final Iterator i = getAlarms().iterator(); i.hasNext();) {
michael@0 569 final VAlarm alarm = (VAlarm) i.next();
michael@0 570 alarm.validate(Method.ADD);
michael@0 571 }
michael@0 572 }
michael@0 573 }
michael@0 574
michael@0 575 /**
michael@0 576 * METHOD:CANCEL Validator.
michael@0 577 *
michael@0 578 * <pre>
michael@0 579 * Component/Property Presence
michael@0 580 * ------------------- ----------------------------------------------
michael@0 581 * METHOD 1 MUST be "CANCEL"
michael@0 582 *
michael@0 583 * VEVENT 1+ All must have the same UID
michael@0 584 * ATTENDEE 0+ MUST include all "Attendees" being removed
michael@0 585 * the event. MUST include all "Attendees" if
michael@0 586 * the entire event is cancelled.
michael@0 587 * DTSTAMP 1
michael@0 588 * ORGANIZER 1
michael@0 589 * SEQUENCE 1
michael@0 590 * UID 1 MUST be the UID of the original REQUEST
michael@0 591 *
michael@0 592 * COMMENT 0 or 1
michael@0 593 * ATTACH 0+
michael@0 594 * CATEGORIES 0 or 1 This property may contain a list of values
michael@0 595 * CLASS 0 or 1
michael@0 596 * CONTACT 0+
michael@0 597 * CREATED 0 or 1
michael@0 598 * DESCRIPTION 0 or 1
michael@0 599 * DTEND 0 or 1 if present DURATION MUST NOT be present
michael@0 600 * DTSTART 0 or 1
michael@0 601 * DURATION 0 or 1 if present DTEND MUST NOT be present
michael@0 602 * EXDATE 0+
michael@0 603 * EXRULE 0+
michael@0 604 * GEO 0 or 1
michael@0 605 * LAST-MODIFIED 0 or 1
michael@0 606 * LOCATION 0 or 1
michael@0 607 * PRIORITY 0 or 1
michael@0 608 * RDATE 0+
michael@0 609 * RECURRENCE-ID 0 or 1 MUST be present if referring to one or
michael@0 610 * more or more recurring instances.
michael@0 611 * Otherwise it MUST NOT be present
michael@0 612 * RELATED-TO 0+
michael@0 613 * RESOURCES 0 or 1
michael@0 614 * RRULE 0+
michael@0 615 * STATUS 0 or 1 MUST be set to CANCELLED. If uninviting
michael@0 616 * specific "Attendees" then MUST NOT be
michael@0 617 * included.
michael@0 618 * SUMMARY 0 or 1
michael@0 619 * TRANSP 0 or 1
michael@0 620 * URL 0 or 1
michael@0 621 * X-PROPERTY 0+
michael@0 622 * REQUEST-STATUS 0
michael@0 623 *
michael@0 624 * VTIMEZONE 0+ MUST be present if any date/time refers to
michael@0 625 * a timezone
michael@0 626 * X-COMPONENT 0+
michael@0 627 *
michael@0 628 * VTODO 0
michael@0 629 * VJOURNAL 0
michael@0 630 * VFREEBUSY 0
michael@0 631 * VALARM 0
michael@0 632 * </pre>
michael@0 633 *
michael@0 634 */
michael@0 635 private class CancelValidator implements Validator {
michael@0 636
michael@0 637 private static final long serialVersionUID = 1L;
michael@0 638
michael@0 639 public final void validate() throws ValidationException {
michael@0 640 PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
michael@0 641 PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties());
michael@0 642 PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
michael@0 643 PropertyValidator.getInstance().assertOne(Property.SEQUENCE, getProperties());
michael@0 644 PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
michael@0 645
michael@0 646 PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, getProperties());
michael@0 647 PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties());
michael@0 648 PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties());
michael@0 649 PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties());
michael@0 650 PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties());
michael@0 651 PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties());
michael@0 652 PropertyValidator.getInstance().assertOneOrLess(Property.DTSTART, getProperties());
michael@0 653 PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties());
michael@0 654 PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties());
michael@0 655 PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties());
michael@0 656 PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties());
michael@0 657 PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties());
michael@0 658 PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties());
michael@0 659 PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties());
michael@0 660 PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties());
michael@0 661 PropertyValidator.getInstance().assertOneOrLess(Property.SUMMARY, getProperties());
michael@0 662 PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties());
michael@0 663 PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties());
michael@0 664
michael@0 665 PropertyValidator.getInstance().assertNone(Property.REQUEST_STATUS, getProperties());
michael@0 666
michael@0 667 ComponentValidator.assertNone(Component.VALARM, getAlarms());
michael@0 668 }
michael@0 669 }
michael@0 670
michael@0 671 /**
michael@0 672 * METHOD:COUNTER Validator.
michael@0 673 *
michael@0 674 * <pre>
michael@0 675 * Component/Property Presence
michael@0 676 * ------------------- ----------------------------------------------
michael@0 677 * METHOD 1 MUST be "COUNTER"
michael@0 678 *
michael@0 679 * VEVENT 1
michael@0 680 * DTSTAMP 1
michael@0 681 * DTSTART 1
michael@0 682 * ORGANIZER 1 MUST be the "Organizer" of the original
michael@0 683 * event
michael@0 684 * SEQUENCE 1 MUST be present if value is greater than 0,
michael@0 685 * MAY be present if 0
michael@0 686 * SUMMARY 1 Can be null
michael@0 687 * UID 1 MUST be the UID associated with the REQUEST
michael@0 688 * being countered
michael@0 689 *
michael@0 690 * ATTACH 0+
michael@0 691 * ATTENDEE 0+ Can also be used to propose other
michael@0 692 * "Attendees"
michael@0 693 * CATEGORIES 0 or 1 This property may contain a list of values
michael@0 694 * CLASS 0 or 1
michael@0 695 * COMMENT 0 or 1
michael@0 696 * CONTACT 0+
michael@0 697 * CREATED 0 or 1
michael@0 698 * DESCRIPTION 0 or 1
michael@0 699 * DTEND 0 or 1 if present DURATION MUST NOT be present
michael@0 700 * DURATION 0 or 1 if present DTEND MUST NOT be present
michael@0 701 * EXDATE 0+
michael@0 702 * EXRULE 0+
michael@0 703 * GEO 0 or 1
michael@0 704 * LAST-MODIFIED 0 or 1
michael@0 705 * LOCATION 0 or 1
michael@0 706 * PRIORITY 0 or 1
michael@0 707 * RDATE 0+
michael@0 708 * RECURRENCE-ID 0 or 1 MUST only if referring to an instance of a
michael@0 709 * recurring calendar component. Otherwise it
michael@0 710 * MUST NOT be present.
michael@0 711 * RELATED-TO 0+
michael@0 712 * REQUEST-STATUS 0+
michael@0 713 * RESOURCES 0 or 1 This property may contain a list of values
michael@0 714 * RRULE 0+
michael@0 715 * STATUS 0 or 1 Value must be one of CONFIRMED/TENATIVE/
michael@0 716 * CANCELLED
michael@0 717 * TRANSP 0 or 1
michael@0 718 * URL 0 or 1
michael@0 719 * X-PROPERTY 0+
michael@0 720 *
michael@0 721 * VALARM 0+
michael@0 722 * VTIMEZONE 0+ MUST be present if any date/time refers to
michael@0 723 * a timezone
michael@0 724 * X-COMPONENT 0+
michael@0 725 *
michael@0 726 * VTODO 0
michael@0 727 * VJOURNAL 0
michael@0 728 * VFREEBUSY 0
michael@0 729 * </pre>
michael@0 730 *
michael@0 731 */
michael@0 732 private class CounterValidator implements Validator {
michael@0 733
michael@0 734 private static final long serialVersionUID = 1L;
michael@0 735
michael@0 736 public void validate() throws ValidationException {
michael@0 737 PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
michael@0 738 PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties());
michael@0 739
michael@0 740 if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) {
michael@0 741 PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
michael@0 742 }
michael@0 743
michael@0 744 PropertyValidator.getInstance().assertOne(Property.SEQUENCE, getProperties());
michael@0 745 PropertyValidator.getInstance().assertOne(Property.SUMMARY, getProperties());
michael@0 746 PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
michael@0 747
michael@0 748 PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties());
michael@0 749 PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties());
michael@0 750 PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, getProperties());
michael@0 751 PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties());
michael@0 752 PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties());
michael@0 753 PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties());
michael@0 754 PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties());
michael@0 755 PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties());
michael@0 756 PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties());
michael@0 757 PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties());
michael@0 758 PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties());
michael@0 759 PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties());
michael@0 760 PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties());
michael@0 761 PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties());
michael@0 762 PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties());
michael@0 763 PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties());
michael@0 764
michael@0 765 for (final Iterator i = getAlarms().iterator(); i.hasNext();) {
michael@0 766 final VAlarm alarm = (VAlarm) i.next();
michael@0 767 alarm.validate(Method.COUNTER);
michael@0 768 }
michael@0 769 }
michael@0 770 }
michael@0 771
michael@0 772 /**
michael@0 773 * METHOD:DECLINECOUNTER Validator.
michael@0 774 *
michael@0 775 * <pre>
michael@0 776 * Component/Property Presence
michael@0 777 * ------------------- ----------------------------------------------
michael@0 778 * METHOD 1 MUST be "DECLINECOUNTER"
michael@0 779 *
michael@0 780 * VEVENT 1
michael@0 781 * DTSTAMP 1
michael@0 782 * ORGANIZER 1
michael@0 783 * UID 1 MUST, same UID specified in original
michael@0 784 * REQUEST and subsequent COUNTER
michael@0 785 * COMMENT 0 or 1
michael@0 786 * RECURRENCE-ID 0 or 1 MUST only if referring to an instance of a
michael@0 787 * recurring calendar component. Otherwise it
michael@0 788 * MUST NOT be present.
michael@0 789 * REQUEST-STATUS 0+
michael@0 790 * SEQUENCE 0 OR 1 MUST be present if value is greater than 0,
michael@0 791 * MAY be present if 0
michael@0 792 * X-PROPERTY 0+
michael@0 793 * ATTACH 0
michael@0 794 * ATTENDEE 0
michael@0 795 * CATEGORIES 0
michael@0 796 * CLASS 0
michael@0 797 * CONTACT 0
michael@0 798 * CREATED 0
michael@0 799 * DESCRIPTION 0
michael@0 800 * DTEND 0
michael@0 801 * DTSTART 0
michael@0 802 * DURATION 0
michael@0 803 * EXDATE 0
michael@0 804 * EXRULE 0
michael@0 805 * GEO 0
michael@0 806 * LAST-MODIFIED 0
michael@0 807 * LOCATION 0
michael@0 808 * PRIORITY 0
michael@0 809 * RDATE 0
michael@0 810 * RELATED-TO 0
michael@0 811 * RESOURCES 0
michael@0 812 * RRULE 0
michael@0 813 * STATUS 0
michael@0 814 * SUMMARY 0
michael@0 815 * TRANSP 0
michael@0 816 * URL 0
michael@0 817 *
michael@0 818 * X-COMPONENT 0+
michael@0 819 * VTODO 0
michael@0 820 * VJOURNAL 0
michael@0 821 * VFREEBUSY 0
michael@0 822 * VTIMEZONE 0
michael@0 823 * VALARM 0
michael@0 824 * </pre>
michael@0 825 *
michael@0 826 */
michael@0 827 private class DeclineCounterValidator implements Validator {
michael@0 828
michael@0 829 private static final long serialVersionUID = 1L;
michael@0 830
michael@0 831 public void validate() throws ValidationException {
michael@0 832 PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
michael@0 833 PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
michael@0 834 PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
michael@0 835
michael@0 836 PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, getProperties());
michael@0 837 PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties());
michael@0 838 PropertyValidator.getInstance().assertOneOrLess(Property.SEQUENCE, getProperties());
michael@0 839
michael@0 840 PropertyValidator.getInstance().assertNone(Property.ATTACH, getProperties());
michael@0 841 PropertyValidator.getInstance().assertNone(Property.ATTENDEE, getProperties());
michael@0 842 PropertyValidator.getInstance().assertNone(Property.CATEGORIES, getProperties());
michael@0 843 PropertyValidator.getInstance().assertNone(Property.CLASS, getProperties());
michael@0 844 PropertyValidator.getInstance().assertNone(Property.CONTACT, getProperties());
michael@0 845 PropertyValidator.getInstance().assertNone(Property.CREATED, getProperties());
michael@0 846 PropertyValidator.getInstance().assertNone(Property.DESCRIPTION, getProperties());
michael@0 847 PropertyValidator.getInstance().assertNone(Property.DTEND, getProperties());
michael@0 848 PropertyValidator.getInstance().assertNone(Property.DTSTART, getProperties());
michael@0 849 PropertyValidator.getInstance().assertNone(Property.DURATION, getProperties());
michael@0 850 PropertyValidator.getInstance().assertNone(Property.EXDATE, getProperties());
michael@0 851 PropertyValidator.getInstance().assertNone(Property.EXRULE, getProperties());
michael@0 852 PropertyValidator.getInstance().assertNone(Property.GEO, getProperties());
michael@0 853 PropertyValidator.getInstance().assertNone(Property.LAST_MODIFIED, getProperties());
michael@0 854 PropertyValidator.getInstance().assertNone(Property.LOCATION, getProperties());
michael@0 855 PropertyValidator.getInstance().assertNone(Property.PRIORITY, getProperties());
michael@0 856 PropertyValidator.getInstance().assertNone(Property.RDATE, getProperties());
michael@0 857 PropertyValidator.getInstance().assertNone(Property.RELATED_TO, getProperties());
michael@0 858 PropertyValidator.getInstance().assertNone(Property.RESOURCES, getProperties());
michael@0 859 PropertyValidator.getInstance().assertNone(Property.RRULE, getProperties());
michael@0 860 PropertyValidator.getInstance().assertNone(Property.STATUS, getProperties());
michael@0 861 PropertyValidator.getInstance().assertNone(Property.SUMMARY, getProperties());
michael@0 862 PropertyValidator.getInstance().assertNone(Property.TRANSP, getProperties());
michael@0 863 PropertyValidator.getInstance().assertNone(Property.URL, getProperties());
michael@0 864
michael@0 865 ComponentValidator.assertNone(Component.VALARM, getAlarms());
michael@0 866 }
michael@0 867 }
michael@0 868
michael@0 869 /**
michael@0 870 * METHOD:PUBLISH Validator.
michael@0 871 *
michael@0 872 * <pre>
michael@0 873 * Component/Property Presence
michael@0 874 * ------------------- ----------------------------------------------
michael@0 875 * METHOD 1 MUST equal "PUBLISH"
michael@0 876 * VEVENT 1+
michael@0 877 * DTSTAMP 1
michael@0 878 * DTSTART 1
michael@0 879 * ORGANIZER 1
michael@0 880 * SUMMARY 1 Can be null.
michael@0 881 * UID 1
michael@0 882 * RECURRENCE-ID 0 or 1 only if referring to an instance of a
michael@0 883 * recurring calendar component. Otherwise
michael@0 884 * it MUST NOT be present.
michael@0 885 * SEQUENCE 0 or 1 MUST be present if value is greater than
michael@0 886 * 0, MAY be present if 0
michael@0 887 * ATTACH 0+
michael@0 888 * CATEGORIES 0 or 1 This property may contain a list of
michael@0 889 * values
michael@0 890 * CLASS 0 or 1
michael@0 891 * COMMENT 0 or 1
michael@0 892 * CONTACT 0+
michael@0 893 * CREATED 0 or 1
michael@0 894 * DESCRIPTION 0 or 1 Can be null
michael@0 895 * DTEND 0 or 1 if present DURATION MUST NOT be present
michael@0 896 * DURATION 0 or 1 if present DTEND MUST NOT be present
michael@0 897 * EXDATE 0+
michael@0 898 * EXRULE 0+
michael@0 899 * GEO 0 or 1
michael@0 900 * LAST-MODIFIED 0 or 1
michael@0 901 * LOCATION 0 or 1
michael@0 902 * PRIORITY 0 or 1
michael@0 903 * RDATE 0+
michael@0 904 * RELATED-TO 0+
michael@0 905 * RESOURCES 0 or 1 This property MAY contain a list of values
michael@0 906 * RRULE 0+
michael@0 907 * STATUS 0 or 1 MAY be one of TENTATIVE/CONFIRMED/CANCELLED
michael@0 908 * TRANSP 0 or 1
michael@0 909 * URL 0 or 1
michael@0 910 * X-PROPERTY 0+
michael@0 911 *
michael@0 912 * ATTENDEE 0
michael@0 913 * REQUEST-STATUS 0
michael@0 914 *
michael@0 915 * VALARM 0+
michael@0 916 * VFREEBUSY 0
michael@0 917 * VJOURNAL 0
michael@0 918 * VTODO 0
michael@0 919 * VTIMEZONE 0+ MUST be present if any date/time refers to
michael@0 920 * a timezone
michael@0 921 * X-COMPONENT 0+
michael@0 922 * </pre>
michael@0 923 *
michael@0 924 */
michael@0 925 private class PublishValidator implements Validator {
michael@0 926
michael@0 927 private static final long serialVersionUID = 1L;
michael@0 928
michael@0 929 public void validate() throws ValidationException {
michael@0 930 PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
michael@0 931 PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties());
michael@0 932
michael@0 933 if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) {
michael@0 934 PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
michael@0 935 PropertyValidator.getInstance().assertOne(Property.SUMMARY, getProperties());
michael@0 936 }
michael@0 937
michael@0 938 PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
michael@0 939
michael@0 940 PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties());
michael@0 941 PropertyValidator.getInstance().assertOneOrLess(Property.SEQUENCE, getProperties());
michael@0 942 PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties());
michael@0 943 PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties());
michael@0 944 PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, getProperties());
michael@0 945 PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties());
michael@0 946 PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties());
michael@0 947 PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties());
michael@0 948 PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties());
michael@0 949 PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties());
michael@0 950 PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties());
michael@0 951 PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties());
michael@0 952 PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties());
michael@0 953 PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties());
michael@0 954 PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties());
michael@0 955 PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties());
michael@0 956 PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties());
michael@0 957
michael@0 958 if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) {
michael@0 959 PropertyValidator.getInstance().assertNone(Property.ATTENDEE, getProperties());
michael@0 960 }
michael@0 961
michael@0 962 PropertyValidator.getInstance().assertNone(Property.REQUEST_STATUS, getProperties());
michael@0 963
michael@0 964 for (final Iterator i = getAlarms().iterator(); i.hasNext();) {
michael@0 965 final VAlarm alarm = (VAlarm) i.next();
michael@0 966 alarm.validate(Method.PUBLISH);
michael@0 967 }
michael@0 968 }
michael@0 969 }
michael@0 970
michael@0 971 /**
michael@0 972 * METHOD:REFRESH Validator.
michael@0 973 *
michael@0 974 * <pre>
michael@0 975 * Component/Property Presence
michael@0 976 * ------------------- ----------------------------------------------
michael@0 977 * METHOD 1 MUST be "REFRESH"
michael@0 978 *
michael@0 979 * VEVENT 1
michael@0 980 * ATTENDEE 1 MUST be the address of requestor
michael@0 981 * DTSTAMP 1
michael@0 982 * ORGANIZER 1
michael@0 983 * UID 1 MUST be the UID associated with original
michael@0 984 * REQUEST
michael@0 985 * COMMENT 0 or 1
michael@0 986 * RECURRENCE-ID 0 or 1 MUST only if referring to an instance of a
michael@0 987 * recurring calendar component. Otherwise
michael@0 988 * it must NOT be present.
michael@0 989 * X-PROPERTY 0+
michael@0 990 *
michael@0 991 * ATTACH 0
michael@0 992 * CATEGORIES 0
michael@0 993 * CLASS 0
michael@0 994 * CONTACT 0
michael@0 995 * CREATED 0
michael@0 996 * DESCRIPTION 0
michael@0 997 * DTEND 0
michael@0 998 * DTSTART 0
michael@0 999 * DURATION 0
michael@0 1000 * EXDATE 0
michael@0 1001 * EXRULE 0
michael@0 1002 * GEO 0
michael@0 1003 * LAST-MODIFIED 0
michael@0 1004 * LOCATION 0
michael@0 1005 * PRIORITY 0
michael@0 1006 * RDATE 0
michael@0 1007 * RELATED-TO 0
michael@0 1008 * REQUEST-STATUS 0
michael@0 1009 * RESOURCES 0
michael@0 1010 * RRULE 0
michael@0 1011 * SEQUENCE 0
michael@0 1012 * STATUS 0
michael@0 1013 * SUMMARY 0
michael@0 1014 * TRANSP 0
michael@0 1015 * URL 0
michael@0 1016 *
michael@0 1017 * X-COMPONENT 0+
michael@0 1018 *
michael@0 1019 * VTODO 0
michael@0 1020 * VJOURNAL 0
michael@0 1021 * VFREEBUSY 0
michael@0 1022 * VTIMEZONE 0
michael@0 1023 * VALARM 0
michael@0 1024 * </pre>
michael@0 1025 *
michael@0 1026 */
michael@0 1027 private class RefreshValidator implements Validator {
michael@0 1028
michael@0 1029 private static final long serialVersionUID = 1L;
michael@0 1030
michael@0 1031 public void validate() throws ValidationException {
michael@0 1032 PropertyValidator.getInstance().assertOne(Property.ATTENDEE, getProperties());
michael@0 1033 PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
michael@0 1034 PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
michael@0 1035 PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
michael@0 1036
michael@0 1037 PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, getProperties());
michael@0 1038 PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties());
michael@0 1039
michael@0 1040 PropertyValidator.getInstance().assertNone(Property.ATTACH, getProperties());
michael@0 1041 PropertyValidator.getInstance().assertNone(Property.CATEGORIES, getProperties());
michael@0 1042 PropertyValidator.getInstance().assertNone(Property.CLASS, getProperties());
michael@0 1043 PropertyValidator.getInstance().assertNone(Property.CONTACT, getProperties());
michael@0 1044 PropertyValidator.getInstance().assertNone(Property.CREATED, getProperties());
michael@0 1045 PropertyValidator.getInstance().assertNone(Property.DESCRIPTION, getProperties());
michael@0 1046 PropertyValidator.getInstance().assertNone(Property.DTEND, getProperties());
michael@0 1047 PropertyValidator.getInstance().assertNone(Property.DTSTART, getProperties());
michael@0 1048 PropertyValidator.getInstance().assertNone(Property.DURATION, getProperties());
michael@0 1049 PropertyValidator.getInstance().assertNone(Property.EXDATE, getProperties());
michael@0 1050 PropertyValidator.getInstance().assertNone(Property.EXRULE, getProperties());
michael@0 1051 PropertyValidator.getInstance().assertNone(Property.GEO, getProperties());
michael@0 1052 PropertyValidator.getInstance().assertNone(Property.LAST_MODIFIED, getProperties());
michael@0 1053 PropertyValidator.getInstance().assertNone(Property.LOCATION, getProperties());
michael@0 1054 PropertyValidator.getInstance().assertNone(Property.PRIORITY, getProperties());
michael@0 1055 PropertyValidator.getInstance().assertNone(Property.RDATE, getProperties());
michael@0 1056 PropertyValidator.getInstance().assertNone(Property.RELATED_TO, getProperties());
michael@0 1057 PropertyValidator.getInstance().assertNone(Property.REQUEST_STATUS, getProperties());
michael@0 1058 PropertyValidator.getInstance().assertNone(Property.RESOURCES, getProperties());
michael@0 1059 PropertyValidator.getInstance().assertNone(Property.RRULE, getProperties());
michael@0 1060 PropertyValidator.getInstance().assertNone(Property.SEQUENCE, getProperties());
michael@0 1061 PropertyValidator.getInstance().assertNone(Property.STATUS, getProperties());
michael@0 1062 PropertyValidator.getInstance().assertNone(Property.SUMMARY, getProperties());
michael@0 1063 PropertyValidator.getInstance().assertNone(Property.TRANSP, getProperties());
michael@0 1064 PropertyValidator.getInstance().assertNone(Property.URL, getProperties());
michael@0 1065
michael@0 1066 ComponentValidator.assertNone(Component.VALARM, getAlarms());
michael@0 1067 }
michael@0 1068 }
michael@0 1069
michael@0 1070 /**
michael@0 1071 * METHOD:REPLY Validator.
michael@0 1072 *
michael@0 1073 * <pre>
michael@0 1074 * Component/Property Presence
michael@0 1075 * ------------------- ----------------------------------------------
michael@0 1076 * METHOD 1 MUST be "REPLY"
michael@0 1077 * VEVENT 1+ All components MUST have the same UID
michael@0 1078 * ATTENDEE 1 MUST be the address of the Attendee
michael@0 1079 * replying.
michael@0 1080 * DTSTAMP 1
michael@0 1081 * ORGANIZER 1
michael@0 1082 * RECURRENCE-ID 0 or 1 only if referring to an instance of a
michael@0 1083 * recurring calendar component. Otherwise
michael@0 1084 * it must NOT be present.
michael@0 1085 * UID 1 MUST be the UID of the original REQUEST
michael@0 1086 *
michael@0 1087 * SEQUENCE 0 or 1 MUST if non-zero, MUST be the sequence
michael@0 1088 * number of the original REQUEST. MAY be
michael@0 1089 * present if 0.
michael@0 1090 *
michael@0 1091 * ATTACH 0+
michael@0 1092 * CATEGORIES 0 or 1 This property may contain a list of values
michael@0 1093 * CLASS 0 or 1
michael@0 1094 * COMMENT 0 or 1
michael@0 1095 * CONTACT 0+
michael@0 1096 * CREATED 0 or 1
michael@0 1097 * DESCRIPTION 0 or 1
michael@0 1098 * DTEND 0 or 1 if present DURATION MUST NOT be present
michael@0 1099 * DTSTART 0 or 1
michael@0 1100 * DURATION 0 or 1 if present DTEND MUST NOT be present
michael@0 1101 * EXDATE 0+
michael@0 1102 * EXRULE 0+
michael@0 1103 * GEO 0 or 1
michael@0 1104 * LAST-MODIFIED 0 or 1
michael@0 1105 * LOCATION 0 or 1
michael@0 1106 * PRIORITY 0 or 1
michael@0 1107 * RDATE 0+
michael@0 1108 * RELATED-TO 0+
michael@0 1109 * RESOURCES 0 or 1 This property MAY contain a list of values
michael@0 1110 * REQUEST-STATUS 0+
michael@0 1111 * RRULE 0+
michael@0 1112 * STATUS 0 or 1
michael@0 1113 * SUMMARY 0 or 1
michael@0 1114 * TRANSP 0 or 1
michael@0 1115 * URL 0 or 1
michael@0 1116 * X-PROPERTY 0+
michael@0 1117 *
michael@0 1118 * VTIMEZONE 0 or 1 MUST be present if any date/time refers
michael@0 1119 * to a timezone
michael@0 1120 * X-COMPONENT 0+
michael@0 1121 *
michael@0 1122 * VALARM 0
michael@0 1123 * VFREEBUSY 0
michael@0 1124 * VJOURNAL 0
michael@0 1125 * VTODO 0
michael@0 1126 * </pre>
michael@0 1127 *
michael@0 1128 */
michael@0 1129 private class ReplyValidator implements Validator {
michael@0 1130
michael@0 1131 private static final long serialVersionUID = 1L;
michael@0 1132
michael@0 1133 public void validate() throws ValidationException {
michael@0 1134 PropertyValidator.getInstance().assertOne(Property.ATTENDEE, getProperties());
michael@0 1135 PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
michael@0 1136 PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
michael@0 1137 PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
michael@0 1138
michael@0 1139 PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties());
michael@0 1140 PropertyValidator.getInstance().assertOneOrLess(Property.SEQUENCE, getProperties());
michael@0 1141 PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties());
michael@0 1142 PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties());
michael@0 1143 PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, getProperties());
michael@0 1144 PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties());
michael@0 1145 PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties());
michael@0 1146 PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties());
michael@0 1147 PropertyValidator.getInstance().assertOneOrLess(Property.DTSTART, getProperties());
michael@0 1148 PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties());
michael@0 1149 PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties());
michael@0 1150 PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties());
michael@0 1151 PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties());
michael@0 1152 PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties());
michael@0 1153 PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties());
michael@0 1154 PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties());
michael@0 1155 PropertyValidator.getInstance().assertOneOrLess(Property.SUMMARY, getProperties());
michael@0 1156 PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties());
michael@0 1157 PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties());
michael@0 1158
michael@0 1159 ComponentValidator.assertNone(Component.VALARM, getAlarms());
michael@0 1160 }
michael@0 1161 }
michael@0 1162
michael@0 1163 /**
michael@0 1164 * METHOD:REQUEST Validator.
michael@0 1165 *
michael@0 1166 * <pre>
michael@0 1167 * Component/Property Presence
michael@0 1168 * -----------------------------------------------------------------
michael@0 1169 * METHOD 1 MUST be "REQUEST"
michael@0 1170 * VEVENT 1+ All components MUST have the same UID
michael@0 1171 * ATTENDEE 1+
michael@0 1172 * DTSTAMP 1
michael@0 1173 * DTSTART 1
michael@0 1174 * ORGANIZER 1
michael@0 1175 * SEQUENCE 0 or 1 MUST be present if value is greater than 0,
michael@0 1176 * MAY be present if 0
michael@0 1177 * SUMMARY 1 Can be null
michael@0 1178 * UID 1
michael@0 1179 *
michael@0 1180 * ATTACH 0+
michael@0 1181 * CATEGORIES 0 or 1 This property may contain a list of values
michael@0 1182 * CLASS 0 or 1
michael@0 1183 * COMMENT 0 or 1
michael@0 1184 * CONTACT 0+
michael@0 1185 * CREATED 0 or 1
michael@0 1186 * DESCRIPTION 0 or 1 Can be null
michael@0 1187 * DTEND 0 or 1 if present DURATION MUST NOT be present
michael@0 1188 * DURATION 0 or 1 if present DTEND MUST NOT be present
michael@0 1189 * EXDATE 0+
michael@0 1190 * EXRULE 0+
michael@0 1191 * GEO 0 or 1
michael@0 1192 * LAST-MODIFIED 0 or 1
michael@0 1193 * LOCATION 0 or 1
michael@0 1194 * PRIORITY 0 or 1
michael@0 1195 * RDATE 0+
michael@0 1196 * RECURRENCE-ID 0 or 1 only if referring to an instance of a
michael@0 1197 * recurring calendar component. Otherwise it
michael@0 1198 * MUST NOT be present.
michael@0 1199 * RELATED-TO 0+
michael@0 1200 * REQUEST-STATUS 0+
michael@0 1201 * RESOURCES 0 or 1 This property MAY contain a list of values
michael@0 1202 * RRULE 0+
michael@0 1203 * STATUS 0 or 1 MAY be one of TENTATIVE/CONFIRMED
michael@0 1204 * TRANSP 0 or 1
michael@0 1205 * URL 0 or 1
michael@0 1206 * X-PROPERTY 0+
michael@0 1207 *
michael@0 1208 * VALARM 0+
michael@0 1209 * VTIMEZONE 0+ MUST be present if any date/time refers to
michael@0 1210 * a timezone
michael@0 1211 * X-COMPONENT 0+
michael@0 1212 * VFREEBUSY 0
michael@0 1213 * VJOURNAL 0
michael@0 1214 * VTODO 0
michael@0 1215 * </pre>
michael@0 1216 *
michael@0 1217 */
michael@0 1218 private class RequestValidator implements Validator {
michael@0 1219
michael@0 1220 private static final long serialVersionUID = 1L;
michael@0 1221
michael@0 1222 public void validate() throws ValidationException {
michael@0 1223 if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) {
michael@0 1224 PropertyValidator.getInstance().assertOneOrMore(Property.ATTENDEE, getProperties());
michael@0 1225 }
michael@0 1226
michael@0 1227 PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
michael@0 1228 PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties());
michael@0 1229 PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
michael@0 1230 PropertyValidator.getInstance().assertOne(Property.SUMMARY, getProperties());
michael@0 1231 PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
michael@0 1232
michael@0 1233 PropertyValidator.getInstance().assertOneOrLess(Property.SEQUENCE, getProperties());
michael@0 1234 PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties());
michael@0 1235 PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties());
michael@0 1236 PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, getProperties());
michael@0 1237 PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties());
michael@0 1238 PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties());
michael@0 1239 PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties());
michael@0 1240 PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties());
michael@0 1241 PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties());
michael@0 1242 PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties());
michael@0 1243 PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties());
michael@0 1244 PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties());
michael@0 1245 PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties());
michael@0 1246 PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties());
michael@0 1247 PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties());
michael@0 1248 PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties());
michael@0 1249 PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties());
michael@0 1250
michael@0 1251 for (final Iterator i = getAlarms().iterator(); i.hasNext();) {
michael@0 1252 final VAlarm alarm = (VAlarm) i.next();
michael@0 1253 alarm.validate(Method.REQUEST);
michael@0 1254 }
michael@0 1255 }
michael@0 1256 }
michael@0 1257 /**
michael@0 1258 * Returns a normalised list of periods representing the consumed time for this event.
michael@0 1259 * @param rangeStart the start of a range
michael@0 1260 * @param rangeEnd the end of a range
michael@0 1261 * @return a normalised list of periods representing consumed time for this event
michael@0 1262 * @see VEvent#getConsumedTime(Date, Date, boolean)
michael@0 1263 */
michael@0 1264 public final PeriodList getConsumedTime(final Date rangeStart,
michael@0 1265 final Date rangeEnd) {
michael@0 1266 return getConsumedTime(rangeStart, rangeEnd, true);
michael@0 1267 }
michael@0 1268
michael@0 1269 /**
michael@0 1270 * Returns a list of periods representing the consumed time for this event in the specified range. Note that the
michael@0 1271 * returned list may contain a single period for non-recurring components or multiple periods for recurring
michael@0 1272 * components. If no time is consumed by this event an empty list is returned.
michael@0 1273 * @param rangeStart the start of the range to check for consumed time
michael@0 1274 * @param rangeEnd the end of the range to check for consumed time
michael@0 1275 * @param normalise indicate whether the returned list of periods should be normalised
michael@0 1276 * @return a list of periods representing consumed time for this event
michael@0 1277 */
michael@0 1278 public final PeriodList getConsumedTime(final Date rangeStart,
michael@0 1279 final Date rangeEnd, final boolean normalise) {
michael@0 1280 PeriodList periods = new PeriodList();
michael@0 1281 // if component is transparent return empty list..
michael@0 1282 if (!Transp.TRANSPARENT.equals(getProperty(Property.TRANSP))) {
michael@0 1283
michael@0 1284 // try {
michael@0 1285 periods = calculateRecurrenceSet(new Period(new DateTime(rangeStart),
michael@0 1286 new DateTime(rangeEnd)));
michael@0 1287 // }
michael@0 1288 // catch (ValidationException ve) {
michael@0 1289 // log.error("Invalid event data", ve);
michael@0 1290 // return periods;
michael@0 1291 // }
michael@0 1292
michael@0 1293 // if periods already specified through recurrence, return..
michael@0 1294 // ..also normalise before returning.
michael@0 1295 if (!periods.isEmpty() && normalise) {
michael@0 1296 periods = periods.normalise();
michael@0 1297 }
michael@0 1298 }
michael@0 1299
michael@0 1300 return periods;
michael@0 1301 }
michael@0 1302
michael@0 1303 /**
michael@0 1304 * Returns a single occurrence of a recurring event.
michael@0 1305 * @param date a date on which the occurence should occur
michael@0 1306 * @return a single non-recurring event instance for the specified date, or null if the event doesn't
michael@0 1307 * occur on the specified date
michael@0 1308 * @throws IOException where an error occurs reading data
michael@0 1309 * @throws URISyntaxException where an invalid URI is encountered
michael@0 1310 * @throws ParseException where an error occurs parsing data
michael@0 1311 */
michael@0 1312 public final VEvent getOccurrence(final Date date) throws IOException,
michael@0 1313 URISyntaxException, ParseException {
michael@0 1314
michael@0 1315 final PeriodList consumedTime = getConsumedTime(date, date);
michael@0 1316 for (final Iterator i = consumedTime.iterator(); i.hasNext();) {
michael@0 1317 final Period p = (Period) i.next();
michael@0 1318 if (p.getStart().equals(date)) {
michael@0 1319 final VEvent occurrence = (VEvent) this.copy();
michael@0 1320 occurrence.getProperties().add(new RecurrenceId(date));
michael@0 1321 return occurrence;
michael@0 1322 }
michael@0 1323 }
michael@0 1324 return null;
michael@0 1325 }
michael@0 1326
michael@0 1327 /**
michael@0 1328 * @return the optional access classification property for an event
michael@0 1329 */
michael@0 1330 public final Clazz getClassification() {
michael@0 1331 return (Clazz) getProperty(Property.CLASS);
michael@0 1332 }
michael@0 1333
michael@0 1334 /**
michael@0 1335 * @return the optional creation-time property for an event
michael@0 1336 */
michael@0 1337 public final Created getCreated() {
michael@0 1338 return (Created) getProperty(Property.CREATED);
michael@0 1339 }
michael@0 1340
michael@0 1341 /**
michael@0 1342 * @return the optional description property for an event
michael@0 1343 */
michael@0 1344 public final Description getDescription() {
michael@0 1345 return (Description) getProperty(Property.DESCRIPTION);
michael@0 1346 }
michael@0 1347
michael@0 1348 /**
michael@0 1349 * Convenience method to pull the DTSTART out of the property list.
michael@0 1350 * @return The DtStart object representation of the start Date
michael@0 1351 */
michael@0 1352 public final DtStart getStartDate() {
michael@0 1353 return (DtStart) getProperty(Property.DTSTART);
michael@0 1354 }
michael@0 1355
michael@0 1356 /**
michael@0 1357 * @return the optional geographic position property for an event
michael@0 1358 */
michael@0 1359 public final Geo getGeographicPos() {
michael@0 1360 return (Geo) getProperty(Property.GEO);
michael@0 1361 }
michael@0 1362
michael@0 1363 /**
michael@0 1364 * @return the optional last-modified property for an event
michael@0 1365 */
michael@0 1366 public final LastModified getLastModified() {
michael@0 1367 return (LastModified) getProperty(Property.LAST_MODIFIED);
michael@0 1368 }
michael@0 1369
michael@0 1370 /**
michael@0 1371 * @return the optional location property for an event
michael@0 1372 */
michael@0 1373 public final Location getLocation() {
michael@0 1374 return (Location) getProperty(Property.LOCATION);
michael@0 1375 }
michael@0 1376
michael@0 1377 /**
michael@0 1378 * @return the optional organizer property for an event
michael@0 1379 */
michael@0 1380 public final Organizer getOrganizer() {
michael@0 1381 return (Organizer) getProperty(Property.ORGANIZER);
michael@0 1382 }
michael@0 1383
michael@0 1384 /**
michael@0 1385 * @return the optional priority property for an event
michael@0 1386 */
michael@0 1387 public final Priority getPriority() {
michael@0 1388 return (Priority) getProperty(Property.PRIORITY);
michael@0 1389 }
michael@0 1390
michael@0 1391 /**
michael@0 1392 * @return the optional date-stamp property
michael@0 1393 */
michael@0 1394 public final DtStamp getDateStamp() {
michael@0 1395 return (DtStamp) getProperty(Property.DTSTAMP);
michael@0 1396 }
michael@0 1397
michael@0 1398 /**
michael@0 1399 * @return the optional sequence number property for an event
michael@0 1400 */
michael@0 1401 public final Sequence getSequence() {
michael@0 1402 return (Sequence) getProperty(Property.SEQUENCE);
michael@0 1403 }
michael@0 1404
michael@0 1405 /**
michael@0 1406 * @return the optional status property for an event
michael@0 1407 */
michael@0 1408 public final Status getStatus() {
michael@0 1409 return (Status) getProperty(Property.STATUS);
michael@0 1410 }
michael@0 1411
michael@0 1412 /**
michael@0 1413 * @return the optional summary property for an event
michael@0 1414 */
michael@0 1415 public final Summary getSummary() {
michael@0 1416 return (Summary) getProperty(Property.SUMMARY);
michael@0 1417 }
michael@0 1418
michael@0 1419 /**
michael@0 1420 * @return the optional time transparency property for an event
michael@0 1421 */
michael@0 1422 public final Transp getTransparency() {
michael@0 1423 return (Transp) getProperty(Property.TRANSP);
michael@0 1424 }
michael@0 1425
michael@0 1426 /**
michael@0 1427 * @return the optional URL property for an event
michael@0 1428 */
michael@0 1429 public final Url getUrl() {
michael@0 1430 return (Url) getProperty(Property.URL);
michael@0 1431 }
michael@0 1432
michael@0 1433 /**
michael@0 1434 * @return the optional recurrence identifier property for an event
michael@0 1435 */
michael@0 1436 public final RecurrenceId getRecurrenceId() {
michael@0 1437 return (RecurrenceId) getProperty(Property.RECURRENCE_ID);
michael@0 1438 }
michael@0 1439
michael@0 1440 /**
michael@0 1441 * Returns the end date of this event. Where an end date is not available it will be derived from the event
michael@0 1442 * duration.
michael@0 1443 * @return a DtEnd instance, or null if one cannot be derived
michael@0 1444 */
michael@0 1445 public final DtEnd getEndDate() {
michael@0 1446 return getEndDate(true);
michael@0 1447 }
michael@0 1448
michael@0 1449 /**
michael@0 1450 * Convenience method to pull the DTEND out of the property list. If DTEND was not specified, use the DTSTART +
michael@0 1451 * DURATION to calculate it.
michael@0 1452 * @param deriveFromDuration specifies whether to derive an end date from the event duration where an end date is
michael@0 1453 * not found
michael@0 1454 * @return The end for this VEVENT.
michael@0 1455 */
michael@0 1456 public final DtEnd getEndDate(final boolean deriveFromDuration) {
michael@0 1457 DtEnd dtEnd = (DtEnd) getProperty(Property.DTEND);
michael@0 1458 // No DTEND? No problem, we'll use the DURATION.
michael@0 1459 if (dtEnd == null && deriveFromDuration && getDuration() != null) {
michael@0 1460 final DtStart dtStart = getStartDate();
michael@0 1461 final Duration vEventDuration = getDuration();
michael@0 1462 dtEnd = new DtEnd(Dates.getInstance(vEventDuration.getDuration()
michael@0 1463 .getTime(dtStart.getDate()), (Value) dtStart
michael@0 1464 .getParameter(Parameter.VALUE)));
michael@0 1465 if (dtStart.isUtc()) {
michael@0 1466 dtEnd.setUtc(true);
michael@0 1467 }
michael@0 1468 }
michael@0 1469 return dtEnd;
michael@0 1470 }
michael@0 1471
michael@0 1472 /**
michael@0 1473 * @return the optional Duration property
michael@0 1474 */
michael@0 1475 public final Duration getDuration() {
michael@0 1476 return (Duration) getProperty(Property.DURATION);
michael@0 1477 }
michael@0 1478
michael@0 1479 /**
michael@0 1480 * Returns the UID property of this component if available.
michael@0 1481 * @return a Uid instance, or null if no UID property exists
michael@0 1482 */
michael@0 1483 public final Uid getUid() {
michael@0 1484 return (Uid) getProperty(Property.UID);
michael@0 1485 }
michael@0 1486
michael@0 1487 /**
michael@0 1488 * {@inheritDoc}
michael@0 1489 */
michael@0 1490 public boolean equals(final Object arg0) {
michael@0 1491 if (arg0 instanceof VEvent) {
michael@0 1492 return super.equals(arg0)
michael@0 1493 && ObjectUtils.equals(alarms, ((VEvent) arg0).getAlarms());
michael@0 1494 }
michael@0 1495 return super.equals(arg0);
michael@0 1496 }
michael@0 1497
michael@0 1498 /**
michael@0 1499 * {@inheritDoc}
michael@0 1500 */
michael@0 1501 public int hashCode() {
michael@0 1502 return new HashCodeBuilder().append(getName()).append(getProperties())
michael@0 1503 .append(getAlarms()).toHashCode();
michael@0 1504 }
michael@0 1505
michael@0 1506 /**
michael@0 1507 * Overrides default copy method to add support for copying alarm sub-components.
michael@0 1508 * @return a copy of the instance
michael@0 1509 * @throws ParseException where values in the instance cannot be parsed
michael@0 1510 * @throws IOException where values in the instance cannot be read
michael@0 1511 * @throws URISyntaxException where an invalid URI value is encountered in the instance
michael@0 1512 * @see net.fortuna.ical4j.model.Component#copy()
michael@0 1513 */
michael@0 1514 public Component copy() throws ParseException, IOException,
michael@0 1515 URISyntaxException {
michael@0 1516 final VEvent copy = (VEvent) super.copy();
michael@0 1517 copy.alarms = new ComponentList(alarms);
michael@0 1518 return copy;
michael@0 1519 }
michael@0 1520 }

mercurial