public final void validate(final boolean recurse) throws ValidationException {

        if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) {

            // From "4.8.4.7 Unique Identifier":
            // Conformance: The property MUST be specified in the "VEVENT", "VTODO",
            // "VJOURNAL" or "VFREEBUSY" calendar components.
            PropertyValidator.getInstance().assertOne(Property.UID,
                    getProperties());

            // From "4.8.7.2 Date/Time Stamp":
            // Conformance: This property MUST be included in the "VEVENT", "VTODO",
            // "VJOURNAL" or "VFREEBUSY" calendar components.
            PropertyValidator.getInstance().assertOne(Property.DTSTAMP,
                    getProperties());
        }

        /*
         * ; the following are optional, ; but MUST NOT occur more than once contact / dtstart / dtend / duration /
         * dtstamp / organizer / uid / url /
         */
        Arrays.asList(Property.CONTACT, Property.DTSTART, Property.DTEND, Property.DURATION,
                Property.DTSTAMP, Property.ORGANIZER, Property.UID, Property.URL).forEach(parameter -> PropertyValidator.getInstance().assertOneOrLess(parameter, getProperties()));

        /*
         * ; the following are optional, ; and MAY occur more than once attendee / comment / freebusy / rstatus / x-prop
         */

        /*
         * The recurrence properties ("RRULE", "EXRULE", "RDATE", "EXDATE") are not permitted within a "VFREEBUSY"
         * calendar component. Any recurring events are resolved into their individual busy time periods using the
         * "FREEBUSY" property.
         */
        Arrays.asList(Property.RRULE, Property.EXRULE, Property.RDATE, Property.EXDATE).forEach(property -> PropertyValidator.getInstance().assertNone(property, getProperties()));

        // DtEnd value must be later in time that DtStart..
        final DtStart dtStart = getProperty(Property.DTSTART);
        
        // 4.8.2.4 Date/Time Start:
        //
        //    Within the "VFREEBUSY" calendar component, this property defines the
        //    start date and time for the free or busy time information. The time
        //    MUST be specified in UTC time.
        if (dtStart != null && !dtStart.isUtc()) {
            throw new ValidationException("DTSTART must be specified in UTC time");
        }
        
        final DtEnd dtEnd = getProperty(Property.DTEND);
        
        // 4.8.2.2 Date/Time End
        //
        //    Within the "VFREEBUSY" calendar component, this property defines the
        //    end date and time for the free or busy time information. The time
        //    MUST be specified in the UTC time format. The value MUST be later in
        //    time than the value of the "DTSTART" property.
        if (dtEnd != null && !dtEnd.isUtc()) {
            throw new ValidationException("DTEND must be specified in UTC time");
        }
        
        if (dtStart != null && dtEnd != null
                && !dtStart.getDate().before(dtEnd.getDate())) {
            throw new ValidationException("Property [" + Property.DTEND
                    + "] must be later in time than [" + Property.DTSTART + "]");
        }

        if (recurse) {
            validateProperties();
        }
    }
public final void validate ( final boolean recurse ) throws ValidationException { if ( ! CompatibilityHints . isHintEnabled ( CompatibilityHints . KEY_RELAXED_VALIDATION ) ) { PropertyValidator . getInstance ( ) . assertOne ( Property . UID , getProperties ( ) ) ; PropertyValidator . getInstance ( ) . assertOne ( Property . DTSTAMP , getProperties ( ) ) ; } Arrays . asList ( Property . CONTACT , Property . DTSTART , Property . DTEND , Property . DURATION , Property . DTSTAMP , Property . ORGANIZER , Property . UID , Property . URL ) . forEach ( parameter -> PropertyValidator . getInstance ( ) . assertOneOrLess ( parameter , getProperties ( ) ) ) ; Arrays . asList ( Property . RRULE , Property . EXRULE , Property . RDATE , Property . EXDATE ) . forEach ( property -> PropertyValidator . getInstance ( ) . assertNone ( property , getProperties ( ) ) ) ; final DtStart dtStart = getProperty ( Property . DTSTART ) ; if ( dtStart != null && ! dtStart . isUtc ( ) ) { throw new ValidationException ( "DTSTART must be specified in UTC time" ) ; } final DtEnd dtEnd = getProperty ( Property . DTEND ) ; if ( dtEnd != null && ! dtEnd . isUtc ( ) ) { throw new ValidationException ( "DTEND must be specified in UTC time" ) ; } if ( dtStart != null && dtEnd != null && ! dtStart . getDate ( ) . before ( dtEnd . getDate ( ) ) ) { throw new ValidationException ( "Property [" + Property . DTEND + "] must be later in time than [" + Property . DTSTART + "]" ) ; } if ( recurse ) { validateProperties ( ) ; } }
{@inheritDoc}