1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/net/fortuna/ical4j/model/component/VEvent.java Tue Feb 10 18:12:00 2015 +0100 1.3 @@ -0,0 +1,1520 @@ 1.4 +/** 1.5 + * Copyright (c) 2012, Ben Fortuna 1.6 + * All rights reserved. 1.7 + * 1.8 + * Redistribution and use in source and binary forms, with or without 1.9 + * modification, are permitted provided that the following conditions 1.10 + * are met: 1.11 + * 1.12 + * o Redistributions of source code must retain the above copyright 1.13 + * notice, this list of conditions and the following disclaimer. 1.14 + * 1.15 + * o Redistributions in binary form must reproduce the above copyright 1.16 + * notice, this list of conditions and the following disclaimer in the 1.17 + * documentation and/or other materials provided with the distribution. 1.18 + * 1.19 + * o Neither the name of Ben Fortuna nor the names of any other contributors 1.20 + * may be used to endorse or promote products derived from this software 1.21 + * without specific prior written permission. 1.22 + * 1.23 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.24 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.25 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.26 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 1.27 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 1.28 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 1.29 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 1.30 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 1.31 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 1.32 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 1.33 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.34 + */ 1.35 +package net.fortuna.ical4j.model.component; 1.36 + 1.37 +import java.io.IOException; 1.38 +import java.net.URISyntaxException; 1.39 +import java.text.ParseException; 1.40 +import java.util.HashMap; 1.41 +import java.util.Iterator; 1.42 +import java.util.Map; 1.43 + 1.44 +import net.fortuna.ical4j.model.Component; 1.45 +import net.fortuna.ical4j.model.ComponentList; 1.46 +import net.fortuna.ical4j.model.Date; 1.47 +import net.fortuna.ical4j.model.DateTime; 1.48 +import net.fortuna.ical4j.model.Dur; 1.49 +import net.fortuna.ical4j.model.Parameter; 1.50 +import net.fortuna.ical4j.model.Period; 1.51 +import net.fortuna.ical4j.model.PeriodList; 1.52 +import net.fortuna.ical4j.model.Property; 1.53 +import net.fortuna.ical4j.model.PropertyList; 1.54 +import net.fortuna.ical4j.model.ValidationException; 1.55 +import net.fortuna.ical4j.model.Validator; 1.56 +import net.fortuna.ical4j.model.parameter.Value; 1.57 +import net.fortuna.ical4j.model.property.Clazz; 1.58 +import net.fortuna.ical4j.model.property.Created; 1.59 +import net.fortuna.ical4j.model.property.Description; 1.60 +import net.fortuna.ical4j.model.property.DtEnd; 1.61 +import net.fortuna.ical4j.model.property.DtStamp; 1.62 +import net.fortuna.ical4j.model.property.DtStart; 1.63 +import net.fortuna.ical4j.model.property.Duration; 1.64 +import net.fortuna.ical4j.model.property.Geo; 1.65 +import net.fortuna.ical4j.model.property.LastModified; 1.66 +import net.fortuna.ical4j.model.property.Location; 1.67 +import net.fortuna.ical4j.model.property.Method; 1.68 +import net.fortuna.ical4j.model.property.Organizer; 1.69 +import net.fortuna.ical4j.model.property.Priority; 1.70 +import net.fortuna.ical4j.model.property.RecurrenceId; 1.71 +import net.fortuna.ical4j.model.property.Sequence; 1.72 +import net.fortuna.ical4j.model.property.Status; 1.73 +import net.fortuna.ical4j.model.property.Summary; 1.74 +import net.fortuna.ical4j.model.property.Transp; 1.75 +import net.fortuna.ical4j.model.property.Uid; 1.76 +import net.fortuna.ical4j.model.property.Url; 1.77 +import net.fortuna.ical4j.util.CompatibilityHints; 1.78 +import net.fortuna.ical4j.util.ComponentValidator; 1.79 +import net.fortuna.ical4j.util.Dates; 1.80 +import net.fortuna.ical4j.util.PropertyValidator; 1.81 +import net.fortuna.ical4j.util.Strings; 1.82 + 1.83 +import org.apache.commons.lang.ObjectUtils; 1.84 +import org.apache.commons.lang.builder.HashCodeBuilder; 1.85 + 1.86 +/** 1.87 + * $Id$ [Apr 5, 2004] 1.88 + * 1.89 + * Defines an iCalendar VEVENT component. 1.90 + * 1.91 + * <pre> 1.92 + * 4.6.1 Event Component 1.93 + * 1.94 + * Component Name: "VEVENT" 1.95 + * 1.96 + * Purpose: Provide a grouping of component properties that describe an 1.97 + * event. 1.98 + * 1.99 + * Format Definition: A "VEVENT" calendar component is defined by the 1.100 + * following notation: 1.101 + * 1.102 + * eventc = "BEGIN" ":" "VEVENT" CRLF 1.103 + * eventprop *alarmc 1.104 + * "END" ":" "VEVENT" CRLF 1.105 + * 1.106 + * eventprop = *( 1.107 + * 1.108 + * ; the following are optional, 1.109 + * ; but MUST NOT occur more than once 1.110 + * 1.111 + * class / created / description / dtstart / geo / 1.112 + * last-mod / location / organizer / priority / 1.113 + * dtstamp / seq / status / summary / transp / 1.114 + * uid / url / recurid / 1.115 + * 1.116 + * ; either 'dtend' or 'duration' may appear in 1.117 + * ; a 'eventprop', but 'dtend' and 'duration' 1.118 + * ; MUST NOT occur in the same 'eventprop' 1.119 + * 1.120 + * dtend / duration / 1.121 + * 1.122 + * ; the following are optional, 1.123 + * ; and MAY occur more than once 1.124 + * 1.125 + * attach / attendee / categories / comment / 1.126 + * contact / exdate / exrule / rstatus / related / 1.127 + * resources / rdate / rrule / x-prop 1.128 + * 1.129 + * ) 1.130 + * </pre> 1.131 + * 1.132 + * Example 1 - Creating a new all-day event: 1.133 + * 1.134 + * <pre><code> 1.135 + * java.util.Calendar cal = java.util.Calendar.getInstance(); 1.136 + * cal.set(java.util.Calendar.MONTH, java.util.Calendar.DECEMBER); 1.137 + * cal.set(java.util.Calendar.DAY_OF_MONTH, 25); 1.138 + * 1.139 + * VEvent christmas = new VEvent(cal.getTime(), "Christmas Day"); 1.140 + * 1.141 + * // initialise as an all-day event.. 1.142 + * christmas.getProperties().getProperty(Property.DTSTART).getParameters().add( 1.143 + * Value.DATE); 1.144 + * 1.145 + * // add timezone information.. 1.146 + * VTimeZone tz = VTimeZone.getDefault(); 1.147 + * TzId tzParam = new TzId(tz.getProperties().getProperty(Property.TZID) 1.148 + * .getValue()); 1.149 + * christmas.getProperties().getProperty(Property.DTSTART).getParameters().add( 1.150 + * tzParam); 1.151 + * </code></pre> 1.152 + * 1.153 + * Example 2 - Creating an event of one (1) hour duration: 1.154 + * 1.155 + * <pre><code> 1.156 + * java.util.Calendar cal = java.util.Calendar.getInstance(); 1.157 + * // tomorrow.. 1.158 + * cal.add(java.util.Calendar.DAY_OF_MONTH, 1); 1.159 + * cal.set(java.util.Calendar.HOUR_OF_DAY, 9); 1.160 + * cal.set(java.util.Calendar.MINUTE, 30); 1.161 + * 1.162 + * VEvent meeting = new VEvent(cal.getTime(), 1000 * 60 * 60, "Progress Meeting"); 1.163 + * 1.164 + * // add timezone information.. 1.165 + * VTimeZone tz = VTimeZone.getDefault(); 1.166 + * TzId tzParam = new TzId(tz.getProperties().getProperty(Property.TZID) 1.167 + * .getValue()); 1.168 + * meeting.getProperties().getProperty(Property.DTSTART).getParameters().add( 1.169 + * tzParam); 1.170 + * </code></pre> 1.171 + * 1.172 + * Example 3 - Retrieve a list of periods representing a recurring event in a specified range: 1.173 + * 1.174 + * <pre><code> 1.175 + * Calendar weekday9AM = Calendar.getInstance(); 1.176 + * weekday9AM.set(2005, Calendar.MARCH, 7, 9, 0, 0); 1.177 + * weekday9AM.set(Calendar.MILLISECOND, 0); 1.178 + * 1.179 + * Calendar weekday5PM = Calendar.getInstance(); 1.180 + * weekday5PM.set(2005, Calendar.MARCH, 7, 17, 0, 0); 1.181 + * weekday5PM.set(Calendar.MILLISECOND, 0); 1.182 + * 1.183 + * // Do the recurrence until December 31st. 1.184 + * Calendar untilCal = Calendar.getInstance(); 1.185 + * untilCal.set(2005, Calendar.DECEMBER, 31); 1.186 + * untilCal.set(Calendar.MILLISECOND, 0); 1.187 + * 1.188 + * // 9:00AM to 5:00PM Rule 1.189 + * Recur recur = new Recur(Recur.WEEKLY, untilCal.getTime()); 1.190 + * recur.getDayList().add(WeekDay.MO); 1.191 + * recur.getDayList().add(WeekDay.TU); 1.192 + * recur.getDayList().add(WeekDay.WE); 1.193 + * recur.getDayList().add(WeekDay.TH); 1.194 + * recur.getDayList().add(WeekDay.FR); 1.195 + * recur.setInterval(3); 1.196 + * recur.setWeekStartDay(WeekDay.MO.getDay()); 1.197 + * RRule rrule = new RRule(recur); 1.198 + * 1.199 + * Summary summary = new Summary("TEST EVENTS THAT HAPPEN 9-5 MON-FRI"); 1.200 + * 1.201 + * weekdayNineToFiveEvents = new VEvent(); 1.202 + * weekdayNineToFiveEvents.getProperties().add(rrule); 1.203 + * weekdayNineToFiveEvents.getProperties().add(summary); 1.204 + * weekdayNineToFiveEvents.getProperties().add(new DtStart(weekday9AM.getTime())); 1.205 + * weekdayNineToFiveEvents.getProperties().add(new DtEnd(weekday5PM.getTime())); 1.206 + * 1.207 + * // Test Start 04/01/2005, End One month later. 1.208 + * // Query Calendar Start and End Dates. 1.209 + * Calendar queryStartDate = Calendar.getInstance(); 1.210 + * queryStartDate.set(2005, Calendar.APRIL, 1, 14, 47, 0); 1.211 + * queryStartDate.set(Calendar.MILLISECOND, 0); 1.212 + * Calendar queryEndDate = Calendar.getInstance(); 1.213 + * queryEndDate.set(2005, Calendar.MAY, 1, 11, 15, 0); 1.214 + * queryEndDate.set(Calendar.MILLISECOND, 0); 1.215 + * 1.216 + * // This range is monday to friday every three weeks, starting from 1.217 + * // March 7th 2005, which means for our query dates we need 1.218 + * // April 18th through to the 22nd. 1.219 + * PeriodList periods = weekdayNineToFiveEvents.getPeriods(queryStartDate 1.220 + * .getTime(), queryEndDate.getTime()); 1.221 + * </code></pre> 1.222 + * 1.223 + * @author Ben Fortuna 1.224 + */ 1.225 +public class VEvent extends CalendarComponent { 1.226 + 1.227 + private static final long serialVersionUID = 2547948989200697335L; 1.228 + 1.229 + private final Map methodValidators = new HashMap(); 1.230 + { 1.231 + methodValidators.put(Method.ADD, new AddValidator()); 1.232 + methodValidators.put(Method.CANCEL, new CancelValidator()); 1.233 + methodValidators.put(Method.COUNTER, new CounterValidator()); 1.234 + methodValidators.put(Method.DECLINE_COUNTER, new DeclineCounterValidator()); 1.235 + methodValidators.put(Method.PUBLISH, new PublishValidator()); 1.236 + methodValidators.put(Method.REFRESH, new RefreshValidator()); 1.237 + methodValidators.put(Method.REPLY, new ReplyValidator()); 1.238 + methodValidators.put(Method.REQUEST, new RequestValidator()); 1.239 + } 1.240 + 1.241 + private ComponentList alarms; 1.242 + 1.243 + /** 1.244 + * Default constructor. 1.245 + */ 1.246 + public VEvent() { 1.247 + super(VEVENT); 1.248 + this.alarms = new ComponentList(); 1.249 + getProperties().add(new DtStamp()); 1.250 + } 1.251 + 1.252 + /** 1.253 + * Constructor. 1.254 + * @param properties a list of properties 1.255 + */ 1.256 + public VEvent(final PropertyList properties) { 1.257 + super(VEVENT, properties); 1.258 + this.alarms = new ComponentList(); 1.259 + } 1.260 + 1.261 + /** 1.262 + * Constructor. 1.263 + * @param properties a list of properties 1.264 + * @param alarms a list of alarms 1.265 + */ 1.266 + public VEvent(final PropertyList properties, final ComponentList alarms) { 1.267 + super(VEVENT, properties); 1.268 + this.alarms = alarms; 1.269 + } 1.270 + 1.271 + /** 1.272 + * Constructs a new VEVENT instance starting at the specified time with the specified summary. 1.273 + * @param start the start date of the new event 1.274 + * @param summary the event summary 1.275 + */ 1.276 + public VEvent(final Date start, final String summary) { 1.277 + this(); 1.278 + getProperties().add(new DtStart(start)); 1.279 + getProperties().add(new Summary(summary)); 1.280 + } 1.281 + 1.282 + /** 1.283 + * Constructs a new VEVENT instance starting and ending at the specified times with the specified summary. 1.284 + * @param start the start date of the new event 1.285 + * @param end the end date of the new event 1.286 + * @param summary the event summary 1.287 + */ 1.288 + public VEvent(final Date start, final Date end, final String summary) { 1.289 + this(); 1.290 + getProperties().add(new DtStart(start)); 1.291 + getProperties().add(new DtEnd(end)); 1.292 + getProperties().add(new Summary(summary)); 1.293 + } 1.294 + 1.295 + /** 1.296 + * Constructs a new VEVENT instance starting at the specified times, for the specified duration, with the specified 1.297 + * summary. 1.298 + * @param start the start date of the new event 1.299 + * @param duration the duration of the new event 1.300 + * @param summary the event summary 1.301 + */ 1.302 + public VEvent(final Date start, final Dur duration, final String summary) { 1.303 + this(); 1.304 + getProperties().add(new DtStart(start)); 1.305 + getProperties().add(new Duration(duration)); 1.306 + getProperties().add(new Summary(summary)); 1.307 + } 1.308 + 1.309 + /** 1.310 + * Returns the list of alarms for this event. 1.311 + * @return a component list 1.312 + */ 1.313 + public final ComponentList getAlarms() { 1.314 + return alarms; 1.315 + } 1.316 + 1.317 + /** 1.318 + * {@inheritDoc} 1.319 + */ 1.320 + public final String toString() { 1.321 + final StringBuffer b = new StringBuffer(); 1.322 + b.append(BEGIN); 1.323 + b.append(':'); 1.324 + b.append(getName()); 1.325 + b.append(Strings.LINE_SEPARATOR); 1.326 + b.append(getProperties()); 1.327 + b.append(getAlarms()); 1.328 + b.append(END); 1.329 + b.append(':'); 1.330 + b.append(getName()); 1.331 + b.append(Strings.LINE_SEPARATOR); 1.332 + return b.toString(); 1.333 + } 1.334 + 1.335 + /** 1.336 + * {@inheritDoc} 1.337 + */ 1.338 + public final void validate(final boolean recurse) throws ValidationException { 1.339 + 1.340 + // validate that getAlarms() only contains VAlarm components 1.341 + final Iterator iterator = getAlarms().iterator(); 1.342 + while (iterator.hasNext()) { 1.343 + final Component component = (Component) iterator.next(); 1.344 + 1.345 + if (!(component instanceof VAlarm)) { 1.346 + throw new ValidationException("Component [" 1.347 + + component.getName() + "] may not occur in VEVENT"); 1.348 + } 1.349 + 1.350 + ((VAlarm) component).validate(recurse); 1.351 + } 1.352 + 1.353 + if (!CompatibilityHints 1.354 + .isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) { 1.355 + 1.356 + // From "4.8.4.7 Unique Identifier": 1.357 + // Conformance: The property MUST be specified in the "VEVENT", "VTODO", 1.358 + // "VJOURNAL" or "VFREEBUSY" calendar components. 1.359 + PropertyValidator.getInstance().assertOne(Property.UID, 1.360 + getProperties()); 1.361 + 1.362 + // From "4.8.7.2 Date/Time Stamp": 1.363 + // Conformance: This property MUST be included in the "VEVENT", "VTODO", 1.364 + // "VJOURNAL" or "VFREEBUSY" calendar components. 1.365 + PropertyValidator.getInstance().assertOne(Property.DTSTAMP, 1.366 + getProperties()); 1.367 + } 1.368 + 1.369 + /* 1.370 + * ; the following are optional, ; but MUST NOT occur more than once class / created / description / dtstart / 1.371 + * geo / last-mod / location / organizer / priority / dtstamp / seq / status / summary / transp / uid / url / 1.372 + * recurid / 1.373 + */ 1.374 + PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, 1.375 + getProperties()); 1.376 + PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, 1.377 + getProperties()); 1.378 + PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, 1.379 + getProperties()); 1.380 + PropertyValidator.getInstance().assertOneOrLess(Property.DTSTART, 1.381 + getProperties()); 1.382 + PropertyValidator.getInstance().assertOneOrLess(Property.GEO, 1.383 + getProperties()); 1.384 + PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, 1.385 + getProperties()); 1.386 + PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, 1.387 + getProperties()); 1.388 + PropertyValidator.getInstance().assertOneOrLess(Property.ORGANIZER, 1.389 + getProperties()); 1.390 + PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, 1.391 + getProperties()); 1.392 + PropertyValidator.getInstance().assertOneOrLess(Property.DTSTAMP, 1.393 + getProperties()); 1.394 + PropertyValidator.getInstance().assertOneOrLess(Property.SEQUENCE, 1.395 + getProperties()); 1.396 + PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, 1.397 + getProperties()); 1.398 + PropertyValidator.getInstance().assertOneOrLess(Property.SUMMARY, 1.399 + getProperties()); 1.400 + PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, 1.401 + getProperties()); 1.402 + PropertyValidator.getInstance().assertOneOrLess(Property.UID, 1.403 + getProperties()); 1.404 + PropertyValidator.getInstance().assertOneOrLess(Property.URL, 1.405 + getProperties()); 1.406 + PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, 1.407 + getProperties()); 1.408 + 1.409 + final Status status = (Status) getProperty(Property.STATUS); 1.410 + if (status != null && !Status.VEVENT_TENTATIVE.getValue().equals(status.getValue()) 1.411 + && !Status.VEVENT_CONFIRMED.getValue().equals(status.getValue()) 1.412 + && !Status.VEVENT_CANCELLED.getValue().equals(status.getValue())) { 1.413 + throw new ValidationException("Status property [" 1.414 + + status.toString() + "] is not applicable for VEVENT"); 1.415 + } 1.416 + 1.417 + /* 1.418 + * ; either 'dtend' or 'duration' may appear in ; a 'eventprop', but 'dtend' and 'duration' ; MUST NOT occur in 1.419 + * the same 'eventprop' dtend / duration / 1.420 + */ 1.421 + try { 1.422 + PropertyValidator.getInstance().assertNone(Property.DTEND, 1.423 + getProperties()); 1.424 + } 1.425 + catch (ValidationException ve) { 1.426 + PropertyValidator.getInstance().assertNone(Property.DURATION, 1.427 + getProperties()); 1.428 + } 1.429 + 1.430 + if (getProperty(Property.DTEND) != null) { 1.431 + 1.432 + /* 1.433 + * The "VEVENT" is also the calendar component used to specify an anniversary or daily reminder within a 1.434 + * calendar. These events have a DATE value type for the "DTSTART" property instead of the default data type 1.435 + * of DATE-TIME. If such a "VEVENT" has a "DTEND" property, it MUST be specified as a DATE value also. The 1.436 + * anniversary type of "VEVENT" can span more than one date (i.e, "DTEND" property value is set to a 1.437 + * calendar date after the "DTSTART" property value). 1.438 + */ 1.439 + final DtStart start = (DtStart) getProperty(Property.DTSTART); 1.440 + final DtEnd end = (DtEnd) getProperty(Property.DTEND); 1.441 + 1.442 + if (start != null) { 1.443 + final Parameter startValue = start.getParameter(Parameter.VALUE); 1.444 + final Parameter endValue = end.getParameter(Parameter.VALUE); 1.445 + 1.446 + boolean startEndValueMismatch = false; 1.447 + if (endValue != null) { 1.448 + if (startValue != null && !endValue.equals(startValue)) { 1.449 + // invalid.. 1.450 + startEndValueMismatch = true; 1.451 + } 1.452 + else if (startValue == null && !Value.DATE_TIME.equals(endValue)) { 1.453 + // invalid.. 1.454 + startEndValueMismatch = true; 1.455 + } 1.456 + } 1.457 + else if (startValue != null && !Value.DATE_TIME.equals(startValue)) { 1.458 + //invalid.. 1.459 + startEndValueMismatch = true; 1.460 + } 1.461 + if (startEndValueMismatch) { 1.462 + throw new ValidationException("Property [" + Property.DTEND 1.463 + + "] must have the same [" + Parameter.VALUE 1.464 + + "] as [" + Property.DTSTART + "]"); 1.465 + } 1.466 + } 1.467 + } 1.468 + 1.469 + /* 1.470 + * ; the following are optional, ; and MAY occur more than once attach / attendee / categories / comment / 1.471 + * contact / exdate / exrule / rstatus / related / resources / rdate / rrule / x-prop 1.472 + */ 1.473 + 1.474 + if (recurse) { 1.475 + validateProperties(); 1.476 + } 1.477 + } 1.478 + 1.479 + /** 1.480 + * {@inheritDoc} 1.481 + */ 1.482 + protected Validator getValidator(Method method) { 1.483 + return (Validator) methodValidators.get(method); 1.484 + } 1.485 + 1.486 + /** 1.487 + * METHOD:ADD Validator. 1.488 + * 1.489 + * <pre> 1.490 + * Component/Property Presence 1.491 + * ------------------- ---------------------------------------------- 1.492 + * METHOD 1 MUST be "ADD" 1.493 + * VEVENT 1 1.494 + * DTSTAMP 1 1.495 + * DTSTART 1 1.496 + * ORGANIZER 1 1.497 + * SEQUENCE 1 MUST be greater than 0 1.498 + * SUMMARY 1 Can be null 1.499 + * UID 1 MUST match that of the original event 1.500 + * 1.501 + * ATTACH 0+ 1.502 + * ATTENDEE 0+ 1.503 + * CATEGORIES 0 or 1 This property MAY contain a list of values 1.504 + * CLASS 0 or 1 1.505 + * COMMENT 0 or 1 1.506 + * CONTACT 0+ 1.507 + * CREATED 0 or 1 1.508 + * DESCRIPTION 0 or 1 Can be null 1.509 + * DTEND 0 or 1 if present DURATION MUST NOT be present 1.510 + * DURATION 0 or 1 if present DTEND MUST NOT be present 1.511 + * EXDATE 0+ 1.512 + * EXRULE 0+ 1.513 + * GEO 0 or 1 1.514 + * LAST-MODIFIED 0 or 1 1.515 + * LOCATION 0 or 1 1.516 + * PRIORITY 0 or 1 1.517 + * RDATE 0+ 1.518 + * RELATED-TO 0+ 1.519 + * RESOURCES 0 or 1 This property MAY contain a list of values 1.520 + * RRULE 0+ 1.521 + * STATUS 0 or 1 MAY be one of TENTATIVE/CONFIRMED 1.522 + * TRANSP 0 or 1 1.523 + * URL 0 or 1 1.524 + * X-PROPERTY 0+ 1.525 + * 1.526 + * RECURRENCE-ID 0 1.527 + * REQUEST-STATUS 0 1.528 + * 1.529 + * VALARM 0+ 1.530 + * VTIMEZONE 0+ MUST be present if any date/time refers to 1.531 + * a timezone 1.532 + * X-COMPONENT 0+ 1.533 + * 1.534 + * VFREEBUSY 0 1.535 + * VTODO 0 1.536 + * VJOURNAL 0 1.537 + * </pre> 1.538 + * 1.539 + */ 1.540 + private class AddValidator implements Validator { 1.541 + 1.542 + private static final long serialVersionUID = 1L; 1.543 + 1.544 + public void validate() throws ValidationException { 1.545 + PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties()); 1.546 + PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties()); 1.547 + PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties()); 1.548 + PropertyValidator.getInstance().assertOne(Property.SEQUENCE, getProperties()); 1.549 + PropertyValidator.getInstance().assertOne(Property.SUMMARY, getProperties()); 1.550 + PropertyValidator.getInstance().assertOne(Property.UID, getProperties()); 1.551 + 1.552 + PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties()); 1.553 + PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties()); 1.554 + PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, getProperties()); 1.555 + PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties()); 1.556 + PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties()); 1.557 + PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties()); 1.558 + PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties()); 1.559 + PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties()); 1.560 + PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties()); 1.561 + PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties()); 1.562 + PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties()); 1.563 + PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties()); 1.564 + PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties()); 1.565 + PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties()); 1.566 + PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties()); 1.567 + 1.568 + PropertyValidator.getInstance().assertNone(Property.RECURRENCE_ID, getProperties()); 1.569 + PropertyValidator.getInstance().assertNone(Property.REQUEST_STATUS, getProperties()); 1.570 + 1.571 + for (final Iterator i = getAlarms().iterator(); i.hasNext();) { 1.572 + final VAlarm alarm = (VAlarm) i.next(); 1.573 + alarm.validate(Method.ADD); 1.574 + } 1.575 + } 1.576 + } 1.577 + 1.578 + /** 1.579 + * METHOD:CANCEL Validator. 1.580 + * 1.581 + * <pre> 1.582 + * Component/Property Presence 1.583 + * ------------------- ---------------------------------------------- 1.584 + * METHOD 1 MUST be "CANCEL" 1.585 + * 1.586 + * VEVENT 1+ All must have the same UID 1.587 + * ATTENDEE 0+ MUST include all "Attendees" being removed 1.588 + * the event. MUST include all "Attendees" if 1.589 + * the entire event is cancelled. 1.590 + * DTSTAMP 1 1.591 + * ORGANIZER 1 1.592 + * SEQUENCE 1 1.593 + * UID 1 MUST be the UID of the original REQUEST 1.594 + * 1.595 + * COMMENT 0 or 1 1.596 + * ATTACH 0+ 1.597 + * CATEGORIES 0 or 1 This property may contain a list of values 1.598 + * CLASS 0 or 1 1.599 + * CONTACT 0+ 1.600 + * CREATED 0 or 1 1.601 + * DESCRIPTION 0 or 1 1.602 + * DTEND 0 or 1 if present DURATION MUST NOT be present 1.603 + * DTSTART 0 or 1 1.604 + * DURATION 0 or 1 if present DTEND MUST NOT be present 1.605 + * EXDATE 0+ 1.606 + * EXRULE 0+ 1.607 + * GEO 0 or 1 1.608 + * LAST-MODIFIED 0 or 1 1.609 + * LOCATION 0 or 1 1.610 + * PRIORITY 0 or 1 1.611 + * RDATE 0+ 1.612 + * RECURRENCE-ID 0 or 1 MUST be present if referring to one or 1.613 + * more or more recurring instances. 1.614 + * Otherwise it MUST NOT be present 1.615 + * RELATED-TO 0+ 1.616 + * RESOURCES 0 or 1 1.617 + * RRULE 0+ 1.618 + * STATUS 0 or 1 MUST be set to CANCELLED. If uninviting 1.619 + * specific "Attendees" then MUST NOT be 1.620 + * included. 1.621 + * SUMMARY 0 or 1 1.622 + * TRANSP 0 or 1 1.623 + * URL 0 or 1 1.624 + * X-PROPERTY 0+ 1.625 + * REQUEST-STATUS 0 1.626 + * 1.627 + * VTIMEZONE 0+ MUST be present if any date/time refers to 1.628 + * a timezone 1.629 + * X-COMPONENT 0+ 1.630 + * 1.631 + * VTODO 0 1.632 + * VJOURNAL 0 1.633 + * VFREEBUSY 0 1.634 + * VALARM 0 1.635 + * </pre> 1.636 + * 1.637 + */ 1.638 + private class CancelValidator implements Validator { 1.639 + 1.640 + private static final long serialVersionUID = 1L; 1.641 + 1.642 + public final void validate() throws ValidationException { 1.643 + PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties()); 1.644 + PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties()); 1.645 + PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties()); 1.646 + PropertyValidator.getInstance().assertOne(Property.SEQUENCE, getProperties()); 1.647 + PropertyValidator.getInstance().assertOne(Property.UID, getProperties()); 1.648 + 1.649 + PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, getProperties()); 1.650 + PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties()); 1.651 + PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties()); 1.652 + PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties()); 1.653 + PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties()); 1.654 + PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties()); 1.655 + PropertyValidator.getInstance().assertOneOrLess(Property.DTSTART, getProperties()); 1.656 + PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties()); 1.657 + PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties()); 1.658 + PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties()); 1.659 + PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties()); 1.660 + PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties()); 1.661 + PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties()); 1.662 + PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties()); 1.663 + PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties()); 1.664 + PropertyValidator.getInstance().assertOneOrLess(Property.SUMMARY, getProperties()); 1.665 + PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties()); 1.666 + PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties()); 1.667 + 1.668 + PropertyValidator.getInstance().assertNone(Property.REQUEST_STATUS, getProperties()); 1.669 + 1.670 + ComponentValidator.assertNone(Component.VALARM, getAlarms()); 1.671 + } 1.672 + } 1.673 + 1.674 + /** 1.675 + * METHOD:COUNTER Validator. 1.676 + * 1.677 + * <pre> 1.678 + * Component/Property Presence 1.679 + * ------------------- ---------------------------------------------- 1.680 + * METHOD 1 MUST be "COUNTER" 1.681 + * 1.682 + * VEVENT 1 1.683 + * DTSTAMP 1 1.684 + * DTSTART 1 1.685 + * ORGANIZER 1 MUST be the "Organizer" of the original 1.686 + * event 1.687 + * SEQUENCE 1 MUST be present if value is greater than 0, 1.688 + * MAY be present if 0 1.689 + * SUMMARY 1 Can be null 1.690 + * UID 1 MUST be the UID associated with the REQUEST 1.691 + * being countered 1.692 + * 1.693 + * ATTACH 0+ 1.694 + * ATTENDEE 0+ Can also be used to propose other 1.695 + * "Attendees" 1.696 + * CATEGORIES 0 or 1 This property may contain a list of values 1.697 + * CLASS 0 or 1 1.698 + * COMMENT 0 or 1 1.699 + * CONTACT 0+ 1.700 + * CREATED 0 or 1 1.701 + * DESCRIPTION 0 or 1 1.702 + * DTEND 0 or 1 if present DURATION MUST NOT be present 1.703 + * DURATION 0 or 1 if present DTEND MUST NOT be present 1.704 + * EXDATE 0+ 1.705 + * EXRULE 0+ 1.706 + * GEO 0 or 1 1.707 + * LAST-MODIFIED 0 or 1 1.708 + * LOCATION 0 or 1 1.709 + * PRIORITY 0 or 1 1.710 + * RDATE 0+ 1.711 + * RECURRENCE-ID 0 or 1 MUST only if referring to an instance of a 1.712 + * recurring calendar component. Otherwise it 1.713 + * MUST NOT be present. 1.714 + * RELATED-TO 0+ 1.715 + * REQUEST-STATUS 0+ 1.716 + * RESOURCES 0 or 1 This property may contain a list of values 1.717 + * RRULE 0+ 1.718 + * STATUS 0 or 1 Value must be one of CONFIRMED/TENATIVE/ 1.719 + * CANCELLED 1.720 + * TRANSP 0 or 1 1.721 + * URL 0 or 1 1.722 + * X-PROPERTY 0+ 1.723 + * 1.724 + * VALARM 0+ 1.725 + * VTIMEZONE 0+ MUST be present if any date/time refers to 1.726 + * a timezone 1.727 + * X-COMPONENT 0+ 1.728 + * 1.729 + * VTODO 0 1.730 + * VJOURNAL 0 1.731 + * VFREEBUSY 0 1.732 + * </pre> 1.733 + * 1.734 + */ 1.735 + private class CounterValidator implements Validator { 1.736 + 1.737 + private static final long serialVersionUID = 1L; 1.738 + 1.739 + public void validate() throws ValidationException { 1.740 + PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties()); 1.741 + PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties()); 1.742 + 1.743 + if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) { 1.744 + PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties()); 1.745 + } 1.746 + 1.747 + PropertyValidator.getInstance().assertOne(Property.SEQUENCE, getProperties()); 1.748 + PropertyValidator.getInstance().assertOne(Property.SUMMARY, getProperties()); 1.749 + PropertyValidator.getInstance().assertOne(Property.UID, getProperties()); 1.750 + 1.751 + PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties()); 1.752 + PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties()); 1.753 + PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, getProperties()); 1.754 + PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties()); 1.755 + PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties()); 1.756 + PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties()); 1.757 + PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties()); 1.758 + PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties()); 1.759 + PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties()); 1.760 + PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties()); 1.761 + PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties()); 1.762 + PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties()); 1.763 + PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties()); 1.764 + PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties()); 1.765 + PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties()); 1.766 + PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties()); 1.767 + 1.768 + for (final Iterator i = getAlarms().iterator(); i.hasNext();) { 1.769 + final VAlarm alarm = (VAlarm) i.next(); 1.770 + alarm.validate(Method.COUNTER); 1.771 + } 1.772 + } 1.773 + } 1.774 + 1.775 + /** 1.776 + * METHOD:DECLINECOUNTER Validator. 1.777 + * 1.778 + * <pre> 1.779 + * Component/Property Presence 1.780 + * ------------------- ---------------------------------------------- 1.781 + * METHOD 1 MUST be "DECLINECOUNTER" 1.782 + * 1.783 + * VEVENT 1 1.784 + * DTSTAMP 1 1.785 + * ORGANIZER 1 1.786 + * UID 1 MUST, same UID specified in original 1.787 + * REQUEST and subsequent COUNTER 1.788 + * COMMENT 0 or 1 1.789 + * RECURRENCE-ID 0 or 1 MUST only if referring to an instance of a 1.790 + * recurring calendar component. Otherwise it 1.791 + * MUST NOT be present. 1.792 + * REQUEST-STATUS 0+ 1.793 + * SEQUENCE 0 OR 1 MUST be present if value is greater than 0, 1.794 + * MAY be present if 0 1.795 + * X-PROPERTY 0+ 1.796 + * ATTACH 0 1.797 + * ATTENDEE 0 1.798 + * CATEGORIES 0 1.799 + * CLASS 0 1.800 + * CONTACT 0 1.801 + * CREATED 0 1.802 + * DESCRIPTION 0 1.803 + * DTEND 0 1.804 + * DTSTART 0 1.805 + * DURATION 0 1.806 + * EXDATE 0 1.807 + * EXRULE 0 1.808 + * GEO 0 1.809 + * LAST-MODIFIED 0 1.810 + * LOCATION 0 1.811 + * PRIORITY 0 1.812 + * RDATE 0 1.813 + * RELATED-TO 0 1.814 + * RESOURCES 0 1.815 + * RRULE 0 1.816 + * STATUS 0 1.817 + * SUMMARY 0 1.818 + * TRANSP 0 1.819 + * URL 0 1.820 + * 1.821 + * X-COMPONENT 0+ 1.822 + * VTODO 0 1.823 + * VJOURNAL 0 1.824 + * VFREEBUSY 0 1.825 + * VTIMEZONE 0 1.826 + * VALARM 0 1.827 + * </pre> 1.828 + * 1.829 + */ 1.830 + private class DeclineCounterValidator implements Validator { 1.831 + 1.832 + private static final long serialVersionUID = 1L; 1.833 + 1.834 + public void validate() throws ValidationException { 1.835 + PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties()); 1.836 + PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties()); 1.837 + PropertyValidator.getInstance().assertOne(Property.UID, getProperties()); 1.838 + 1.839 + PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, getProperties()); 1.840 + PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties()); 1.841 + PropertyValidator.getInstance().assertOneOrLess(Property.SEQUENCE, getProperties()); 1.842 + 1.843 + PropertyValidator.getInstance().assertNone(Property.ATTACH, getProperties()); 1.844 + PropertyValidator.getInstance().assertNone(Property.ATTENDEE, getProperties()); 1.845 + PropertyValidator.getInstance().assertNone(Property.CATEGORIES, getProperties()); 1.846 + PropertyValidator.getInstance().assertNone(Property.CLASS, getProperties()); 1.847 + PropertyValidator.getInstance().assertNone(Property.CONTACT, getProperties()); 1.848 + PropertyValidator.getInstance().assertNone(Property.CREATED, getProperties()); 1.849 + PropertyValidator.getInstance().assertNone(Property.DESCRIPTION, getProperties()); 1.850 + PropertyValidator.getInstance().assertNone(Property.DTEND, getProperties()); 1.851 + PropertyValidator.getInstance().assertNone(Property.DTSTART, getProperties()); 1.852 + PropertyValidator.getInstance().assertNone(Property.DURATION, getProperties()); 1.853 + PropertyValidator.getInstance().assertNone(Property.EXDATE, getProperties()); 1.854 + PropertyValidator.getInstance().assertNone(Property.EXRULE, getProperties()); 1.855 + PropertyValidator.getInstance().assertNone(Property.GEO, getProperties()); 1.856 + PropertyValidator.getInstance().assertNone(Property.LAST_MODIFIED, getProperties()); 1.857 + PropertyValidator.getInstance().assertNone(Property.LOCATION, getProperties()); 1.858 + PropertyValidator.getInstance().assertNone(Property.PRIORITY, getProperties()); 1.859 + PropertyValidator.getInstance().assertNone(Property.RDATE, getProperties()); 1.860 + PropertyValidator.getInstance().assertNone(Property.RELATED_TO, getProperties()); 1.861 + PropertyValidator.getInstance().assertNone(Property.RESOURCES, getProperties()); 1.862 + PropertyValidator.getInstance().assertNone(Property.RRULE, getProperties()); 1.863 + PropertyValidator.getInstance().assertNone(Property.STATUS, getProperties()); 1.864 + PropertyValidator.getInstance().assertNone(Property.SUMMARY, getProperties()); 1.865 + PropertyValidator.getInstance().assertNone(Property.TRANSP, getProperties()); 1.866 + PropertyValidator.getInstance().assertNone(Property.URL, getProperties()); 1.867 + 1.868 + ComponentValidator.assertNone(Component.VALARM, getAlarms()); 1.869 + } 1.870 + } 1.871 + 1.872 + /** 1.873 + * METHOD:PUBLISH Validator. 1.874 + * 1.875 + * <pre> 1.876 + * Component/Property Presence 1.877 + * ------------------- ---------------------------------------------- 1.878 + * METHOD 1 MUST equal "PUBLISH" 1.879 + * VEVENT 1+ 1.880 + * DTSTAMP 1 1.881 + * DTSTART 1 1.882 + * ORGANIZER 1 1.883 + * SUMMARY 1 Can be null. 1.884 + * UID 1 1.885 + * RECURRENCE-ID 0 or 1 only if referring to an instance of a 1.886 + * recurring calendar component. Otherwise 1.887 + * it MUST NOT be present. 1.888 + * SEQUENCE 0 or 1 MUST be present if value is greater than 1.889 + * 0, MAY be present if 0 1.890 + * ATTACH 0+ 1.891 + * CATEGORIES 0 or 1 This property may contain a list of 1.892 + * values 1.893 + * CLASS 0 or 1 1.894 + * COMMENT 0 or 1 1.895 + * CONTACT 0+ 1.896 + * CREATED 0 or 1 1.897 + * DESCRIPTION 0 or 1 Can be null 1.898 + * DTEND 0 or 1 if present DURATION MUST NOT be present 1.899 + * DURATION 0 or 1 if present DTEND MUST NOT be present 1.900 + * EXDATE 0+ 1.901 + * EXRULE 0+ 1.902 + * GEO 0 or 1 1.903 + * LAST-MODIFIED 0 or 1 1.904 + * LOCATION 0 or 1 1.905 + * PRIORITY 0 or 1 1.906 + * RDATE 0+ 1.907 + * RELATED-TO 0+ 1.908 + * RESOURCES 0 or 1 This property MAY contain a list of values 1.909 + * RRULE 0+ 1.910 + * STATUS 0 or 1 MAY be one of TENTATIVE/CONFIRMED/CANCELLED 1.911 + * TRANSP 0 or 1 1.912 + * URL 0 or 1 1.913 + * X-PROPERTY 0+ 1.914 + * 1.915 + * ATTENDEE 0 1.916 + * REQUEST-STATUS 0 1.917 + * 1.918 + * VALARM 0+ 1.919 + * VFREEBUSY 0 1.920 + * VJOURNAL 0 1.921 + * VTODO 0 1.922 + * VTIMEZONE 0+ MUST be present if any date/time refers to 1.923 + * a timezone 1.924 + * X-COMPONENT 0+ 1.925 + * </pre> 1.926 + * 1.927 + */ 1.928 + private class PublishValidator implements Validator { 1.929 + 1.930 + private static final long serialVersionUID = 1L; 1.931 + 1.932 + public void validate() throws ValidationException { 1.933 + PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties()); 1.934 + PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties()); 1.935 + 1.936 + if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) { 1.937 + PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties()); 1.938 + PropertyValidator.getInstance().assertOne(Property.SUMMARY, getProperties()); 1.939 + } 1.940 + 1.941 + PropertyValidator.getInstance().assertOne(Property.UID, getProperties()); 1.942 + 1.943 + PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties()); 1.944 + PropertyValidator.getInstance().assertOneOrLess(Property.SEQUENCE, getProperties()); 1.945 + PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties()); 1.946 + PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties()); 1.947 + PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, getProperties()); 1.948 + PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties()); 1.949 + PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties()); 1.950 + PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties()); 1.951 + PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties()); 1.952 + PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties()); 1.953 + PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties()); 1.954 + PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties()); 1.955 + PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties()); 1.956 + PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties()); 1.957 + PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties()); 1.958 + PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties()); 1.959 + PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties()); 1.960 + 1.961 + if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) { 1.962 + PropertyValidator.getInstance().assertNone(Property.ATTENDEE, getProperties()); 1.963 + } 1.964 + 1.965 + PropertyValidator.getInstance().assertNone(Property.REQUEST_STATUS, getProperties()); 1.966 + 1.967 + for (final Iterator i = getAlarms().iterator(); i.hasNext();) { 1.968 + final VAlarm alarm = (VAlarm) i.next(); 1.969 + alarm.validate(Method.PUBLISH); 1.970 + } 1.971 + } 1.972 + } 1.973 + 1.974 + /** 1.975 + * METHOD:REFRESH Validator. 1.976 + * 1.977 + * <pre> 1.978 + * Component/Property Presence 1.979 + * ------------------- ---------------------------------------------- 1.980 + * METHOD 1 MUST be "REFRESH" 1.981 + * 1.982 + * VEVENT 1 1.983 + * ATTENDEE 1 MUST be the address of requestor 1.984 + * DTSTAMP 1 1.985 + * ORGANIZER 1 1.986 + * UID 1 MUST be the UID associated with original 1.987 + * REQUEST 1.988 + * COMMENT 0 or 1 1.989 + * RECURRENCE-ID 0 or 1 MUST only if referring to an instance of a 1.990 + * recurring calendar component. Otherwise 1.991 + * it must NOT be present. 1.992 + * X-PROPERTY 0+ 1.993 + * 1.994 + * ATTACH 0 1.995 + * CATEGORIES 0 1.996 + * CLASS 0 1.997 + * CONTACT 0 1.998 + * CREATED 0 1.999 + * DESCRIPTION 0 1.1000 + * DTEND 0 1.1001 + * DTSTART 0 1.1002 + * DURATION 0 1.1003 + * EXDATE 0 1.1004 + * EXRULE 0 1.1005 + * GEO 0 1.1006 + * LAST-MODIFIED 0 1.1007 + * LOCATION 0 1.1008 + * PRIORITY 0 1.1009 + * RDATE 0 1.1010 + * RELATED-TO 0 1.1011 + * REQUEST-STATUS 0 1.1012 + * RESOURCES 0 1.1013 + * RRULE 0 1.1014 + * SEQUENCE 0 1.1015 + * STATUS 0 1.1016 + * SUMMARY 0 1.1017 + * TRANSP 0 1.1018 + * URL 0 1.1019 + * 1.1020 + * X-COMPONENT 0+ 1.1021 + * 1.1022 + * VTODO 0 1.1023 + * VJOURNAL 0 1.1024 + * VFREEBUSY 0 1.1025 + * VTIMEZONE 0 1.1026 + * VALARM 0 1.1027 + * </pre> 1.1028 + * 1.1029 + */ 1.1030 + private class RefreshValidator implements Validator { 1.1031 + 1.1032 + private static final long serialVersionUID = 1L; 1.1033 + 1.1034 + public void validate() throws ValidationException { 1.1035 + PropertyValidator.getInstance().assertOne(Property.ATTENDEE, getProperties()); 1.1036 + PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties()); 1.1037 + PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties()); 1.1038 + PropertyValidator.getInstance().assertOne(Property.UID, getProperties()); 1.1039 + 1.1040 + PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, getProperties()); 1.1041 + PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties()); 1.1042 + 1.1043 + PropertyValidator.getInstance().assertNone(Property.ATTACH, getProperties()); 1.1044 + PropertyValidator.getInstance().assertNone(Property.CATEGORIES, getProperties()); 1.1045 + PropertyValidator.getInstance().assertNone(Property.CLASS, getProperties()); 1.1046 + PropertyValidator.getInstance().assertNone(Property.CONTACT, getProperties()); 1.1047 + PropertyValidator.getInstance().assertNone(Property.CREATED, getProperties()); 1.1048 + PropertyValidator.getInstance().assertNone(Property.DESCRIPTION, getProperties()); 1.1049 + PropertyValidator.getInstance().assertNone(Property.DTEND, getProperties()); 1.1050 + PropertyValidator.getInstance().assertNone(Property.DTSTART, getProperties()); 1.1051 + PropertyValidator.getInstance().assertNone(Property.DURATION, getProperties()); 1.1052 + PropertyValidator.getInstance().assertNone(Property.EXDATE, getProperties()); 1.1053 + PropertyValidator.getInstance().assertNone(Property.EXRULE, getProperties()); 1.1054 + PropertyValidator.getInstance().assertNone(Property.GEO, getProperties()); 1.1055 + PropertyValidator.getInstance().assertNone(Property.LAST_MODIFIED, getProperties()); 1.1056 + PropertyValidator.getInstance().assertNone(Property.LOCATION, getProperties()); 1.1057 + PropertyValidator.getInstance().assertNone(Property.PRIORITY, getProperties()); 1.1058 + PropertyValidator.getInstance().assertNone(Property.RDATE, getProperties()); 1.1059 + PropertyValidator.getInstance().assertNone(Property.RELATED_TO, getProperties()); 1.1060 + PropertyValidator.getInstance().assertNone(Property.REQUEST_STATUS, getProperties()); 1.1061 + PropertyValidator.getInstance().assertNone(Property.RESOURCES, getProperties()); 1.1062 + PropertyValidator.getInstance().assertNone(Property.RRULE, getProperties()); 1.1063 + PropertyValidator.getInstance().assertNone(Property.SEQUENCE, getProperties()); 1.1064 + PropertyValidator.getInstance().assertNone(Property.STATUS, getProperties()); 1.1065 + PropertyValidator.getInstance().assertNone(Property.SUMMARY, getProperties()); 1.1066 + PropertyValidator.getInstance().assertNone(Property.TRANSP, getProperties()); 1.1067 + PropertyValidator.getInstance().assertNone(Property.URL, getProperties()); 1.1068 + 1.1069 + ComponentValidator.assertNone(Component.VALARM, getAlarms()); 1.1070 + } 1.1071 + } 1.1072 + 1.1073 + /** 1.1074 + * METHOD:REPLY Validator. 1.1075 + * 1.1076 + * <pre> 1.1077 + * Component/Property Presence 1.1078 + * ------------------- ---------------------------------------------- 1.1079 + * METHOD 1 MUST be "REPLY" 1.1080 + * VEVENT 1+ All components MUST have the same UID 1.1081 + * ATTENDEE 1 MUST be the address of the Attendee 1.1082 + * replying. 1.1083 + * DTSTAMP 1 1.1084 + * ORGANIZER 1 1.1085 + * RECURRENCE-ID 0 or 1 only if referring to an instance of a 1.1086 + * recurring calendar component. Otherwise 1.1087 + * it must NOT be present. 1.1088 + * UID 1 MUST be the UID of the original REQUEST 1.1089 + * 1.1090 + * SEQUENCE 0 or 1 MUST if non-zero, MUST be the sequence 1.1091 + * number of the original REQUEST. MAY be 1.1092 + * present if 0. 1.1093 + * 1.1094 + * ATTACH 0+ 1.1095 + * CATEGORIES 0 or 1 This property may contain a list of values 1.1096 + * CLASS 0 or 1 1.1097 + * COMMENT 0 or 1 1.1098 + * CONTACT 0+ 1.1099 + * CREATED 0 or 1 1.1100 + * DESCRIPTION 0 or 1 1.1101 + * DTEND 0 or 1 if present DURATION MUST NOT be present 1.1102 + * DTSTART 0 or 1 1.1103 + * DURATION 0 or 1 if present DTEND MUST NOT be present 1.1104 + * EXDATE 0+ 1.1105 + * EXRULE 0+ 1.1106 + * GEO 0 or 1 1.1107 + * LAST-MODIFIED 0 or 1 1.1108 + * LOCATION 0 or 1 1.1109 + * PRIORITY 0 or 1 1.1110 + * RDATE 0+ 1.1111 + * RELATED-TO 0+ 1.1112 + * RESOURCES 0 or 1 This property MAY contain a list of values 1.1113 + * REQUEST-STATUS 0+ 1.1114 + * RRULE 0+ 1.1115 + * STATUS 0 or 1 1.1116 + * SUMMARY 0 or 1 1.1117 + * TRANSP 0 or 1 1.1118 + * URL 0 or 1 1.1119 + * X-PROPERTY 0+ 1.1120 + * 1.1121 + * VTIMEZONE 0 or 1 MUST be present if any date/time refers 1.1122 + * to a timezone 1.1123 + * X-COMPONENT 0+ 1.1124 + * 1.1125 + * VALARM 0 1.1126 + * VFREEBUSY 0 1.1127 + * VJOURNAL 0 1.1128 + * VTODO 0 1.1129 + * </pre> 1.1130 + * 1.1131 + */ 1.1132 + private class ReplyValidator implements Validator { 1.1133 + 1.1134 + private static final long serialVersionUID = 1L; 1.1135 + 1.1136 + public void validate() throws ValidationException { 1.1137 + PropertyValidator.getInstance().assertOne(Property.ATTENDEE, getProperties()); 1.1138 + PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties()); 1.1139 + PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties()); 1.1140 + PropertyValidator.getInstance().assertOne(Property.UID, getProperties()); 1.1141 + 1.1142 + PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties()); 1.1143 + PropertyValidator.getInstance().assertOneOrLess(Property.SEQUENCE, getProperties()); 1.1144 + PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties()); 1.1145 + PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties()); 1.1146 + PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, getProperties()); 1.1147 + PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties()); 1.1148 + PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties()); 1.1149 + PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties()); 1.1150 + PropertyValidator.getInstance().assertOneOrLess(Property.DTSTART, getProperties()); 1.1151 + PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties()); 1.1152 + PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties()); 1.1153 + PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties()); 1.1154 + PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties()); 1.1155 + PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties()); 1.1156 + PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties()); 1.1157 + PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties()); 1.1158 + PropertyValidator.getInstance().assertOneOrLess(Property.SUMMARY, getProperties()); 1.1159 + PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties()); 1.1160 + PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties()); 1.1161 + 1.1162 + ComponentValidator.assertNone(Component.VALARM, getAlarms()); 1.1163 + } 1.1164 + } 1.1165 + 1.1166 + /** 1.1167 + * METHOD:REQUEST Validator. 1.1168 + * 1.1169 + * <pre> 1.1170 + * Component/Property Presence 1.1171 + * ----------------------------------------------------------------- 1.1172 + * METHOD 1 MUST be "REQUEST" 1.1173 + * VEVENT 1+ All components MUST have the same UID 1.1174 + * ATTENDEE 1+ 1.1175 + * DTSTAMP 1 1.1176 + * DTSTART 1 1.1177 + * ORGANIZER 1 1.1178 + * SEQUENCE 0 or 1 MUST be present if value is greater than 0, 1.1179 + * MAY be present if 0 1.1180 + * SUMMARY 1 Can be null 1.1181 + * UID 1 1.1182 + * 1.1183 + * ATTACH 0+ 1.1184 + * CATEGORIES 0 or 1 This property may contain a list of values 1.1185 + * CLASS 0 or 1 1.1186 + * COMMENT 0 or 1 1.1187 + * CONTACT 0+ 1.1188 + * CREATED 0 or 1 1.1189 + * DESCRIPTION 0 or 1 Can be null 1.1190 + * DTEND 0 or 1 if present DURATION MUST NOT be present 1.1191 + * DURATION 0 or 1 if present DTEND MUST NOT be present 1.1192 + * EXDATE 0+ 1.1193 + * EXRULE 0+ 1.1194 + * GEO 0 or 1 1.1195 + * LAST-MODIFIED 0 or 1 1.1196 + * LOCATION 0 or 1 1.1197 + * PRIORITY 0 or 1 1.1198 + * RDATE 0+ 1.1199 + * RECURRENCE-ID 0 or 1 only if referring to an instance of a 1.1200 + * recurring calendar component. Otherwise it 1.1201 + * MUST NOT be present. 1.1202 + * RELATED-TO 0+ 1.1203 + * REQUEST-STATUS 0+ 1.1204 + * RESOURCES 0 or 1 This property MAY contain a list of values 1.1205 + * RRULE 0+ 1.1206 + * STATUS 0 or 1 MAY be one of TENTATIVE/CONFIRMED 1.1207 + * TRANSP 0 or 1 1.1208 + * URL 0 or 1 1.1209 + * X-PROPERTY 0+ 1.1210 + * 1.1211 + * VALARM 0+ 1.1212 + * VTIMEZONE 0+ MUST be present if any date/time refers to 1.1213 + * a timezone 1.1214 + * X-COMPONENT 0+ 1.1215 + * VFREEBUSY 0 1.1216 + * VJOURNAL 0 1.1217 + * VTODO 0 1.1218 + * </pre> 1.1219 + * 1.1220 + */ 1.1221 + private class RequestValidator implements Validator { 1.1222 + 1.1223 + private static final long serialVersionUID = 1L; 1.1224 + 1.1225 + public void validate() throws ValidationException { 1.1226 + if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) { 1.1227 + PropertyValidator.getInstance().assertOneOrMore(Property.ATTENDEE, getProperties()); 1.1228 + } 1.1229 + 1.1230 + PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties()); 1.1231 + PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties()); 1.1232 + PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties()); 1.1233 + PropertyValidator.getInstance().assertOne(Property.SUMMARY, getProperties()); 1.1234 + PropertyValidator.getInstance().assertOne(Property.UID, getProperties()); 1.1235 + 1.1236 + PropertyValidator.getInstance().assertOneOrLess(Property.SEQUENCE, getProperties()); 1.1237 + PropertyValidator.getInstance().assertOneOrLess(Property.CATEGORIES, getProperties()); 1.1238 + PropertyValidator.getInstance().assertOneOrLess(Property.CLASS, getProperties()); 1.1239 + PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, getProperties()); 1.1240 + PropertyValidator.getInstance().assertOneOrLess(Property.CREATED, getProperties()); 1.1241 + PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties()); 1.1242 + PropertyValidator.getInstance().assertOneOrLess(Property.DTEND, getProperties()); 1.1243 + PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties()); 1.1244 + PropertyValidator.getInstance().assertOneOrLess(Property.GEO, getProperties()); 1.1245 + PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED, getProperties()); 1.1246 + PropertyValidator.getInstance().assertOneOrLess(Property.LOCATION, getProperties()); 1.1247 + PropertyValidator.getInstance().assertOneOrLess(Property.PRIORITY, getProperties()); 1.1248 + PropertyValidator.getInstance().assertOneOrLess(Property.RECURRENCE_ID, getProperties()); 1.1249 + PropertyValidator.getInstance().assertOneOrLess(Property.RESOURCES, getProperties()); 1.1250 + PropertyValidator.getInstance().assertOneOrLess(Property.STATUS, getProperties()); 1.1251 + PropertyValidator.getInstance().assertOneOrLess(Property.TRANSP, getProperties()); 1.1252 + PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties()); 1.1253 + 1.1254 + for (final Iterator i = getAlarms().iterator(); i.hasNext();) { 1.1255 + final VAlarm alarm = (VAlarm) i.next(); 1.1256 + alarm.validate(Method.REQUEST); 1.1257 + } 1.1258 + } 1.1259 + } 1.1260 + /** 1.1261 + * Returns a normalised list of periods representing the consumed time for this event. 1.1262 + * @param rangeStart the start of a range 1.1263 + * @param rangeEnd the end of a range 1.1264 + * @return a normalised list of periods representing consumed time for this event 1.1265 + * @see VEvent#getConsumedTime(Date, Date, boolean) 1.1266 + */ 1.1267 + public final PeriodList getConsumedTime(final Date rangeStart, 1.1268 + final Date rangeEnd) { 1.1269 + return getConsumedTime(rangeStart, rangeEnd, true); 1.1270 + } 1.1271 + 1.1272 + /** 1.1273 + * Returns a list of periods representing the consumed time for this event in the specified range. Note that the 1.1274 + * returned list may contain a single period for non-recurring components or multiple periods for recurring 1.1275 + * components. If no time is consumed by this event an empty list is returned. 1.1276 + * @param rangeStart the start of the range to check for consumed time 1.1277 + * @param rangeEnd the end of the range to check for consumed time 1.1278 + * @param normalise indicate whether the returned list of periods should be normalised 1.1279 + * @return a list of periods representing consumed time for this event 1.1280 + */ 1.1281 + public final PeriodList getConsumedTime(final Date rangeStart, 1.1282 + final Date rangeEnd, final boolean normalise) { 1.1283 + PeriodList periods = new PeriodList(); 1.1284 + // if component is transparent return empty list.. 1.1285 + if (!Transp.TRANSPARENT.equals(getProperty(Property.TRANSP))) { 1.1286 + 1.1287 +// try { 1.1288 + periods = calculateRecurrenceSet(new Period(new DateTime(rangeStart), 1.1289 + new DateTime(rangeEnd))); 1.1290 +// } 1.1291 +// catch (ValidationException ve) { 1.1292 +// log.error("Invalid event data", ve); 1.1293 +// return periods; 1.1294 +// } 1.1295 + 1.1296 + // if periods already specified through recurrence, return.. 1.1297 + // ..also normalise before returning. 1.1298 + if (!periods.isEmpty() && normalise) { 1.1299 + periods = periods.normalise(); 1.1300 + } 1.1301 + } 1.1302 + 1.1303 + return periods; 1.1304 + } 1.1305 + 1.1306 + /** 1.1307 + * Returns a single occurrence of a recurring event. 1.1308 + * @param date a date on which the occurence should occur 1.1309 + * @return a single non-recurring event instance for the specified date, or null if the event doesn't 1.1310 + * occur on the specified date 1.1311 + * @throws IOException where an error occurs reading data 1.1312 + * @throws URISyntaxException where an invalid URI is encountered 1.1313 + * @throws ParseException where an error occurs parsing data 1.1314 + */ 1.1315 + public final VEvent getOccurrence(final Date date) throws IOException, 1.1316 + URISyntaxException, ParseException { 1.1317 + 1.1318 + final PeriodList consumedTime = getConsumedTime(date, date); 1.1319 + for (final Iterator i = consumedTime.iterator(); i.hasNext();) { 1.1320 + final Period p = (Period) i.next(); 1.1321 + if (p.getStart().equals(date)) { 1.1322 + final VEvent occurrence = (VEvent) this.copy(); 1.1323 + occurrence.getProperties().add(new RecurrenceId(date)); 1.1324 + return occurrence; 1.1325 + } 1.1326 + } 1.1327 + return null; 1.1328 + } 1.1329 + 1.1330 + /** 1.1331 + * @return the optional access classification property for an event 1.1332 + */ 1.1333 + public final Clazz getClassification() { 1.1334 + return (Clazz) getProperty(Property.CLASS); 1.1335 + } 1.1336 + 1.1337 + /** 1.1338 + * @return the optional creation-time property for an event 1.1339 + */ 1.1340 + public final Created getCreated() { 1.1341 + return (Created) getProperty(Property.CREATED); 1.1342 + } 1.1343 + 1.1344 + /** 1.1345 + * @return the optional description property for an event 1.1346 + */ 1.1347 + public final Description getDescription() { 1.1348 + return (Description) getProperty(Property.DESCRIPTION); 1.1349 + } 1.1350 + 1.1351 + /** 1.1352 + * Convenience method to pull the DTSTART out of the property list. 1.1353 + * @return The DtStart object representation of the start Date 1.1354 + */ 1.1355 + public final DtStart getStartDate() { 1.1356 + return (DtStart) getProperty(Property.DTSTART); 1.1357 + } 1.1358 + 1.1359 + /** 1.1360 + * @return the optional geographic position property for an event 1.1361 + */ 1.1362 + public final Geo getGeographicPos() { 1.1363 + return (Geo) getProperty(Property.GEO); 1.1364 + } 1.1365 + 1.1366 + /** 1.1367 + * @return the optional last-modified property for an event 1.1368 + */ 1.1369 + public final LastModified getLastModified() { 1.1370 + return (LastModified) getProperty(Property.LAST_MODIFIED); 1.1371 + } 1.1372 + 1.1373 + /** 1.1374 + * @return the optional location property for an event 1.1375 + */ 1.1376 + public final Location getLocation() { 1.1377 + return (Location) getProperty(Property.LOCATION); 1.1378 + } 1.1379 + 1.1380 + /** 1.1381 + * @return the optional organizer property for an event 1.1382 + */ 1.1383 + public final Organizer getOrganizer() { 1.1384 + return (Organizer) getProperty(Property.ORGANIZER); 1.1385 + } 1.1386 + 1.1387 + /** 1.1388 + * @return the optional priority property for an event 1.1389 + */ 1.1390 + public final Priority getPriority() { 1.1391 + return (Priority) getProperty(Property.PRIORITY); 1.1392 + } 1.1393 + 1.1394 + /** 1.1395 + * @return the optional date-stamp property 1.1396 + */ 1.1397 + public final DtStamp getDateStamp() { 1.1398 + return (DtStamp) getProperty(Property.DTSTAMP); 1.1399 + } 1.1400 + 1.1401 + /** 1.1402 + * @return the optional sequence number property for an event 1.1403 + */ 1.1404 + public final Sequence getSequence() { 1.1405 + return (Sequence) getProperty(Property.SEQUENCE); 1.1406 + } 1.1407 + 1.1408 + /** 1.1409 + * @return the optional status property for an event 1.1410 + */ 1.1411 + public final Status getStatus() { 1.1412 + return (Status) getProperty(Property.STATUS); 1.1413 + } 1.1414 + 1.1415 + /** 1.1416 + * @return the optional summary property for an event 1.1417 + */ 1.1418 + public final Summary getSummary() { 1.1419 + return (Summary) getProperty(Property.SUMMARY); 1.1420 + } 1.1421 + 1.1422 + /** 1.1423 + * @return the optional time transparency property for an event 1.1424 + */ 1.1425 + public final Transp getTransparency() { 1.1426 + return (Transp) getProperty(Property.TRANSP); 1.1427 + } 1.1428 + 1.1429 + /** 1.1430 + * @return the optional URL property for an event 1.1431 + */ 1.1432 + public final Url getUrl() { 1.1433 + return (Url) getProperty(Property.URL); 1.1434 + } 1.1435 + 1.1436 + /** 1.1437 + * @return the optional recurrence identifier property for an event 1.1438 + */ 1.1439 + public final RecurrenceId getRecurrenceId() { 1.1440 + return (RecurrenceId) getProperty(Property.RECURRENCE_ID); 1.1441 + } 1.1442 + 1.1443 + /** 1.1444 + * Returns the end date of this event. Where an end date is not available it will be derived from the event 1.1445 + * duration. 1.1446 + * @return a DtEnd instance, or null if one cannot be derived 1.1447 + */ 1.1448 + public final DtEnd getEndDate() { 1.1449 + return getEndDate(true); 1.1450 + } 1.1451 + 1.1452 + /** 1.1453 + * Convenience method to pull the DTEND out of the property list. If DTEND was not specified, use the DTSTART + 1.1454 + * DURATION to calculate it. 1.1455 + * @param deriveFromDuration specifies whether to derive an end date from the event duration where an end date is 1.1456 + * not found 1.1457 + * @return The end for this VEVENT. 1.1458 + */ 1.1459 + public final DtEnd getEndDate(final boolean deriveFromDuration) { 1.1460 + DtEnd dtEnd = (DtEnd) getProperty(Property.DTEND); 1.1461 + // No DTEND? No problem, we'll use the DURATION. 1.1462 + if (dtEnd == null && deriveFromDuration && getDuration() != null) { 1.1463 + final DtStart dtStart = getStartDate(); 1.1464 + final Duration vEventDuration = getDuration(); 1.1465 + dtEnd = new DtEnd(Dates.getInstance(vEventDuration.getDuration() 1.1466 + .getTime(dtStart.getDate()), (Value) dtStart 1.1467 + .getParameter(Parameter.VALUE))); 1.1468 + if (dtStart.isUtc()) { 1.1469 + dtEnd.setUtc(true); 1.1470 + } 1.1471 + } 1.1472 + return dtEnd; 1.1473 + } 1.1474 + 1.1475 + /** 1.1476 + * @return the optional Duration property 1.1477 + */ 1.1478 + public final Duration getDuration() { 1.1479 + return (Duration) getProperty(Property.DURATION); 1.1480 + } 1.1481 + 1.1482 + /** 1.1483 + * Returns the UID property of this component if available. 1.1484 + * @return a Uid instance, or null if no UID property exists 1.1485 + */ 1.1486 + public final Uid getUid() { 1.1487 + return (Uid) getProperty(Property.UID); 1.1488 + } 1.1489 + 1.1490 + /** 1.1491 + * {@inheritDoc} 1.1492 + */ 1.1493 + public boolean equals(final Object arg0) { 1.1494 + if (arg0 instanceof VEvent) { 1.1495 + return super.equals(arg0) 1.1496 + && ObjectUtils.equals(alarms, ((VEvent) arg0).getAlarms()); 1.1497 + } 1.1498 + return super.equals(arg0); 1.1499 + } 1.1500 + 1.1501 + /** 1.1502 + * {@inheritDoc} 1.1503 + */ 1.1504 + public int hashCode() { 1.1505 + return new HashCodeBuilder().append(getName()).append(getProperties()) 1.1506 + .append(getAlarms()).toHashCode(); 1.1507 + } 1.1508 + 1.1509 + /** 1.1510 + * Overrides default copy method to add support for copying alarm sub-components. 1.1511 + * @return a copy of the instance 1.1512 + * @throws ParseException where values in the instance cannot be parsed 1.1513 + * @throws IOException where values in the instance cannot be read 1.1514 + * @throws URISyntaxException where an invalid URI value is encountered in the instance 1.1515 + * @see net.fortuna.ical4j.model.Component#copy() 1.1516 + */ 1.1517 + public Component copy() throws ParseException, IOException, 1.1518 + URISyntaxException { 1.1519 + final VEvent copy = (VEvent) super.copy(); 1.1520 + copy.alarms = new ComponentList(alarms); 1.1521 + return copy; 1.1522 + } 1.1523 +}