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

Tue, 10 Feb 2015 19:58:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 10 Feb 2015 19:58:00 +0100
changeset 4
45d57ecba757
parent 3
73bdfa70b04e
permissions
-rw-r--r--

Upgrade the upgraded ical4j component to use org.apache.commons.lang3.

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@4 80 import org.apache.commons.lang3.ObjectUtils;
michael@4 81 import org.apache.commons.lang3.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.CREATED, getProperties());
michael@0 552 PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties());
michael@0 553 PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties());
michael@0 554 PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties());
michael@0 555 PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties());
michael@0 556 PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties());
michael@0 557 PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties());
michael@0 558 PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties());
michael@0 559 PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties());
michael@0 560 PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties());
michael@0 561 PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties());
michael@0 562 PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties());
michael@0 563
michael@0 564 PropertyValidator.getInstance().assertNone(Property.RECURRENCE_ID, getProperties());
michael@0 565 PropertyValidator.getInstance().assertNone(Property.REQUEST_STATUS, getProperties());
michael@0 566
michael@0 567 for (final Iterator i = getAlarms().iterator(); i.hasNext();) {
michael@0 568 final VAlarm alarm = (VAlarm) i.next();
michael@0 569 alarm.validate(Method.ADD);
michael@0 570 }
michael@0 571 }
michael@0 572 }
michael@0 573
michael@0 574 /**
michael@0 575 * METHOD:CANCEL Validator.
michael@0 576 *
michael@0 577 * <pre>
michael@0 578 * Component/Property Presence
michael@0 579 * ------------------- ----------------------------------------------
michael@0 580 * METHOD 1 MUST be "CANCEL"
michael@0 581 *
michael@0 582 * VEVENT 1+ All must have the same UID
michael@0 583 * ATTENDEE 0+ MUST include all "Attendees" being removed
michael@0 584 * the event. MUST include all "Attendees" if
michael@0 585 * the entire event is cancelled.
michael@0 586 * DTSTAMP 1
michael@0 587 * ORGANIZER 1
michael@0 588 * SEQUENCE 1
michael@0 589 * UID 1 MUST be the UID of the original REQUEST
michael@0 590 *
michael@0 591 * COMMENT 0 or 1
michael@0 592 * ATTACH 0+
michael@0 593 * CATEGORIES 0 or 1 This property may contain a list of values
michael@0 594 * CLASS 0 or 1
michael@0 595 * CONTACT 0+
michael@0 596 * CREATED 0 or 1
michael@0 597 * DESCRIPTION 0 or 1
michael@0 598 * DTEND 0 or 1 if present DURATION MUST NOT be present
michael@0 599 * DTSTART 0 or 1
michael@0 600 * DURATION 0 or 1 if present DTEND MUST NOT be present
michael@0 601 * EXDATE 0+
michael@0 602 * EXRULE 0+
michael@0 603 * GEO 0 or 1
michael@0 604 * LAST-MODIFIED 0 or 1
michael@0 605 * LOCATION 0 or 1
michael@0 606 * PRIORITY 0 or 1
michael@0 607 * RDATE 0+
michael@0 608 * RECURRENCE-ID 0 or 1 MUST be present if referring to one or
michael@0 609 * more or more recurring instances.
michael@0 610 * Otherwise it MUST NOT be present
michael@0 611 * RELATED-TO 0+
michael@0 612 * RESOURCES 0 or 1
michael@0 613 * RRULE 0+
michael@0 614 * STATUS 0 or 1 MUST be set to CANCELLED. If uninviting
michael@0 615 * specific "Attendees" then MUST NOT be
michael@0 616 * included.
michael@0 617 * SUMMARY 0 or 1
michael@0 618 * TRANSP 0 or 1
michael@0 619 * URL 0 or 1
michael@0 620 * X-PROPERTY 0+
michael@0 621 * REQUEST-STATUS 0
michael@0 622 *
michael@0 623 * VTIMEZONE 0+ MUST be present if any date/time refers to
michael@0 624 * a timezone
michael@0 625 * X-COMPONENT 0+
michael@0 626 *
michael@0 627 * VTODO 0
michael@0 628 * VJOURNAL 0
michael@0 629 * VFREEBUSY 0
michael@0 630 * VALARM 0
michael@0 631 * </pre>
michael@0 632 *
michael@0 633 */
michael@0 634 private class CancelValidator implements Validator {
michael@0 635
michael@0 636 private static final long serialVersionUID = 1L;
michael@0 637
michael@0 638 public final void validate() throws ValidationException {
michael@0 639 PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
michael@0 640 PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties());
michael@0 641 PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
michael@0 642 PropertyValidator.getInstance().assertOne(Property.SEQUENCE, getProperties());
michael@0 643 PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
michael@0 644
michael@0 645 PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties());
michael@0 646 PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties());
michael@0 647 PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties());
michael@0 648 PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties());
michael@0 649 PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties());
michael@0 650 PropertyValidator.getInstance().assertOneOrLess(Property.DTSTART, getProperties());
michael@0 651 PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties());
michael@0 652 PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties());
michael@0 653 PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties());
michael@0 654 PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties());
michael@0 655 PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties());
michael@0 656 PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties());
michael@0 657 PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties());
michael@0 658 PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties());
michael@0 659 PropertyValidator.getInstance().assertOneOrLess(Property.SUMMARY, getProperties());
michael@0 660 PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties());
michael@0 661 PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties());
michael@0 662
michael@0 663 PropertyValidator.getInstance().assertNone(Property.REQUEST_STATUS, getProperties());
michael@0 664
michael@0 665 ComponentValidator.assertNone(Component.VALARM, getAlarms());
michael@0 666 }
michael@0 667 }
michael@0 668
michael@0 669 /**
michael@0 670 * METHOD:COUNTER Validator.
michael@0 671 *
michael@0 672 * <pre>
michael@0 673 * Component/Property Presence
michael@0 674 * ------------------- ----------------------------------------------
michael@0 675 * METHOD 1 MUST be "COUNTER"
michael@0 676 *
michael@0 677 * VEVENT 1
michael@0 678 * DTSTAMP 1
michael@0 679 * DTSTART 1
michael@0 680 * ORGANIZER 1 MUST be the "Organizer" of the original
michael@0 681 * event
michael@0 682 * SEQUENCE 1 MUST be present if value is greater than 0,
michael@0 683 * MAY be present if 0
michael@0 684 * SUMMARY 1 Can be null
michael@0 685 * UID 1 MUST be the UID associated with the REQUEST
michael@0 686 * being countered
michael@0 687 *
michael@0 688 * ATTACH 0+
michael@0 689 * ATTENDEE 0+ Can also be used to propose other
michael@0 690 * "Attendees"
michael@0 691 * CATEGORIES 0 or 1 This property may contain a list of values
michael@0 692 * CLASS 0 or 1
michael@0 693 * COMMENT 0 or 1
michael@0 694 * CONTACT 0+
michael@0 695 * CREATED 0 or 1
michael@0 696 * DESCRIPTION 0 or 1
michael@0 697 * DTEND 0 or 1 if present DURATION MUST NOT be present
michael@0 698 * DURATION 0 or 1 if present DTEND MUST NOT be present
michael@0 699 * EXDATE 0+
michael@0 700 * EXRULE 0+
michael@0 701 * GEO 0 or 1
michael@0 702 * LAST-MODIFIED 0 or 1
michael@0 703 * LOCATION 0 or 1
michael@0 704 * PRIORITY 0 or 1
michael@0 705 * RDATE 0+
michael@0 706 * RECURRENCE-ID 0 or 1 MUST only if referring to an instance of a
michael@0 707 * recurring calendar component. Otherwise it
michael@0 708 * MUST NOT be present.
michael@0 709 * RELATED-TO 0+
michael@0 710 * REQUEST-STATUS 0+
michael@0 711 * RESOURCES 0 or 1 This property may contain a list of values
michael@0 712 * RRULE 0+
michael@0 713 * STATUS 0 or 1 Value must be one of CONFIRMED/TENATIVE/
michael@0 714 * CANCELLED
michael@0 715 * TRANSP 0 or 1
michael@0 716 * URL 0 or 1
michael@0 717 * X-PROPERTY 0+
michael@0 718 *
michael@0 719 * VALARM 0+
michael@0 720 * VTIMEZONE 0+ MUST be present if any date/time refers to
michael@0 721 * a timezone
michael@0 722 * X-COMPONENT 0+
michael@0 723 *
michael@0 724 * VTODO 0
michael@0 725 * VJOURNAL 0
michael@0 726 * VFREEBUSY 0
michael@0 727 * </pre>
michael@0 728 *
michael@0 729 */
michael@0 730 private class CounterValidator implements Validator {
michael@0 731
michael@0 732 private static final long serialVersionUID = 1L;
michael@0 733
michael@0 734 public void validate() throws ValidationException {
michael@0 735 PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
michael@0 736 PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties());
michael@0 737
michael@0 738 if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) {
michael@0 739 PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
michael@0 740 }
michael@0 741
michael@0 742 PropertyValidator.getInstance().assertOne(Property.SEQUENCE, getProperties());
michael@0 743 PropertyValidator.getInstance().assertOne(Property.SUMMARY, getProperties());
michael@0 744 PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
michael@0 745
michael@0 746 PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties());
michael@0 747 PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties());
michael@0 748 PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties());
michael@0 749 PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties());
michael@0 750 PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties());
michael@0 751 PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties());
michael@0 752 PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties());
michael@0 753 PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties());
michael@0 754 PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties());
michael@0 755 PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties());
michael@0 756 PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties());
michael@0 757 PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties());
michael@0 758 PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties());
michael@0 759 PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties());
michael@0 760 PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties());
michael@0 761
michael@0 762 for (final Iterator i = getAlarms().iterator(); i.hasNext();) {
michael@0 763 final VAlarm alarm = (VAlarm) i.next();
michael@0 764 alarm.validate(Method.COUNTER);
michael@0 765 }
michael@0 766 }
michael@0 767 }
michael@0 768
michael@0 769 /**
michael@0 770 * METHOD:DECLINECOUNTER Validator.
michael@0 771 *
michael@0 772 * <pre>
michael@0 773 * Component/Property Presence
michael@0 774 * ------------------- ----------------------------------------------
michael@0 775 * METHOD 1 MUST be "DECLINECOUNTER"
michael@0 776 *
michael@0 777 * VEVENT 1
michael@0 778 * DTSTAMP 1
michael@0 779 * ORGANIZER 1
michael@0 780 * UID 1 MUST, same UID specified in original
michael@0 781 * REQUEST and subsequent COUNTER
michael@0 782 * COMMENT 0 or 1
michael@0 783 * RECURRENCE-ID 0 or 1 MUST only if referring to an instance of a
michael@0 784 * recurring calendar component. Otherwise it
michael@0 785 * MUST NOT be present.
michael@0 786 * REQUEST-STATUS 0+
michael@0 787 * SEQUENCE 0 OR 1 MUST be present if value is greater than 0,
michael@0 788 * MAY be present if 0
michael@0 789 * X-PROPERTY 0+
michael@0 790 * ATTACH 0
michael@0 791 * ATTENDEE 0
michael@0 792 * CATEGORIES 0
michael@0 793 * CLASS 0
michael@0 794 * CONTACT 0
michael@0 795 * CREATED 0
michael@0 796 * DESCRIPTION 0
michael@0 797 * DTEND 0
michael@0 798 * DTSTART 0
michael@0 799 * DURATION 0
michael@0 800 * EXDATE 0
michael@0 801 * EXRULE 0
michael@0 802 * GEO 0
michael@0 803 * LAST-MODIFIED 0
michael@0 804 * LOCATION 0
michael@0 805 * PRIORITY 0
michael@0 806 * RDATE 0
michael@0 807 * RELATED-TO 0
michael@0 808 * RESOURCES 0
michael@0 809 * RRULE 0
michael@0 810 * STATUS 0
michael@0 811 * SUMMARY 0
michael@0 812 * TRANSP 0
michael@0 813 * URL 0
michael@0 814 *
michael@0 815 * X-COMPONENT 0+
michael@0 816 * VTODO 0
michael@0 817 * VJOURNAL 0
michael@0 818 * VFREEBUSY 0
michael@0 819 * VTIMEZONE 0
michael@0 820 * VALARM 0
michael@0 821 * </pre>
michael@0 822 *
michael@0 823 */
michael@0 824 private class DeclineCounterValidator implements Validator {
michael@0 825
michael@0 826 private static final long serialVersionUID = 1L;
michael@0 827
michael@0 828 public void validate() throws ValidationException {
michael@0 829 PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
michael@0 830 PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
michael@0 831 PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
michael@0 832
michael@0 833 PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties());
michael@0 834 PropertyValidator.getInstance().assertOneOrLess(Property.SEQUENCE, getProperties());
michael@0 835
michael@0 836 PropertyValidator.getInstance().assertNone(Property.ATTACH, getProperties());
michael@0 837 PropertyValidator.getInstance().assertNone(Property.ATTENDEE, getProperties());
michael@0 838 PropertyValidator.getInstance().assertNone(Property.CATEGORIES, getProperties());
michael@0 839 PropertyValidator.getInstance().assertNone(Property.CLASS, getProperties());
michael@0 840 PropertyValidator.getInstance().assertNone(Property.CONTACT, getProperties());
michael@0 841 PropertyValidator.getInstance().assertNone(Property.CREATED, getProperties());
michael@0 842 PropertyValidator.getInstance().assertNone(Property.DESCRIPTION, getProperties());
michael@0 843 PropertyValidator.getInstance().assertNone(Property.DTEND, getProperties());
michael@0 844 PropertyValidator.getInstance().assertNone(Property.DTSTART, getProperties());
michael@0 845 PropertyValidator.getInstance().assertNone(Property.DURATION, getProperties());
michael@0 846 PropertyValidator.getInstance().assertNone(Property.EXDATE, getProperties());
michael@0 847 PropertyValidator.getInstance().assertNone(Property.EXRULE, getProperties());
michael@0 848 PropertyValidator.getInstance().assertNone(Property.GEO, getProperties());
michael@0 849 PropertyValidator.getInstance().assertNone(Property.LAST_MODIFIED, getProperties());
michael@0 850 PropertyValidator.getInstance().assertNone(Property.LOCATION, getProperties());
michael@0 851 PropertyValidator.getInstance().assertNone(Property.PRIORITY, getProperties());
michael@0 852 PropertyValidator.getInstance().assertNone(Property.RDATE, getProperties());
michael@0 853 PropertyValidator.getInstance().assertNone(Property.RELATED_TO, getProperties());
michael@0 854 PropertyValidator.getInstance().assertNone(Property.RESOURCES, getProperties());
michael@0 855 PropertyValidator.getInstance().assertNone(Property.RRULE, getProperties());
michael@0 856 PropertyValidator.getInstance().assertNone(Property.STATUS, getProperties());
michael@0 857 PropertyValidator.getInstance().assertNone(Property.SUMMARY, getProperties());
michael@0 858 PropertyValidator.getInstance().assertNone(Property.TRANSP, getProperties());
michael@0 859 PropertyValidator.getInstance().assertNone(Property.URL, getProperties());
michael@0 860
michael@0 861 ComponentValidator.assertNone(Component.VALARM, getAlarms());
michael@0 862 }
michael@0 863 }
michael@0 864
michael@0 865 /**
michael@0 866 * METHOD:PUBLISH Validator.
michael@0 867 *
michael@0 868 * <pre>
michael@0 869 * Component/Property Presence
michael@0 870 * ------------------- ----------------------------------------------
michael@0 871 * METHOD 1 MUST equal "PUBLISH"
michael@0 872 * VEVENT 1+
michael@0 873 * DTSTAMP 1
michael@0 874 * DTSTART 1
michael@0 875 * ORGANIZER 1
michael@0 876 * SUMMARY 1 Can be null.
michael@0 877 * UID 1
michael@0 878 * RECURRENCE-ID 0 or 1 only if referring to an instance of a
michael@0 879 * recurring calendar component. Otherwise
michael@0 880 * it MUST NOT be present.
michael@0 881 * SEQUENCE 0 or 1 MUST be present if value is greater than
michael@0 882 * 0, MAY be present if 0
michael@0 883 * ATTACH 0+
michael@0 884 * CATEGORIES 0 or 1 This property may contain a list of
michael@0 885 * values
michael@0 886 * CLASS 0 or 1
michael@0 887 * COMMENT 0 or 1
michael@0 888 * CONTACT 0+
michael@0 889 * CREATED 0 or 1
michael@0 890 * DESCRIPTION 0 or 1 Can be null
michael@0 891 * DTEND 0 or 1 if present DURATION MUST NOT be present
michael@0 892 * DURATION 0 or 1 if present DTEND MUST NOT be present
michael@0 893 * EXDATE 0+
michael@0 894 * EXRULE 0+
michael@0 895 * GEO 0 or 1
michael@0 896 * LAST-MODIFIED 0 or 1
michael@0 897 * LOCATION 0 or 1
michael@0 898 * PRIORITY 0 or 1
michael@0 899 * RDATE 0+
michael@0 900 * RELATED-TO 0+
michael@0 901 * RESOURCES 0 or 1 This property MAY contain a list of values
michael@0 902 * RRULE 0+
michael@0 903 * STATUS 0 or 1 MAY be one of TENTATIVE/CONFIRMED/CANCELLED
michael@0 904 * TRANSP 0 or 1
michael@0 905 * URL 0 or 1
michael@0 906 * X-PROPERTY 0+
michael@0 907 *
michael@0 908 * ATTENDEE 0
michael@0 909 * REQUEST-STATUS 0
michael@0 910 *
michael@0 911 * VALARM 0+
michael@0 912 * VFREEBUSY 0
michael@0 913 * VJOURNAL 0
michael@0 914 * VTODO 0
michael@0 915 * VTIMEZONE 0+ MUST be present if any date/time refers to
michael@0 916 * a timezone
michael@0 917 * X-COMPONENT 0+
michael@0 918 * </pre>
michael@0 919 *
michael@0 920 */
michael@0 921 private class PublishValidator implements Validator {
michael@0 922
michael@0 923 private static final long serialVersionUID = 1L;
michael@0 924
michael@0 925 public void validate() throws ValidationException {
michael@0 926 PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
michael@0 927 PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties());
michael@0 928
michael@0 929 if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) {
michael@0 930 PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
michael@0 931 PropertyValidator.getInstance().assertOne(Property.SUMMARY, getProperties());
michael@0 932 }
michael@0 933
michael@0 934 PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
michael@0 935
michael@0 936 PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties());
michael@0 937 PropertyValidator.getInstance().assertOneOrLess(Property.SEQUENCE, getProperties());
michael@0 938 PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties());
michael@0 939 PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties());
michael@0 940 PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties());
michael@0 941 PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties());
michael@0 942 PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties());
michael@0 943 PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties());
michael@0 944 PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties());
michael@0 945 PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties());
michael@0 946 PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties());
michael@0 947 PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties());
michael@0 948 PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties());
michael@0 949 PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties());
michael@0 950 PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties());
michael@0 951 PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties());
michael@0 952
michael@0 953 if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) {
michael@0 954 PropertyValidator.getInstance().assertNone(Property.ATTENDEE, getProperties());
michael@0 955 }
michael@0 956
michael@0 957 PropertyValidator.getInstance().assertNone(Property.REQUEST_STATUS, getProperties());
michael@0 958
michael@0 959 for (final Iterator i = getAlarms().iterator(); i.hasNext();) {
michael@0 960 final VAlarm alarm = (VAlarm) i.next();
michael@0 961 alarm.validate(Method.PUBLISH);
michael@0 962 }
michael@0 963 }
michael@0 964 }
michael@0 965
michael@0 966 /**
michael@0 967 * METHOD:REFRESH Validator.
michael@0 968 *
michael@0 969 * <pre>
michael@0 970 * Component/Property Presence
michael@0 971 * ------------------- ----------------------------------------------
michael@0 972 * METHOD 1 MUST be "REFRESH"
michael@0 973 *
michael@0 974 * VEVENT 1
michael@0 975 * ATTENDEE 1 MUST be the address of requestor
michael@0 976 * DTSTAMP 1
michael@0 977 * ORGANIZER 1
michael@0 978 * UID 1 MUST be the UID associated with original
michael@0 979 * REQUEST
michael@0 980 * COMMENT 0 or 1
michael@0 981 * RECURRENCE-ID 0 or 1 MUST only if referring to an instance of a
michael@0 982 * recurring calendar component. Otherwise
michael@0 983 * it must NOT be present.
michael@0 984 * X-PROPERTY 0+
michael@0 985 *
michael@0 986 * ATTACH 0
michael@0 987 * CATEGORIES 0
michael@0 988 * CLASS 0
michael@0 989 * CONTACT 0
michael@0 990 * CREATED 0
michael@0 991 * DESCRIPTION 0
michael@0 992 * DTEND 0
michael@0 993 * DTSTART 0
michael@0 994 * DURATION 0
michael@0 995 * EXDATE 0
michael@0 996 * EXRULE 0
michael@0 997 * GEO 0
michael@0 998 * LAST-MODIFIED 0
michael@0 999 * LOCATION 0
michael@0 1000 * PRIORITY 0
michael@0 1001 * RDATE 0
michael@0 1002 * RELATED-TO 0
michael@0 1003 * REQUEST-STATUS 0
michael@0 1004 * RESOURCES 0
michael@0 1005 * RRULE 0
michael@0 1006 * SEQUENCE 0
michael@0 1007 * STATUS 0
michael@0 1008 * SUMMARY 0
michael@0 1009 * TRANSP 0
michael@0 1010 * URL 0
michael@0 1011 *
michael@0 1012 * X-COMPONENT 0+
michael@0 1013 *
michael@0 1014 * VTODO 0
michael@0 1015 * VJOURNAL 0
michael@0 1016 * VFREEBUSY 0
michael@0 1017 * VTIMEZONE 0
michael@0 1018 * VALARM 0
michael@0 1019 * </pre>
michael@0 1020 *
michael@0 1021 */
michael@0 1022 private class RefreshValidator implements Validator {
michael@0 1023
michael@0 1024 private static final long serialVersionUID = 1L;
michael@0 1025
michael@0 1026 public void validate() throws ValidationException {
michael@0 1027 PropertyValidator.getInstance().assertOne(Property.ATTENDEE, getProperties());
michael@0 1028 PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
michael@0 1029 PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
michael@0 1030 PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
michael@0 1031
michael@0 1032 PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties());
michael@0 1033
michael@0 1034 PropertyValidator.getInstance().assertNone(Property.ATTACH, getProperties());
michael@0 1035 PropertyValidator.getInstance().assertNone(Property.CATEGORIES, getProperties());
michael@0 1036 PropertyValidator.getInstance().assertNone(Property.CLASS, getProperties());
michael@0 1037 PropertyValidator.getInstance().assertNone(Property.CONTACT, getProperties());
michael@0 1038 PropertyValidator.getInstance().assertNone(Property.CREATED, getProperties());
michael@0 1039 PropertyValidator.getInstance().assertNone(Property.DESCRIPTION, getProperties());
michael@0 1040 PropertyValidator.getInstance().assertNone(Property.DTEND, getProperties());
michael@0 1041 PropertyValidator.getInstance().assertNone(Property.DTSTART, getProperties());
michael@0 1042 PropertyValidator.getInstance().assertNone(Property.DURATION, getProperties());
michael@0 1043 PropertyValidator.getInstance().assertNone(Property.EXDATE, getProperties());
michael@0 1044 PropertyValidator.getInstance().assertNone(Property.EXRULE, getProperties());
michael@0 1045 PropertyValidator.getInstance().assertNone(Property.GEO, getProperties());
michael@0 1046 PropertyValidator.getInstance().assertNone(Property.LAST_MODIFIED, getProperties());
michael@0 1047 PropertyValidator.getInstance().assertNone(Property.LOCATION, getProperties());
michael@0 1048 PropertyValidator.getInstance().assertNone(Property.PRIORITY, getProperties());
michael@0 1049 PropertyValidator.getInstance().assertNone(Property.RDATE, getProperties());
michael@0 1050 PropertyValidator.getInstance().assertNone(Property.RELATED_TO, getProperties());
michael@0 1051 PropertyValidator.getInstance().assertNone(Property.REQUEST_STATUS, getProperties());
michael@0 1052 PropertyValidator.getInstance().assertNone(Property.RESOURCES, getProperties());
michael@0 1053 PropertyValidator.getInstance().assertNone(Property.RRULE, getProperties());
michael@0 1054 PropertyValidator.getInstance().assertNone(Property.SEQUENCE, getProperties());
michael@0 1055 PropertyValidator.getInstance().assertNone(Property.STATUS, getProperties());
michael@0 1056 PropertyValidator.getInstance().assertNone(Property.SUMMARY, getProperties());
michael@0 1057 PropertyValidator.getInstance().assertNone(Property.TRANSP, getProperties());
michael@0 1058 PropertyValidator.getInstance().assertNone(Property.URL, getProperties());
michael@0 1059
michael@0 1060 ComponentValidator.assertNone(Component.VALARM, getAlarms());
michael@0 1061 }
michael@0 1062 }
michael@0 1063
michael@0 1064 /**
michael@0 1065 * METHOD:REPLY Validator.
michael@0 1066 *
michael@0 1067 * <pre>
michael@0 1068 * Component/Property Presence
michael@0 1069 * ------------------- ----------------------------------------------
michael@0 1070 * METHOD 1 MUST be "REPLY"
michael@0 1071 * VEVENT 1+ All components MUST have the same UID
michael@0 1072 * ATTENDEE 1 MUST be the address of the Attendee
michael@0 1073 * replying.
michael@0 1074 * DTSTAMP 1
michael@0 1075 * ORGANIZER 1
michael@0 1076 * RECURRENCE-ID 0 or 1 only if referring to an instance of a
michael@0 1077 * recurring calendar component. Otherwise
michael@0 1078 * it must NOT be present.
michael@0 1079 * UID 1 MUST be the UID of the original REQUEST
michael@0 1080 *
michael@0 1081 * SEQUENCE 0 or 1 MUST if non-zero, MUST be the sequence
michael@0 1082 * number of the original REQUEST. MAY be
michael@0 1083 * present if 0.
michael@0 1084 *
michael@0 1085 * ATTACH 0+
michael@0 1086 * CATEGORIES 0 or 1 This property may contain a list of values
michael@0 1087 * CLASS 0 or 1
michael@0 1088 * COMMENT 0 or 1
michael@0 1089 * CONTACT 0+
michael@0 1090 * CREATED 0 or 1
michael@0 1091 * DESCRIPTION 0 or 1
michael@0 1092 * DTEND 0 or 1 if present DURATION MUST NOT be present
michael@0 1093 * DTSTART 0 or 1
michael@0 1094 * DURATION 0 or 1 if present DTEND MUST NOT be present
michael@0 1095 * EXDATE 0+
michael@0 1096 * EXRULE 0+
michael@0 1097 * GEO 0 or 1
michael@0 1098 * LAST-MODIFIED 0 or 1
michael@0 1099 * LOCATION 0 or 1
michael@0 1100 * PRIORITY 0 or 1
michael@0 1101 * RDATE 0+
michael@0 1102 * RELATED-TO 0+
michael@0 1103 * RESOURCES 0 or 1 This property MAY contain a list of values
michael@0 1104 * REQUEST-STATUS 0+
michael@0 1105 * RRULE 0+
michael@0 1106 * STATUS 0 or 1
michael@0 1107 * SUMMARY 0 or 1
michael@0 1108 * TRANSP 0 or 1
michael@0 1109 * URL 0 or 1
michael@0 1110 * X-PROPERTY 0+
michael@0 1111 *
michael@0 1112 * VTIMEZONE 0 or 1 MUST be present if any date/time refers
michael@0 1113 * to a timezone
michael@0 1114 * X-COMPONENT 0+
michael@0 1115 *
michael@0 1116 * VALARM 0
michael@0 1117 * VFREEBUSY 0
michael@0 1118 * VJOURNAL 0
michael@0 1119 * VTODO 0
michael@0 1120 * </pre>
michael@0 1121 *
michael@0 1122 */
michael@0 1123 private class ReplyValidator implements Validator {
michael@0 1124
michael@0 1125 private static final long serialVersionUID = 1L;
michael@0 1126
michael@0 1127 public void validate() throws ValidationException {
michael@0 1128 PropertyValidator.getInstance().assertOne(Property.ATTENDEE, getProperties());
michael@0 1129 PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
michael@0 1130 PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
michael@0 1131 PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
michael@0 1132
michael@0 1133 PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties());
michael@0 1134 PropertyValidator.getInstance().assertOneOrLess(Property.SEQUENCE, getProperties());
michael@0 1135 PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties());
michael@0 1136 PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties());
michael@0 1137 PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties());
michael@0 1138 PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties());
michael@0 1139 PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties());
michael@0 1140 PropertyValidator.getInstance().assertOneOrLess(Property.DTSTART, getProperties());
michael@0 1141 PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties());
michael@0 1142 PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties());
michael@0 1143 PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties());
michael@0 1144 PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties());
michael@0 1145 PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties());
michael@0 1146 PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties());
michael@0 1147 PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties());
michael@0 1148 PropertyValidator.getInstance().assertOneOrLess(Property.SUMMARY, getProperties());
michael@0 1149 PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties());
michael@0 1150 PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties());
michael@0 1151
michael@0 1152 ComponentValidator.assertNone(Component.VALARM, getAlarms());
michael@0 1153 }
michael@0 1154 }
michael@0 1155
michael@0 1156 /**
michael@0 1157 * METHOD:REQUEST Validator.
michael@0 1158 *
michael@0 1159 * <pre>
michael@0 1160 * Component/Property Presence
michael@0 1161 * -----------------------------------------------------------------
michael@0 1162 * METHOD 1 MUST be "REQUEST"
michael@0 1163 * VEVENT 1+ All components MUST have the same UID
michael@0 1164 * ATTENDEE 1+
michael@0 1165 * DTSTAMP 1
michael@0 1166 * DTSTART 1
michael@0 1167 * ORGANIZER 1
michael@0 1168 * SEQUENCE 0 or 1 MUST be present if value is greater than 0,
michael@0 1169 * MAY be present if 0
michael@0 1170 * SUMMARY 1 Can be null
michael@0 1171 * UID 1
michael@0 1172 *
michael@0 1173 * ATTACH 0+
michael@0 1174 * CATEGORIES 0 or 1 This property may contain a list of values
michael@0 1175 * CLASS 0 or 1
michael@0 1176 * COMMENT 0 or 1
michael@0 1177 * CONTACT 0+
michael@0 1178 * CREATED 0 or 1
michael@0 1179 * DESCRIPTION 0 or 1 Can be null
michael@0 1180 * DTEND 0 or 1 if present DURATION MUST NOT be present
michael@0 1181 * DURATION 0 or 1 if present DTEND MUST NOT be present
michael@0 1182 * EXDATE 0+
michael@0 1183 * EXRULE 0+
michael@0 1184 * GEO 0 or 1
michael@0 1185 * LAST-MODIFIED 0 or 1
michael@0 1186 * LOCATION 0 or 1
michael@0 1187 * PRIORITY 0 or 1
michael@0 1188 * RDATE 0+
michael@0 1189 * RECURRENCE-ID 0 or 1 only if referring to an instance of a
michael@0 1190 * recurring calendar component. Otherwise it
michael@0 1191 * MUST NOT be present.
michael@0 1192 * RELATED-TO 0+
michael@0 1193 * REQUEST-STATUS 0+
michael@0 1194 * RESOURCES 0 or 1 This property MAY contain a list of values
michael@0 1195 * RRULE 0+
michael@0 1196 * STATUS 0 or 1 MAY be one of TENTATIVE/CONFIRMED
michael@0 1197 * TRANSP 0 or 1
michael@0 1198 * URL 0 or 1
michael@0 1199 * X-PROPERTY 0+
michael@0 1200 *
michael@0 1201 * VALARM 0+
michael@0 1202 * VTIMEZONE 0+ MUST be present if any date/time refers to
michael@0 1203 * a timezone
michael@0 1204 * X-COMPONENT 0+
michael@0 1205 * VFREEBUSY 0
michael@0 1206 * VJOURNAL 0
michael@0 1207 * VTODO 0
michael@0 1208 * </pre>
michael@0 1209 *
michael@0 1210 */
michael@0 1211 private class RequestValidator implements Validator {
michael@0 1212
michael@0 1213 private static final long serialVersionUID = 1L;
michael@0 1214
michael@0 1215 public void validate() throws ValidationException {
michael@0 1216 if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) {
michael@0 1217 PropertyValidator.getInstance().assertOneOrMore(Property.ATTENDEE, getProperties());
michael@0 1218 }
michael@0 1219
michael@0 1220 PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
michael@0 1221 PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties());
michael@0 1222 PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
michael@0 1223 PropertyValidator.getInstance().assertOne(Property.SUMMARY, getProperties());
michael@0 1224 PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
michael@0 1225
michael@0 1226 PropertyValidator.getInstance().assertOneOrLess(Property.SEQUENCE, getProperties());
michael@0 1227 PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties());
michael@0 1228 PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties());
michael@0 1229 PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties());
michael@0 1230 PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties());
michael@0 1231 PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties());
michael@0 1232 PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties());
michael@0 1233 PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties());
michael@0 1234 PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties());
michael@0 1235 PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties());
michael@0 1236 PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties());
michael@0 1237 PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties());
michael@0 1238 PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties());
michael@0 1239 PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties());
michael@0 1240 PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties());
michael@0 1241 PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties());
michael@0 1242
michael@0 1243 for (final Iterator i = getAlarms().iterator(); i.hasNext();) {
michael@0 1244 final VAlarm alarm = (VAlarm) i.next();
michael@0 1245 alarm.validate(Method.REQUEST);
michael@0 1246 }
michael@0 1247 }
michael@0 1248 }
michael@0 1249 /**
michael@0 1250 * Returns a normalised list of periods representing the consumed time for this event.
michael@0 1251 * @param rangeStart the start of a range
michael@0 1252 * @param rangeEnd the end of a range
michael@0 1253 * @return a normalised list of periods representing consumed time for this event
michael@0 1254 * @see VEvent#getConsumedTime(Date, Date, boolean)
michael@0 1255 */
michael@0 1256 public final PeriodList getConsumedTime(final Date rangeStart,
michael@0 1257 final Date rangeEnd) {
michael@0 1258 return getConsumedTime(rangeStart, rangeEnd, true);
michael@0 1259 }
michael@0 1260
michael@0 1261 /**
michael@0 1262 * Returns a list of periods representing the consumed time for this event in the specified range. Note that the
michael@0 1263 * returned list may contain a single period for non-recurring components or multiple periods for recurring
michael@0 1264 * components. If no time is consumed by this event an empty list is returned.
michael@0 1265 * @param rangeStart the start of the range to check for consumed time
michael@0 1266 * @param rangeEnd the end of the range to check for consumed time
michael@0 1267 * @param normalise indicate whether the returned list of periods should be normalised
michael@0 1268 * @return a list of periods representing consumed time for this event
michael@0 1269 */
michael@0 1270 public final PeriodList getConsumedTime(final Date rangeStart,
michael@0 1271 final Date rangeEnd, final boolean normalise) {
michael@0 1272 PeriodList periods = new PeriodList();
michael@0 1273 // if component is transparent return empty list..
michael@0 1274 if (!Transp.TRANSPARENT.equals(getProperty(Property.TRANSP))) {
michael@0 1275
michael@0 1276 // try {
michael@0 1277 periods = calculateRecurrenceSet(new Period(new DateTime(rangeStart),
michael@0 1278 new DateTime(rangeEnd)));
michael@0 1279 // }
michael@0 1280 // catch (ValidationException ve) {
michael@0 1281 // log.error("Invalid event data", ve);
michael@0 1282 // return periods;
michael@0 1283 // }
michael@0 1284
michael@0 1285 // if periods already specified through recurrence, return..
michael@0 1286 // ..also normalise before returning.
michael@0 1287 if (!periods.isEmpty() && normalise) {
michael@0 1288 periods = periods.normalise();
michael@0 1289 }
michael@0 1290 }
michael@0 1291
michael@0 1292 return periods;
michael@0 1293 }
michael@0 1294
michael@0 1295 /**
michael@0 1296 * Returns a single occurrence of a recurring event.
michael@0 1297 * @param date a date on which the occurence should occur
michael@0 1298 * @return a single non-recurring event instance for the specified date, or null if the event doesn't
michael@0 1299 * occur on the specified date
michael@0 1300 * @throws IOException where an error occurs reading data
michael@0 1301 * @throws URISyntaxException where an invalid URI is encountered
michael@0 1302 * @throws ParseException where an error occurs parsing data
michael@0 1303 */
michael@0 1304 public final VEvent getOccurrence(final Date date) throws IOException,
michael@0 1305 URISyntaxException, ParseException {
michael@0 1306
michael@0 1307 final PeriodList consumedTime = getConsumedTime(date, date);
michael@0 1308 for (final Iterator i = consumedTime.iterator(); i.hasNext();) {
michael@0 1309 final Period p = (Period) i.next();
michael@0 1310 if (p.getStart().equals(date)) {
michael@0 1311 final VEvent occurrence = (VEvent) this.copy();
michael@0 1312 occurrence.getProperties().add(new RecurrenceId(date));
michael@0 1313 return occurrence;
michael@0 1314 }
michael@0 1315 }
michael@0 1316 return null;
michael@0 1317 }
michael@0 1318
michael@0 1319 /**
michael@0 1320 * @return the optional access classification property for an event
michael@0 1321 */
michael@0 1322 public final Clazz getClassification() {
michael@0 1323 return (Clazz) getProperty(Property.CLASS);
michael@0 1324 }
michael@0 1325
michael@0 1326 /**
michael@0 1327 * @return the optional creation-time property for an event
michael@0 1328 */
michael@0 1329 public final Created getCreated() {
michael@0 1330 return (Created) getProperty(Property.CREATED);
michael@0 1331 }
michael@0 1332
michael@0 1333 /**
michael@0 1334 * @return the optional description property for an event
michael@0 1335 */
michael@0 1336 public final Description getDescription() {
michael@0 1337 return (Description) getProperty(Property.DESCRIPTION);
michael@0 1338 }
michael@0 1339
michael@0 1340 /**
michael@0 1341 * Convenience method to pull the DTSTART out of the property list.
michael@0 1342 * @return The DtStart object representation of the start Date
michael@0 1343 */
michael@0 1344 public final DtStart getStartDate() {
michael@0 1345 return (DtStart) getProperty(Property.DTSTART);
michael@0 1346 }
michael@0 1347
michael@0 1348 /**
michael@0 1349 * @return the optional geographic position property for an event
michael@0 1350 */
michael@0 1351 public final Geo getGeographicPos() {
michael@0 1352 return (Geo) getProperty(Property.GEO);
michael@0 1353 }
michael@0 1354
michael@0 1355 /**
michael@0 1356 * @return the optional last-modified property for an event
michael@0 1357 */
michael@0 1358 public final LastModified getLastModified() {
michael@0 1359 return (LastModified) getProperty(Property.LAST_MODIFIED);
michael@0 1360 }
michael@0 1361
michael@0 1362 /**
michael@0 1363 * @return the optional location property for an event
michael@0 1364 */
michael@0 1365 public final Location getLocation() {
michael@0 1366 return (Location) getProperty(Property.LOCATION);
michael@0 1367 }
michael@0 1368
michael@0 1369 /**
michael@0 1370 * @return the optional organizer property for an event
michael@0 1371 */
michael@0 1372 public final Organizer getOrganizer() {
michael@0 1373 return (Organizer) getProperty(Property.ORGANIZER);
michael@0 1374 }
michael@0 1375
michael@0 1376 /**
michael@0 1377 * @return the optional priority property for an event
michael@0 1378 */
michael@0 1379 public final Priority getPriority() {
michael@0 1380 return (Priority) getProperty(Property.PRIORITY);
michael@0 1381 }
michael@0 1382
michael@0 1383 /**
michael@0 1384 * @return the optional date-stamp property
michael@0 1385 */
michael@0 1386 public final DtStamp getDateStamp() {
michael@0 1387 return (DtStamp) getProperty(Property.DTSTAMP);
michael@0 1388 }
michael@0 1389
michael@0 1390 /**
michael@0 1391 * @return the optional sequence number property for an event
michael@0 1392 */
michael@0 1393 public final Sequence getSequence() {
michael@0 1394 return (Sequence) getProperty(Property.SEQUENCE);
michael@0 1395 }
michael@0 1396
michael@0 1397 /**
michael@0 1398 * @return the optional status property for an event
michael@0 1399 */
michael@0 1400 public final Status getStatus() {
michael@0 1401 return (Status) getProperty(Property.STATUS);
michael@0 1402 }
michael@0 1403
michael@0 1404 /**
michael@0 1405 * @return the optional summary property for an event
michael@0 1406 */
michael@0 1407 public final Summary getSummary() {
michael@0 1408 return (Summary) getProperty(Property.SUMMARY);
michael@0 1409 }
michael@0 1410
michael@0 1411 /**
michael@0 1412 * @return the optional time transparency property for an event
michael@0 1413 */
michael@0 1414 public final Transp getTransparency() {
michael@0 1415 return (Transp) getProperty(Property.TRANSP);
michael@0 1416 }
michael@0 1417
michael@0 1418 /**
michael@0 1419 * @return the optional URL property for an event
michael@0 1420 */
michael@0 1421 public final Url getUrl() {
michael@0 1422 return (Url) getProperty(Property.URL);
michael@0 1423 }
michael@0 1424
michael@0 1425 /**
michael@0 1426 * @return the optional recurrence identifier property for an event
michael@0 1427 */
michael@0 1428 public final RecurrenceId getRecurrenceId() {
michael@0 1429 return (RecurrenceId) getProperty(Property.RECURRENCE_ID);
michael@0 1430 }
michael@0 1431
michael@0 1432 /**
michael@0 1433 * Returns the end date of this event. Where an end date is not available it will be derived from the event
michael@0 1434 * duration.
michael@0 1435 * @return a DtEnd instance, or null if one cannot be derived
michael@0 1436 */
michael@0 1437 public final DtEnd getEndDate() {
michael@0 1438 return getEndDate(true);
michael@0 1439 }
michael@0 1440
michael@0 1441 /**
michael@0 1442 * Convenience method to pull the DTEND out of the property list. If DTEND was not specified, use the DTSTART +
michael@0 1443 * DURATION to calculate it.
michael@0 1444 * @param deriveFromDuration specifies whether to derive an end date from the event duration where an end date is
michael@0 1445 * not found
michael@0 1446 * @return The end for this VEVENT.
michael@0 1447 */
michael@0 1448 public final DtEnd getEndDate(final boolean deriveFromDuration) {
michael@0 1449 DtEnd dtEnd = (DtEnd) getProperty(Property.DTEND);
michael@0 1450 // No DTEND? No problem, we'll use the DURATION.
michael@3 1451 if (dtEnd == null && deriveFromDuration && getStartDate() != null) {
michael@0 1452 final DtStart dtStart = getStartDate();
michael@3 1453 final Duration vEventDuration;
michael@3 1454 if (getDuration() != null) {
michael@3 1455 vEventDuration = getDuration();
michael@3 1456 } else if (dtStart.getDate() instanceof DateTime) {
michael@3 1457 // If "DTSTART" is a DATE-TIME, then the event's duration is zero (see: RFC 5545, 3.6.1 Event Component)
michael@3 1458 vEventDuration = new Duration(new Dur(0, 0, 0, 0));
michael@3 1459 } else {
michael@3 1460 // If "DTSTART" is a DATE, then the event's duration is one day (see: RFC 5545, 3.6.1 Event Component)
michael@3 1461 vEventDuration = new Duration(new Dur(1, 0, 0, 0));
michael@3 1462 }
michael@3 1463
michael@0 1464 dtEnd = new DtEnd(Dates.getInstance(vEventDuration.getDuration()
michael@0 1465 .getTime(dtStart.getDate()), (Value) dtStart
michael@0 1466 .getParameter(Parameter.VALUE)));
michael@0 1467 if (dtStart.isUtc()) {
michael@0 1468 dtEnd.setUtc(true);
michael@0 1469 }
michael@0 1470 }
michael@0 1471 return dtEnd;
michael@0 1472 }
michael@0 1473
michael@0 1474 /**
michael@0 1475 * @return the optional Duration property
michael@0 1476 */
michael@0 1477 public final Duration getDuration() {
michael@0 1478 return (Duration) getProperty(Property.DURATION);
michael@0 1479 }
michael@0 1480
michael@0 1481 /**
michael@0 1482 * Returns the UID property of this component if available.
michael@0 1483 * @return a Uid instance, or null if no UID property exists
michael@0 1484 */
michael@0 1485 public final Uid getUid() {
michael@0 1486 return (Uid) getProperty(Property.UID);
michael@0 1487 }
michael@0 1488
michael@0 1489 /**
michael@0 1490 * {@inheritDoc}
michael@0 1491 */
michael@0 1492 public boolean equals(final Object arg0) {
michael@0 1493 if (arg0 instanceof VEvent) {
michael@0 1494 return super.equals(arg0)
michael@0 1495 && ObjectUtils.equals(alarms, ((VEvent) arg0).getAlarms());
michael@0 1496 }
michael@0 1497 return super.equals(arg0);
michael@0 1498 }
michael@0 1499
michael@0 1500 /**
michael@0 1501 * {@inheritDoc}
michael@0 1502 */
michael@0 1503 public int hashCode() {
michael@0 1504 return new HashCodeBuilder().append(getName()).append(getProperties())
michael@0 1505 .append(getAlarms()).toHashCode();
michael@0 1506 }
michael@0 1507
michael@0 1508 /**
michael@0 1509 * Overrides default copy method to add support for copying alarm sub-components.
michael@0 1510 * @return a copy of the instance
michael@0 1511 * @throws ParseException where values in the instance cannot be parsed
michael@0 1512 * @throws IOException where values in the instance cannot be read
michael@0 1513 * @throws URISyntaxException where an invalid URI value is encountered in the instance
michael@0 1514 * @see net.fortuna.ical4j.model.Component#copy()
michael@0 1515 */
michael@0 1516 public Component copy() throws ParseException, IOException,
michael@0 1517 URISyntaxException {
michael@0 1518 final VEvent copy = (VEvent) super.copy();
michael@0 1519 copy.alarms = new ComponentList(alarms);
michael@0 1520 return copy;
michael@0 1521 }
michael@0 1522 }

mercurial