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

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

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

Upgrade embedded ical4j from ancient whatever to upstream version 1.0.6.

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

mercurial