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

        // validate that getAlarms() only contains VAlarm components
        for (VAlarm component : getAlarms()) {
            component.validate(recurse);
        }

        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 class / completed / created / description /
         * dtstamp / dtstart / geo / last-mod / location / organizer / percent / priority / recurid / seq / status /
         * summary / uid / url /
         */
        Arrays.asList(Property.CLASS, Property.COMPLETED, Property.CREATED, Property.DESCRIPTION,
                Property.DTSTAMP, Property.DTSTART, Property.GEO, Property.LAST_MODIFIED, Property.LOCATION, Property.ORGANIZER,
                Property.PERCENT_COMPLETE, Property.PRIORITY, Property.RECURRENCE_ID, Property.SEQUENCE, Property.STATUS,
                Property.SUMMARY, Property.UID, Property.URL).forEach(property -> PropertyValidator.getInstance().assertOneOrLess(property, getProperties()));

        final Status status = getProperty(Property.STATUS);
        if (status != null && !Status.VTODO_NEEDS_ACTION.getValue().equals(status.getValue())
                && !Status.VTODO_COMPLETED.getValue().equals(status.getValue())
                && !Status.VTODO_IN_PROCESS.getValue().equals(status.getValue())
                && !Status.VTODO_CANCELLED.getValue().equals(status.getValue())) {
            throw new ValidationException("Status property ["
                    + status.toString() + "] may not occur in VTODO");
        }

        /*
         * ; either 'due' or 'duration' may appear in ; a 'todoprop', but 'due' and 'duration' ; MUST NOT occur in the
         * same 'todoprop' due / duration /
         */
        try {
            PropertyValidator.getInstance().assertNone(Property.DUE,
                    getProperties());
        }
        catch (ValidationException ve) {
            PropertyValidator.getInstance().assertNone(Property.DURATION,
                    getProperties());
        }

        /*
         * ; the following are optional, ; and MAY occur more than once attach / attendee / categories / comment /
         * contact / exdate / exrule / rstatus / related / resources / rdate / rrule / x-prop
         */

        if (recurse) {
            validateProperties();
        }
    }
public final void validate ( final boolean recurse ) throws ValidationException { for ( VAlarm component : getAlarms ( ) ) { component . validate ( recurse ) ; } if ( ! CompatibilityHints . isHintEnabled ( CompatibilityHints . KEY_RELAXED_VALIDATION ) ) { PropertyValidator . getInstance ( ) . assertOne ( Property . UID , getProperties ( ) ) ; PropertyValidator . getInstance ( ) . assertOne ( Property . DTSTAMP , getProperties ( ) ) ; } Arrays . asList ( Property . CLASS , Property . COMPLETED , Property . CREATED , Property . DESCRIPTION , Property . DTSTAMP , Property . DTSTART , Property . GEO , Property . LAST_MODIFIED , Property . LOCATION , Property . ORGANIZER , Property . PERCENT_COMPLETE , Property . PRIORITY , Property . RECURRENCE_ID , Property . SEQUENCE , Property . STATUS , Property . SUMMARY , Property . UID , Property . URL ) . forEach ( property -> PropertyValidator . getInstance ( ) . assertOneOrLess ( property , getProperties ( ) ) ) ; final Status status = getProperty ( Property . STATUS ) ; if ( status != null && ! Status . VTODO_NEEDS_ACTION . getValue ( ) . equals ( status . getValue ( ) ) && ! Status . VTODO_COMPLETED . getValue ( ) . equals ( status . getValue ( ) ) && ! Status . VTODO_IN_PROCESS . getValue ( ) . equals ( status . getValue ( ) ) && ! Status . VTODO_CANCELLED . getValue ( ) . equals ( status . getValue ( ) ) ) { throw new ValidationException ( "Status property [" + status . toString ( ) + "] may not occur in VTODO" ) ; } try { PropertyValidator . getInstance ( ) . assertNone ( Property . DUE , getProperties ( ) ) ; } catch ( ValidationException ve ) { PropertyValidator . getInstance ( ) . assertNone ( Property . DURATION , getProperties ( ) ) ; } if ( recurse ) { validateProperties ( ) ; } }
{@inheritDoc}