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

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

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

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

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

mercurial