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

branch
ICAL4J_EMBED_1
changeset 15
cc93757aeca3
parent 14
5ae3e5665a0b
child 18
6dcaece8ec41
     1.1 --- a/src/net/fortuna/ical4j/model/component/VFreeBusy.java	Thu Feb 12 18:02:00 2015 +0100
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,805 +0,0 @@
     1.4 -/**
     1.5 - * Copyright (c) 2012, Ben Fortuna
     1.6 - * All rights reserved.
     1.7 - *
     1.8 - * Redistribution and use in source and binary forms, with or without
     1.9 - * modification, are permitted provided that the following conditions
    1.10 - * are met:
    1.11 - *
    1.12 - *  o Redistributions of source code must retain the above copyright
    1.13 - * notice, this list of conditions and the following disclaimer.
    1.14 - *
    1.15 - *  o Redistributions in binary form must reproduce the above copyright
    1.16 - * notice, this list of conditions and the following disclaimer in the
    1.17 - * documentation and/or other materials provided with the distribution.
    1.18 - *
    1.19 - *  o Neither the name of Ben Fortuna nor the names of any other contributors
    1.20 - * may be used to endorse or promote products derived from this software
    1.21 - * without specific prior written permission.
    1.22 - *
    1.23 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    1.24 - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    1.25 - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    1.26 - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    1.27 - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    1.28 - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    1.29 - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    1.30 - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    1.31 - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    1.32 - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    1.33 - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.34 - */
    1.35 -package net.fortuna.ical4j.model.component;
    1.36 -
    1.37 -import java.util.HashMap;
    1.38 -import java.util.Iterator;
    1.39 -import java.util.Map;
    1.40 -
    1.41 -import net.fortuna.ical4j.model.Component;
    1.42 -import net.fortuna.ical4j.model.ComponentList;
    1.43 -import net.fortuna.ical4j.model.DateRange;
    1.44 -import net.fortuna.ical4j.model.DateTime;
    1.45 -import net.fortuna.ical4j.model.Dur;
    1.46 -import net.fortuna.ical4j.model.Period;
    1.47 -import net.fortuna.ical4j.model.PeriodList;
    1.48 -import net.fortuna.ical4j.model.Property;
    1.49 -import net.fortuna.ical4j.model.PropertyList;
    1.50 -import net.fortuna.ical4j.model.ValidationException;
    1.51 -import net.fortuna.ical4j.model.Validator;
    1.52 -import net.fortuna.ical4j.model.parameter.FbType;
    1.53 -import net.fortuna.ical4j.model.property.Contact;
    1.54 -import net.fortuna.ical4j.model.property.DtEnd;
    1.55 -import net.fortuna.ical4j.model.property.DtStamp;
    1.56 -import net.fortuna.ical4j.model.property.DtStart;
    1.57 -import net.fortuna.ical4j.model.property.Duration;
    1.58 -import net.fortuna.ical4j.model.property.FreeBusy;
    1.59 -import net.fortuna.ical4j.model.property.Method;
    1.60 -import net.fortuna.ical4j.model.property.Organizer;
    1.61 -import net.fortuna.ical4j.model.property.Uid;
    1.62 -import net.fortuna.ical4j.model.property.Url;
    1.63 -import net.fortuna.ical4j.util.CompatibilityHints;
    1.64 -import net.fortuna.ical4j.util.PropertyValidator;
    1.65 -
    1.66 -/**
    1.67 - * $Id$ [Apr 5, 2004]
    1.68 - *
    1.69 - * Defines an iCalendar VFREEBUSY component.
    1.70 - *
    1.71 - * <pre>
    1.72 - *  4.6.4 Free/Busy Component
    1.73 - *
    1.74 - *     Component Name: VFREEBUSY
    1.75 - *
    1.76 - *     Purpose: Provide a grouping of component properties that describe
    1.77 - *     either a request for free/busy time, describe a response to a request
    1.78 - *     for free/busy time or describe a published set of busy time.
    1.79 - *
    1.80 - *     Formal Definition: A &quot;VFREEBUSY&quot; calendar component is defined by the
    1.81 - *     following notation:
    1.82 - *
    1.83 - *       freebusyc  = &quot;BEGIN&quot; &quot;:&quot; &quot;VFREEBUSY&quot; CRLF
    1.84 - *                    fbprop
    1.85 - *                    &quot;END&quot; &quot;:&quot; &quot;VFREEBUSY&quot; CRLF
    1.86 - *
    1.87 - *       fbprop     = *(
    1.88 - *
    1.89 - *                  ; the following are optional,
    1.90 - *                  ; but MUST NOT occur more than once
    1.91 - *
    1.92 - *                  contact / dtstart / dtend / duration / dtstamp /
    1.93 - *                  organizer / uid / url /
    1.94 - *
    1.95 - *                  ; the following are optional,
    1.96 - *                  ; and MAY occur more than once
    1.97 - *
    1.98 - *                  attendee / comment / freebusy / rstatus / x-prop
    1.99 - *
   1.100 - *                  )
   1.101 - *
   1.102 - *     Description: A &quot;VFREEBUSY&quot; calendar component is a grouping of
   1.103 - *     component properties that represents either a request for, a reply to
   1.104 - *     a request for free or busy time information or a published set of
   1.105 - *     busy time information.
   1.106 - *
   1.107 - *     When used to request free/busy time information, the &quot;ATTENDEE&quot;
   1.108 - *     property specifies the calendar users whose free/busy time is being
   1.109 - *     requested; the &quot;ORGANIZER&quot; property specifies the calendar user who
   1.110 - *     is requesting the free/busy time; the &quot;DTSTART&quot; and &quot;DTEND&quot;
   1.111 - *     properties specify the window of time for which the free/busy time is
   1.112 - *     being requested; the &quot;UID&quot; and &quot;DTSTAMP&quot; properties are specified to
   1.113 - *     assist in proper sequencing of multiple free/busy time requests.
   1.114 - *
   1.115 - *     When used to reply to a request for free/busy time, the &quot;ATTENDEE&quot;
   1.116 - *     property specifies the calendar user responding to the free/busy time
   1.117 - *     request; the &quot;ORGANIZER&quot; property specifies the calendar user that
   1.118 - *     originally requested the free/busy time; the &quot;FREEBUSY&quot; property
   1.119 - *     specifies the free/busy time information (if it exists); and the
   1.120 - *     &quot;UID&quot; and &quot;DTSTAMP&quot; properties are specified to assist in proper
   1.121 - *     sequencing of multiple free/busy time replies.
   1.122 - *
   1.123 - *     When used to publish busy time, the &quot;ORGANIZER&quot; property specifies
   1.124 - *     the calendar user associated with the published busy time; the
   1.125 - *     &quot;DTSTART&quot; and &quot;DTEND&quot; properties specify an inclusive time window
   1.126 - *     that surrounds the busy time information; the &quot;FREEBUSY&quot; property
   1.127 - *     specifies the published busy time information; and the &quot;DTSTAMP&quot;
   1.128 - *     property specifies the date/time that iCalendar object was created.
   1.129 - *
   1.130 - *     The &quot;VFREEBUSY&quot; calendar component cannot be nested within another
   1.131 - *     calendar component. Multiple &quot;VFREEBUSY&quot; calendar components can be
   1.132 - *     specified within an iCalendar object. This permits the grouping of
   1.133 - *     Free/Busy information into logical collections, such as monthly
   1.134 - *     groups of busy time information.
   1.135 - *
   1.136 - *     The &quot;VFREEBUSY&quot; calendar component is intended for use in iCalendar
   1.137 - *     object methods involving requests for free time, requests for busy
   1.138 - *     time, requests for both free and busy, and the associated replies.
   1.139 - *
   1.140 - *     Free/Busy information is represented with the &quot;FREEBUSY&quot; property.
   1.141 - *     This property provides a terse representation of time periods. One or
   1.142 - *     more &quot;FREEBUSY&quot; properties can be specified in the &quot;VFREEBUSY&quot;
   1.143 - *     calendar component.
   1.144 - *
   1.145 - *     When present in a &quot;VFREEBUSY&quot; calendar component, the &quot;DTSTART&quot; and
   1.146 - *     &quot;DTEND&quot; properties SHOULD be specified prior to any &quot;FREEBUSY&quot;
   1.147 - *     properties. In a free time request, these properties can be used in
   1.148 - *     combination with the &quot;DURATION&quot; property to represent a request for a
   1.149 - *     duration of free time within a specified window of time.
   1.150 - *
   1.151 - *     The recurrence properties (&quot;RRULE&quot;, &quot;EXRULE&quot;, &quot;RDATE&quot;, &quot;EXDATE&quot;) are
   1.152 - *     not permitted within a &quot;VFREEBUSY&quot; calendar component. Any recurring
   1.153 - *     events are resolved into their individual busy time periods using the
   1.154 - *     &quot;FREEBUSY&quot; property.
   1.155 - *
   1.156 - *     Example: The following is an example of a &quot;VFREEBUSY&quot; calendar
   1.157 - *     component used to request free or busy time information:
   1.158 - *
   1.159 - *       BEGIN:VFREEBUSY
   1.160 - *       ORGANIZER:MAILTO:jane_doe@host1.com
   1.161 - *       ATTENDEE:MAILTO:john_public@host2.com
   1.162 - *       DTSTART:19971015T050000Z
   1.163 - *       DTEND:19971016T050000Z
   1.164 - *       DTSTAMP:19970901T083000Z
   1.165 - *       END:VFREEBUSY
   1.166 - *
   1.167 - *     The following is an example of a &quot;VFREEBUSY&quot; calendar component used
   1.168 - *     to reply to the request with busy time information:
   1.169 - *
   1.170 - *       BEGIN:VFREEBUSY
   1.171 - *       ORGANIZER:MAILTO:jane_doe@host1.com
   1.172 - *       ATTENDEE:MAILTO:john_public@host2.com
   1.173 - *       DTSTAMP:19970901T100000Z
   1.174 - *       FREEBUSY;VALUE=PERIOD:19971015T050000Z/PT8H30M,
   1.175 - *        19971015T160000Z/PT5H30M,19971015T223000Z/PT6H30M
   1.176 - *       URL:http://host2.com/pub/busy/jpublic-01.ifb
   1.177 - *       COMMENT:This iCalendar file contains busy time information for
   1.178 - *         the next three months.
   1.179 - *       END:VFREEBUSY
   1.180 - *
   1.181 - *     The following is an example of a &quot;VFREEBUSY&quot; calendar component used
   1.182 - *     to publish busy time information.
   1.183 - *
   1.184 - *       BEGIN:VFREEBUSY
   1.185 - *       ORGANIZER:jsmith@host.com
   1.186 - *       DTSTART:19980313T141711Z
   1.187 - *       DTEND:19980410T141711Z
   1.188 - *       FREEBUSY:19980314T233000Z/19980315T003000Z
   1.189 - *       FREEBUSY:19980316T153000Z/19980316T163000Z
   1.190 - *       FREEBUSY:19980318T030000Z/19980318T040000Z
   1.191 - *       URL:http://www.host.com/calendar/busytime/jsmith.ifb
   1.192 - *       END:VFREEBUSY
   1.193 - * </pre>
   1.194 - *
   1.195 - * Example 1 - Requesting all busy time slots for a given period:
   1.196 - *
   1.197 - * <pre><code>
   1.198 - * // request all busy times between today and 1 week from now..
   1.199 - * DateTime start = new DateTime();
   1.200 - * DateTime end = new DateTime(start.getTime() + 1000 * 60 * 60 * 24 * 7);
   1.201 - *
   1.202 - * VFreeBusy request = new VFreeBusy(start, end);
   1.203 - *
   1.204 - * VFreeBusy reply = new VFreeBusy(request, calendar.getComponents());
   1.205 - * </code></pre>
   1.206 - *
   1.207 - * Example 2 - Requesting all free time slots for a given period of at least the specified duration:
   1.208 - *
   1.209 - * <pre><code>
   1.210 - * // request all free time between today and 1 week from now of
   1.211 - * // duration 2 hours or more..
   1.212 - * DateTime start = new DateTime();
   1.213 - * DateTime end = new DateTime(start.getTime() + 1000 * 60 * 60 * 24 * 7);
   1.214 - *
   1.215 - * VFreeBusy request = new VFreeBusy(start, end, new Dur(0, 2, 0, 0));
   1.216 - *
   1.217 - * VFreeBusy response = new VFreeBusy(request, myCalendar.getComponents());
   1.218 - * </code></pre>
   1.219 - *
   1.220 - * @author Ben Fortuna
   1.221 - */
   1.222 -public class VFreeBusy extends CalendarComponent {
   1.223 -
   1.224 -    private static final long serialVersionUID = 1046534053331139832L;
   1.225 -
   1.226 -    private final Map methodValidators = new HashMap();
   1.227 -    {
   1.228 -        methodValidators.put(Method.PUBLISH, new PublishValidator());
   1.229 -        methodValidators.put(Method.REPLY, new ReplyValidator());
   1.230 -        methodValidators.put(Method.REQUEST, new RequestValidator());
   1.231 -    }
   1.232 -    
   1.233 -    /**
   1.234 -     * Default constructor.
   1.235 -     */
   1.236 -    public VFreeBusy() {
   1.237 -        super(VFREEBUSY);
   1.238 -        getProperties().add(new DtStamp());
   1.239 -    }
   1.240 -
   1.241 -    /**
   1.242 -     * Constructor.
   1.243 -     * @param properties a list of properties
   1.244 -     */
   1.245 -    public VFreeBusy(final PropertyList properties) {
   1.246 -        super(VFREEBUSY, properties);
   1.247 -    }
   1.248 -
   1.249 -    /**
   1.250 -     * Constructs a new VFreeBusy instance with the specified start and end boundaries. This constructor should be used
   1.251 -     * for requesting busy time for a specified period.
   1.252 -     * @param start the starting boundary for the VFreeBusy
   1.253 -     * @param end the ending boundary for the VFreeBusy
   1.254 -     */
   1.255 -    public VFreeBusy(final DateTime start, final DateTime end) {
   1.256 -        this();
   1.257 -        
   1.258 -        // 4.8.2.4 Date/Time Start:
   1.259 -        //
   1.260 -        //    Within the "VFREEBUSY" calendar component, this property defines the
   1.261 -        //    start date and time for the free or busy time information. The time
   1.262 -        //    MUST be specified in UTC time.
   1.263 -        getProperties().add(new DtStart(start, true));
   1.264 -        
   1.265 -        // 4.8.2.2 Date/Time End
   1.266 -        //
   1.267 -        //    Within the "VFREEBUSY" calendar component, this property defines the
   1.268 -        //    end date and time for the free or busy time information. The time
   1.269 -        //    MUST be specified in the UTC time format. The value MUST be later in
   1.270 -        //    time than the value of the "DTSTART" property.
   1.271 -        getProperties().add(new DtEnd(end, true));
   1.272 -    }
   1.273 -
   1.274 -    /**
   1.275 -     * Constructs a new VFreeBusy instance with the specified start and end boundaries. This constructor should be used
   1.276 -     * for requesting free time for a specified duration in given period defined by the start date and end date.
   1.277 -     * @param start the starting boundary for the VFreeBusy
   1.278 -     * @param end the ending boundary for the VFreeBusy
   1.279 -     * @param duration the length of the period being requested
   1.280 -     */
   1.281 -    public VFreeBusy(final DateTime start, final DateTime end, final Dur duration) {
   1.282 -        this();
   1.283 -        
   1.284 -        // 4.8.2.4 Date/Time Start:
   1.285 -        //
   1.286 -        //    Within the "VFREEBUSY" calendar component, this property defines the
   1.287 -        //    start date and time for the free or busy time information. The time
   1.288 -        //    MUST be specified in UTC time.
   1.289 -        getProperties().add(new DtStart(start, true));
   1.290 -        
   1.291 -        // 4.8.2.2 Date/Time End
   1.292 -        //
   1.293 -        //    Within the "VFREEBUSY" calendar component, this property defines the
   1.294 -        //    end date and time for the free or busy time information. The time
   1.295 -        //    MUST be specified in the UTC time format. The value MUST be later in
   1.296 -        //    time than the value of the "DTSTART" property.
   1.297 -        getProperties().add(new DtEnd(end, true));
   1.298 -
   1.299 -        getProperties().add(new Duration(duration));
   1.300 -    }
   1.301 -
   1.302 -    /**
   1.303 -     * Constructs a new VFreeBusy instance representing a reply to the specified VFREEBUSY request according to the
   1.304 -     * specified list of components.
   1.305 -     * If the request argument has its duration set, then the result
   1.306 -     * represents a list of <em>free</em> times (that is, parameter FBTYPE
   1.307 -     * is set to FbType.FREE).
   1.308 -     * If the request argument does not have its duration set, then the result
   1.309 -     * represents a list of <em>busy</em> times.
   1.310 -     * @param request a VFREEBUSY request
   1.311 -     * @param components a component list used to initialise busy time
   1.312 -     * @throws ValidationException 
   1.313 -     */
   1.314 -    public VFreeBusy(final VFreeBusy request, final ComponentList components) {
   1.315 -        this();
   1.316 -        
   1.317 -        final DtStart start = (DtStart) request.getProperty(Property.DTSTART);
   1.318 -        
   1.319 -        final DtEnd end = (DtEnd) request.getProperty(Property.DTEND);
   1.320 -        
   1.321 -        final Duration duration = (Duration) request.getProperty(Property.DURATION);
   1.322 -        
   1.323 -        // 4.8.2.4 Date/Time Start:
   1.324 -        //
   1.325 -        //    Within the "VFREEBUSY" calendar component, this property defines the
   1.326 -        //    start date and time for the free or busy time information. The time
   1.327 -        //    MUST be specified in UTC time.
   1.328 -        getProperties().add(new DtStart(start.getDate(), true));
   1.329 -        
   1.330 -        // 4.8.2.2 Date/Time End
   1.331 -        //
   1.332 -        //    Within the "VFREEBUSY" calendar component, this property defines the
   1.333 -        //    end date and time for the free or busy time information. The time
   1.334 -        //    MUST be specified in the UTC time format. The value MUST be later in
   1.335 -        //    time than the value of the "DTSTART" property.
   1.336 -        getProperties().add(new DtEnd(end.getDate(), true));
   1.337 -        
   1.338 -        if (duration != null) {
   1.339 -            getProperties().add(new Duration(duration.getDuration()));
   1.340 -            // Initialise with all free time of at least the specified duration..
   1.341 -            final DateTime freeStart = new DateTime(start.getDate());
   1.342 -            final DateTime freeEnd = new DateTime(end.getDate());
   1.343 -            final FreeBusy fb = new FreeTimeBuilder().start(freeStart)
   1.344 -                .end(freeEnd)
   1.345 -                .duration(duration.getDuration())
   1.346 -                .components(components)
   1.347 -                .build();
   1.348 -            if (fb != null && !fb.getPeriods().isEmpty()) {
   1.349 -                getProperties().add(fb);
   1.350 -            }
   1.351 -        }
   1.352 -        else {
   1.353 -            // initialise with all busy time for the specified period..
   1.354 -            final DateTime busyStart = new DateTime(start.getDate());
   1.355 -            final DateTime busyEnd = new DateTime(end.getDate());
   1.356 -            final FreeBusy fb = new BusyTimeBuilder().start(busyStart)
   1.357 -                .end(busyEnd)
   1.358 -                .components(components)
   1.359 -                .build();
   1.360 -            if (fb != null && !fb.getPeriods().isEmpty()) {
   1.361 -                getProperties().add(fb);
   1.362 -            }
   1.363 -        }
   1.364 -    }
   1.365 -
   1.366 -    /**
   1.367 -     * Create a FREEBUSY property representing the busy time for the specified component list. If the component is not
   1.368 -     * applicable to FREEBUSY time, or if the component is outside the bounds of the start and end dates, null is
   1.369 -     * returned. If no valid busy periods are identified in the component an empty FREEBUSY property is returned (i.e.
   1.370 -     * empty period list).
   1.371 -     */
   1.372 -    private class BusyTimeBuilder {
   1.373 -        
   1.374 -        private DateTime start;
   1.375 -        
   1.376 -        private DateTime end;
   1.377 -        
   1.378 -        private ComponentList components;
   1.379 -        
   1.380 -        public BusyTimeBuilder start(DateTime start) {
   1.381 -            this.start = start;
   1.382 -            return this;
   1.383 -        }
   1.384 -        
   1.385 -        public BusyTimeBuilder end(DateTime end) {
   1.386 -            this.end = end;
   1.387 -            return this;
   1.388 -        }
   1.389 -        
   1.390 -        public BusyTimeBuilder components(ComponentList components) {
   1.391 -            this.components = components;
   1.392 -            return this;
   1.393 -        }
   1.394 -        
   1.395 -        public FreeBusy build() {
   1.396 -            final PeriodList periods = getConsumedTime(components, start, end);
   1.397 -            final DateRange range = new DateRange(start, end);
   1.398 -            // periods must be in UTC time for freebusy..
   1.399 -            periods.setUtc(true);
   1.400 -            for (final Iterator i = periods.iterator(); i.hasNext();) {
   1.401 -                final Period period = (Period) i.next();
   1.402 -                // check if period outside bounds..
   1.403 -                if (!range.intersects(period)) {
   1.404 -                    i.remove();
   1.405 -                }
   1.406 -            }
   1.407 -            return new FreeBusy(periods);
   1.408 -        }
   1.409 -    }
   1.410 -
   1.411 -    /**
   1.412 -     * Create a FREEBUSY property representing the free time available of the specified duration for the given list of
   1.413 -     * components. component. If the component is not applicable to FREEBUSY time, or if the component is outside the
   1.414 -     * bounds of the start and end dates, null is returned. If no valid busy periods are identified in the component an
   1.415 -     * empty FREEBUSY property is returned (i.e. empty period list).
   1.416 -     */
   1.417 -    private class FreeTimeBuilder {
   1.418 -        
   1.419 -        private DateTime start;
   1.420 -        
   1.421 -        private DateTime end;
   1.422 -        
   1.423 -        private Dur duration;
   1.424 -        
   1.425 -        private ComponentList components;
   1.426 -        
   1.427 -        public FreeTimeBuilder start(DateTime start) {
   1.428 -            this.start = start;
   1.429 -            return this;
   1.430 -        }
   1.431 -        
   1.432 -        public FreeTimeBuilder end(DateTime end) {
   1.433 -            this.end = end;
   1.434 -            return this;
   1.435 -        }
   1.436 -        
   1.437 -        private FreeTimeBuilder duration(Dur duration) {
   1.438 -            this.duration = duration;
   1.439 -            return this;
   1.440 -        }
   1.441 -        
   1.442 -        public FreeTimeBuilder components(ComponentList components) {
   1.443 -            this.components = components;
   1.444 -            return this;
   1.445 -        }
   1.446 -        
   1.447 -        public FreeBusy build() {
   1.448 -            final FreeBusy fb = new FreeBusy();
   1.449 -            fb.getParameters().add(FbType.FREE);
   1.450 -            final PeriodList periods = getConsumedTime(components, start, end);
   1.451 -            final DateRange range = new DateRange(start, end);
   1.452 -            // Add final consumed time to avoid special-case end-of-list processing
   1.453 -            periods.add(new Period(end, end));
   1.454 -            DateTime lastPeriodEnd = new DateTime(start);
   1.455 -            // where no time is consumed set the last period end as the range start..
   1.456 -            for (final Iterator i = periods.iterator(); i.hasNext();) {
   1.457 -                final Period period = (Period) i.next();
   1.458 -                
   1.459 -                // check if period outside bounds.. or period intersects with the end of the range..
   1.460 -                if (range.contains(period) || 
   1.461 -                		(range.intersects(period) && period.getStart().after(range.getRangeStart()))) {
   1.462 -                    
   1.463 -                    // calculate duration between this period start and last period end..
   1.464 -                    final Duration freeDuration = new Duration(lastPeriodEnd, period.getStart());
   1.465 -                    if (freeDuration.getDuration().compareTo(duration) >= 0) {
   1.466 -                        fb.getPeriods().add(new Period(lastPeriodEnd, freeDuration.getDuration()));
   1.467 -                    }
   1.468 -                }
   1.469 -                
   1.470 -                if (period.getEnd().after(lastPeriodEnd)) {
   1.471 -                    lastPeriodEnd = period.getEnd();
   1.472 -                }
   1.473 -            }
   1.474 -            return fb;
   1.475 -        }
   1.476 -    }
   1.477 -
   1.478 -    /**
   1.479 -     * Creates a list of periods representing the time consumed by the specified list of components.
   1.480 -     * @param components
   1.481 -     * @return
   1.482 -     */
   1.483 -    private PeriodList getConsumedTime(final ComponentList components, final DateTime rangeStart,
   1.484 -            final DateTime rangeEnd) {
   1.485 -        
   1.486 -        final PeriodList periods = new PeriodList();
   1.487 -        // only events consume time..
   1.488 -        for (final Iterator i = components.getComponents(Component.VEVENT).iterator(); i.hasNext();) {
   1.489 -            final Component component = (Component) i.next();
   1.490 -            periods.addAll(((VEvent) component).getConsumedTime(rangeStart, rangeEnd, false));
   1.491 -        }
   1.492 -        return periods.normalise();
   1.493 -    }
   1.494 -
   1.495 -    /**
   1.496 -     * {@inheritDoc}
   1.497 -     */
   1.498 -    public final void validate(final boolean recurse) throws ValidationException {
   1.499 -
   1.500 -        if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) {
   1.501 -
   1.502 -            // From "4.8.4.7 Unique Identifier":
   1.503 -            // Conformance: The property MUST be specified in the "VEVENT", "VTODO",
   1.504 -            // "VJOURNAL" or "VFREEBUSY" calendar components.
   1.505 -            PropertyValidator.getInstance().assertOne(Property.UID,
   1.506 -                    getProperties());
   1.507 -
   1.508 -            // From "4.8.7.2 Date/Time Stamp":
   1.509 -            // Conformance: This property MUST be included in the "VEVENT", "VTODO",
   1.510 -            // "VJOURNAL" or "VFREEBUSY" calendar components.
   1.511 -            PropertyValidator.getInstance().assertOne(Property.DTSTAMP,
   1.512 -                    getProperties());
   1.513 -        }
   1.514 -
   1.515 -        final PropertyValidator validator = PropertyValidator.getInstance();
   1.516 -
   1.517 -        /*
   1.518 -         * ; the following are optional, ; but MUST NOT occur more than once contact / dtstart / dtend / duration /
   1.519 -         * dtstamp / organizer / uid / url /
   1.520 -         */
   1.521 -        validator.assertOneOrLess(Property.CONTACT, getProperties());
   1.522 -        validator.assertOneOrLess(Property.DTSTART, getProperties());
   1.523 -        validator.assertOneOrLess(Property.DTEND, getProperties());
   1.524 -        validator.assertOneOrLess(Property.DURATION, getProperties());
   1.525 -        validator.assertOneOrLess(Property.DTSTAMP, getProperties());
   1.526 -        validator.assertOneOrLess(Property.ORGANIZER, getProperties());
   1.527 -        validator.assertOneOrLess(Property.UID, getProperties());
   1.528 -        validator.assertOneOrLess(Property.URL, getProperties());
   1.529 -
   1.530 -        /*
   1.531 -         * ; the following are optional, ; and MAY occur more than once attendee / comment / freebusy / rstatus / x-prop
   1.532 -         */
   1.533 -
   1.534 -        /*
   1.535 -         * The recurrence properties ("RRULE", "EXRULE", "RDATE", "EXDATE") are not permitted within a "VFREEBUSY"
   1.536 -         * calendar component. Any recurring events are resolved into their individual busy time periods using the
   1.537 -         * "FREEBUSY" property.
   1.538 -         */
   1.539 -        validator.assertNone(Property.RRULE, getProperties());
   1.540 -        validator.assertNone(Property.EXRULE, getProperties());
   1.541 -        validator.assertNone(Property.RDATE, getProperties());
   1.542 -        validator.assertNone(Property.EXDATE, getProperties());
   1.543 -
   1.544 -        // DtEnd value must be later in time that DtStart..
   1.545 -        final DtStart dtStart = (DtStart) getProperty(Property.DTSTART);
   1.546 -        
   1.547 -        // 4.8.2.4 Date/Time Start:
   1.548 -        //
   1.549 -        //    Within the "VFREEBUSY" calendar component, this property defines the
   1.550 -        //    start date and time for the free or busy time information. The time
   1.551 -        //    MUST be specified in UTC time.
   1.552 -        if (dtStart != null && !dtStart.isUtc()) {
   1.553 -            throw new ValidationException("DTSTART must be specified in UTC time");
   1.554 -        }
   1.555 -        
   1.556 -        final DtEnd dtEnd = (DtEnd) getProperty(Property.DTEND);
   1.557 -        
   1.558 -        // 4.8.2.2 Date/Time End
   1.559 -        //
   1.560 -        //    Within the "VFREEBUSY" calendar component, this property defines the
   1.561 -        //    end date and time for the free or busy time information. The time
   1.562 -        //    MUST be specified in the UTC time format. The value MUST be later in
   1.563 -        //    time than the value of the "DTSTART" property.
   1.564 -        if (dtEnd != null && !dtEnd.isUtc()) {
   1.565 -            throw new ValidationException("DTEND must be specified in UTC time");
   1.566 -        }
   1.567 -        
   1.568 -        if (dtStart != null && dtEnd != null
   1.569 -                && !dtStart.getDate().before(dtEnd.getDate())) {
   1.570 -            throw new ValidationException("Property [" + Property.DTEND
   1.571 -                    + "] must be later in time than [" + Property.DTSTART + "]");
   1.572 -        }
   1.573 -
   1.574 -        if (recurse) {
   1.575 -            validateProperties();
   1.576 -        }
   1.577 -    }
   1.578 -
   1.579 -    /**
   1.580 -     * {@inheritDoc}
   1.581 -     */
   1.582 -    protected Validator getValidator(Method method) {
   1.583 -        return (Validator) methodValidators.get(method);
   1.584 -    }
   1.585 -
   1.586 -    /**
   1.587 -     * <pre>
   1.588 -     * Component/Property  Presence
   1.589 -     * ------------------- ----------------------------------------------
   1.590 -     * METHOD              1       MUST be "PUBLISH"
   1.591 -     * 
   1.592 -     * VFREEBUSY           1+
   1.593 -     *     DTSTAMP         1
   1.594 -     *     DTSTART         1       DateTime values must be in UTC
   1.595 -     *     DTEND           1       DateTime values must be in UTC
   1.596 -     *     FREEBUSY        1+      MUST be BUSYTIME. Multiple instances are
   1.597 -     *                             allowed. Multiple instances must be sorted
   1.598 -     *                             in ascending order
   1.599 -     *     ORGANIZER       1       MUST contain the address of originator of
   1.600 -     *                             busy time data.
   1.601 -     *     UID             1
   1.602 -     *     COMMENT         0 or 1
   1.603 -     *     CONTACT         0+
   1.604 -     *     X-PROPERTY      0+
   1.605 -     *     URL             0 or 1  Specifies busy time URL
   1.606 -     * 
   1.607 -     *     ATTENDEE        0
   1.608 -     *     DURATION        0
   1.609 -     *     REQUEST-STATUS  0
   1.610 -     * 
   1.611 -     * X-COMPONENT         0+
   1.612 -     * 
   1.613 -     * VEVENT              0
   1.614 -     * VTODO               0
   1.615 -     * VJOURNAL            0
   1.616 -     * VTIMEZONE           0
   1.617 -     * VALARM              0
   1.618 -     * </pre>
   1.619 -     * 
   1.620 -     */
   1.621 -    private class PublishValidator implements Validator {
   1.622 -        
   1.623 -		private static final long serialVersionUID = 1L;
   1.624 - 
   1.625 -        public void validate() throws ValidationException {
   1.626 -            PropertyValidator.getInstance().assertOneOrMore(Property.FREEBUSY, getProperties());
   1.627 -            
   1.628 -            PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
   1.629 -            PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties());
   1.630 -            PropertyValidator.getInstance().assertOne(Property.DTEND, getProperties());
   1.631 -            PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
   1.632 -            PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
   1.633 -            
   1.634 -            PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties());
   1.635 -            
   1.636 -            PropertyValidator.getInstance().assertNone(Property.ATTENDEE, getProperties());
   1.637 -            PropertyValidator.getInstance().assertNone(Property.DURATION, getProperties());
   1.638 -            PropertyValidator.getInstance().assertNone(Property.REQUEST_STATUS, getProperties());
   1.639 -        }
   1.640 -    }
   1.641 -    
   1.642 -    /**
   1.643 -     * <pre>
   1.644 -     * Component/Property  Presence
   1.645 -     * ------------------- ----------------------------------------------
   1.646 -     * METHOD              1      MUST be "REPLY"
   1.647 -     * 
   1.648 -     * VFREEBUSY           1
   1.649 -     *     ATTENDEE        1      (address of recipient replying)
   1.650 -     *     DTSTAMP         1
   1.651 -     *     DTEND           1      DateTime values must be in UTC
   1.652 -     *     DTSTART         1      DateTime values must be in UTC
   1.653 -     *     FREEBUSY        0+      (values MUST all be of the same data
   1.654 -     *                             type. Multiple instances are allowed.
   1.655 -     *                             Multiple instances MUST be sorted in
   1.656 -     *                             ascending order. Values MAY NOT overlap)
   1.657 -     *     ORGANIZER       1       MUST be the request originator's address
   1.658 -     *     UID             1
   1.659 -     * 
   1.660 -     *     COMMENT         0 or 1
   1.661 -     *     CONTACT         0+
   1.662 -     *     REQUEST-STATUS  0+
   1.663 -     *     URL             0 or 1  (specifies busy time URL)
   1.664 -     *     X-PROPERTY      0+
   1.665 -     *     DURATION        0
   1.666 -     *     SEQUENCE        0
   1.667 -     * 
   1.668 -     * X-COMPONENT         0+
   1.669 -     * VALARM              0
   1.670 -     * VEVENT              0
   1.671 -     * VTODO               0
   1.672 -     * VJOURNAL            0
   1.673 -     * VTIMEZONE           0
   1.674 -     * </pre>
   1.675 -     * 
   1.676 -     */
   1.677 -    private class ReplyValidator implements Validator {
   1.678 -        
   1.679 -		private static final long serialVersionUID = 1L;
   1.680 -
   1.681 -        public void validate() throws ValidationException {
   1.682 -
   1.683 -            // FREEBUSY is 1+ in RFC2446 but 0+ in Calsify
   1.684 -            
   1.685 -            PropertyValidator.getInstance().assertOne(Property.ATTENDEE, getProperties());
   1.686 -            PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
   1.687 -            PropertyValidator.getInstance().assertOne(Property.DTEND, getProperties());
   1.688 -            PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties());
   1.689 -            PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
   1.690 -            PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
   1.691 -            
   1.692 -            PropertyValidator.getInstance().assertOneOrLess(Property.URL, getProperties());
   1.693 -            
   1.694 -            PropertyValidator.getInstance().assertNone(Property.DURATION, getProperties());
   1.695 -            PropertyValidator.getInstance().assertNone(Property.SEQUENCE, getProperties());
   1.696 -        }
   1.697 -    }
   1.698 -    
   1.699 -    /**
   1.700 -     * METHOD:REQUEST Validator.
   1.701 -     * 
   1.702 -     * <pre>
   1.703 -     * Component/Property  Presence
   1.704 -     * ------------------- ----------------------------------------------
   1.705 -     * METHOD              1      MUST be "REQUEST"
   1.706 -     * 
   1.707 -     * VFREEBUSY           1
   1.708 -     *     ATTENDEE        1+     contain the address of the calendar store
   1.709 -     *     DTEND           1      DateTime values must be in UTC
   1.710 -     *     DTSTAMP         1
   1.711 -     *     DTSTART         1      DateTime values must be in UTC
   1.712 -     *     ORGANIZER       1      MUST be the request originator's address
   1.713 -     *     UID             1
   1.714 -     *     COMMENT         0 or 1
   1.715 -     *     CONTACT         0+
   1.716 -     *     X-PROPERTY      0+
   1.717 -     * 
   1.718 -     *     FREEBUSY        0
   1.719 -     *     DURATION        0
   1.720 -     *     REQUEST-STATUS  0
   1.721 -     *     URL             0
   1.722 -     * 
   1.723 -     * X-COMPONENT         0+
   1.724 -     * VALARM              0
   1.725 -     * VEVENT              0
   1.726 -     * VTODO               0
   1.727 -     * VJOURNAL            0
   1.728 -     * VTIMEZONE           0
   1.729 -     * </pre>
   1.730 -     * 
   1.731 -     */
   1.732 -    private class RequestValidator implements Validator {
   1.733 -        
   1.734 -		private static final long serialVersionUID = 1L;
   1.735 -
   1.736 -        public void validate() throws ValidationException {
   1.737 -            PropertyValidator.getInstance().assertOneOrMore(Property.ATTENDEE, getProperties());
   1.738 -            
   1.739 -            PropertyValidator.getInstance().assertOne(Property.DTEND, getProperties());
   1.740 -            PropertyValidator.getInstance().assertOne(Property.DTSTAMP, getProperties());
   1.741 -            PropertyValidator.getInstance().assertOne(Property.DTSTART, getProperties());
   1.742 -            PropertyValidator.getInstance().assertOne(Property.ORGANIZER, getProperties());
   1.743 -            PropertyValidator.getInstance().assertOne(Property.UID, getProperties());
   1.744 -            
   1.745 -            PropertyValidator.getInstance().assertNone(Property.FREEBUSY, getProperties());
   1.746 -            PropertyValidator.getInstance().assertNone(Property.DURATION, getProperties());
   1.747 -            PropertyValidator.getInstance().assertNone(Property.REQUEST_STATUS, getProperties());
   1.748 -            PropertyValidator.getInstance().assertNone(Property.URL, getProperties());
   1.749 -        }
   1.750 -    }
   1.751 -    
   1.752 -    /**
   1.753 -     * @return the CONTACT property or null if not specified
   1.754 -     */
   1.755 -    public final Contact getContact() {
   1.756 -        return (Contact) getProperty(Property.CONTACT);
   1.757 -    }
   1.758 -
   1.759 -    /**
   1.760 -     * @return the DTSTART propery or null if not specified
   1.761 -     */
   1.762 -    public final DtStart getStartDate() {
   1.763 -        return (DtStart) getProperty(Property.DTSTART);
   1.764 -    }
   1.765 -
   1.766 -    /**
   1.767 -     * @return the DTEND property or null if not specified
   1.768 -     */
   1.769 -    public final DtEnd getEndDate() {
   1.770 -        return (DtEnd) getProperty(Property.DTEND);
   1.771 -    }
   1.772 -
   1.773 -    /**
   1.774 -     * @return the DURATION property or null if not specified
   1.775 -     */
   1.776 -    public final Duration getDuration() {
   1.777 -        return (Duration) getProperty(Property.DURATION);
   1.778 -    }
   1.779 -
   1.780 -    /**
   1.781 -     * @return the DTSTAMP property or null if not specified
   1.782 -     */
   1.783 -    public final DtStamp getDateStamp() {
   1.784 -        return (DtStamp) getProperty(Property.DTSTAMP);
   1.785 -    }
   1.786 -
   1.787 -    /**
   1.788 -     * @return the ORGANIZER property or null if not specified
   1.789 -     */
   1.790 -    public final Organizer getOrganizer() {
   1.791 -        return (Organizer) getProperty(Property.ORGANIZER);
   1.792 -    }
   1.793 -
   1.794 -    /**
   1.795 -     * @return the URL property or null if not specified
   1.796 -     */
   1.797 -    public final Url getUrl() {
   1.798 -        return (Url) getProperty(Property.URL);
   1.799 -    }
   1.800 -
   1.801 -    /**
   1.802 -     * Returns the UID property of this component if available.
   1.803 -     * @return a Uid instance, or null if no UID property exists
   1.804 -     */
   1.805 -    public final Uid getUid() {
   1.806 -        return (Uid) getProperty(Property.UID);
   1.807 -    }
   1.808 -}

mercurial