michael@0: /** michael@0: * Copyright (c) 2012, Ben Fortuna michael@0: * All rights reserved. michael@0: * michael@0: * Redistribution and use in source and binary forms, with or without michael@0: * modification, are permitted provided that the following conditions michael@0: * are met: michael@0: * michael@0: * o Redistributions of source code must retain the above copyright michael@0: * notice, this list of conditions and the following disclaimer. michael@0: * michael@0: * o Redistributions in binary form must reproduce the above copyright michael@0: * notice, this list of conditions and the following disclaimer in the michael@0: * documentation and/or other materials provided with the distribution. michael@0: * michael@0: * o Neither the name of Ben Fortuna nor the names of any other contributors michael@0: * may be used to endorse or promote products derived from this software michael@0: * without specific prior written permission. michael@0: * michael@0: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR michael@0: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, michael@0: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, michael@0: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR michael@0: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF michael@0: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING michael@0: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS michael@0: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: */ michael@0: package net.fortuna.ical4j.model.component; michael@0: michael@0: import java.util.HashMap; michael@0: import java.util.Map; michael@0: michael@0: import net.fortuna.ical4j.model.DateTime; michael@0: import net.fortuna.ical4j.model.Dur; michael@0: import net.fortuna.ical4j.model.Property; michael@0: import net.fortuna.ical4j.model.PropertyList; michael@0: import net.fortuna.ical4j.model.ValidationException; michael@0: import net.fortuna.ical4j.model.Validator; michael@0: import net.fortuna.ical4j.model.property.Action; michael@0: import net.fortuna.ical4j.model.property.Attach; michael@0: import net.fortuna.ical4j.model.property.Description; michael@0: import net.fortuna.ical4j.model.property.Duration; michael@0: import net.fortuna.ical4j.model.property.Method; michael@0: import net.fortuna.ical4j.model.property.Repeat; michael@0: import net.fortuna.ical4j.model.property.Summary; michael@0: import net.fortuna.ical4j.model.property.Trigger; michael@0: import net.fortuna.ical4j.util.PropertyValidator; michael@0: michael@0: /** michael@0: * $Id$ [Apr 5, 2004] michael@0: * michael@0: * Defines an iCalendar VALARM component. michael@0: * michael@0: *
michael@0: * 4.6.6 Alarm Component michael@0: * michael@0: * Component Name: VALARM michael@0: * michael@0: * Purpose: Provide a grouping of component properties that define an michael@0: * alarm. michael@0: * michael@0: * Formal Definition: A "VALARM" calendar component is defined by the michael@0: * following notation: michael@0: * michael@0: * alarmc = "BEGIN" ":" "VALARM" CRLF michael@0: * (audioprop / dispprop / emailprop / procprop) michael@0: * "END" ":" "VALARM" CRLF michael@0: * michael@0: * audioprop = 2*( michael@0: * michael@0: * ; 'action' and 'trigger' are both REQUIRED, michael@0: * ; but MUST NOT occur more than once michael@0: * michael@0: * action / trigger / michael@0: * michael@0: * ; 'duration' and 'repeat' are both optional, michael@0: * ; and MUST NOT occur more than once each, michael@0: * ; but if one occurs, so MUST the other michael@0: * michael@0: * duration / repeat / michael@0: * michael@0: * ; the following is optional, michael@0: * ; but MUST NOT occur more than once michael@0: * michael@0: * attach / michael@0: * michael@0: * ; the following is optional, michael@0: * ; and MAY occur more than once michael@0: * michael@0: * x-prop michael@0: * michael@0: * ) michael@0: * michael@0: * michael@0: * michael@0: * dispprop = 3*( michael@0: * michael@0: * ; the following are all REQUIRED, michael@0: * ; but MUST NOT occur more than once michael@0: * michael@0: * action / description / trigger / michael@0: * michael@0: * ; 'duration' and 'repeat' are both optional, michael@0: * ; and MUST NOT occur more than once each, michael@0: * ; but if one occurs, so MUST the other michael@0: * michael@0: * duration / repeat / michael@0: * michael@0: * ; the following is optional, michael@0: * ; and MAY occur more than once michael@0: * michael@0: * *x-prop michael@0: * michael@0: * ) michael@0: * michael@0: * michael@0: * michael@0: * emailprop = 5*( michael@0: * michael@0: * ; the following are all REQUIRED, michael@0: * ; but MUST NOT occur more than once michael@0: * michael@0: * action / description / trigger / summary michael@0: * michael@0: * ; the following is REQUIRED, michael@0: * ; and MAY occur more than once michael@0: * michael@0: * attendee / michael@0: * michael@0: * ; 'duration' and 'repeat' are both optional, michael@0: * ; and MUST NOT occur more than once each, michael@0: * ; but if one occurs, so MUST the other michael@0: * michael@0: * duration / repeat / michael@0: * michael@0: * ; the following are optional, michael@0: * ; and MAY occur more than once michael@0: * michael@0: * attach / x-prop michael@0: * michael@0: * ) michael@0: * michael@0: * michael@0: * michael@0: * procprop = 3*( michael@0: * michael@0: * ; the following are all REQUIRED, michael@0: * ; but MUST NOT occur more than once michael@0: * michael@0: * action / attach / trigger / michael@0: * michael@0: * ; 'duration' and 'repeat' are both optional, michael@0: * ; and MUST NOT occur more than once each, michael@0: * ; but if one occurs, so MUST the other michael@0: * michael@0: * duration / repeat / michael@0: * michael@0: * ; 'description' is optional, michael@0: * ; and MUST NOT occur more than once michael@0: * michael@0: * description / michael@0: * michael@0: * ; the following is optional, michael@0: * ; and MAY occur more than once michael@0: * michael@0: * x-prop michael@0: * michael@0: * ) michael@0: *michael@0: * michael@0: * Example 1 - Creating an alarm to trigger at a specific time: michael@0: * michael@0: *
michael@0: * java.util.Calendar cal = java.util.Calendar.getInstance();
michael@0: * cal.set(java.util.Calendar.MONTH, java.util.Calendar.DECEMBER);
michael@0: * cal.set(java.util.Calendar.DAY_OF_MONTH, 25);
michael@0: *
michael@0: * VAlarm christmas = new VAlarm(cal.getTime());
michael@0: *
michael@0: *
michael@0: * Example 2 - Creating an alarm to trigger one (1) hour before the scheduled start of the parent event/the parent todo
michael@0: * is due:
michael@0: *
michael@0: *
michael@0: * VAlarm reminder = new VAlarm(new Dur(0, -1, 0, 0));
michael@0: *
michael@0: * // repeat reminder four (4) more times every fifteen (15) minutes..
michael@0: * reminder.getProperties().add(new Repeat(4));
michael@0: * reminder.getProperties().add(new Duration(new Dur(0, 0, 15, 0)));
michael@0: *
michael@0: * // display a message..
michael@0: * reminder.getProperties().add(Action.DISPLAY);
michael@0: * reminder.getProperties().add(new Description("Progress Meeting at 9:30am"));
michael@0: *
michael@0: *
michael@0: * @author Ben Fortuna
michael@0: */
michael@0: public class VAlarm extends CalendarComponent {
michael@0:
michael@0: private static final long serialVersionUID = -8193965477414653802L;
michael@0:
michael@0: private final Map actionValidators = new HashMap();
michael@0: {
michael@0: actionValidators.put(Action.AUDIO, new AudioValidator());
michael@0: actionValidators.put(Action.DISPLAY, new DisplayValidator());
michael@0: actionValidators.put(Action.EMAIL, new EmailValidator());
michael@0: actionValidators.put(Action.PROCEDURE, new ProcedureValidator());
michael@0: }
michael@0:
michael@0: private final Validator itipValidator = new ITIPValidator();
michael@0:
michael@0: /**
michael@0: * Default constructor.
michael@0: */
michael@0: public VAlarm() {
michael@0: super(VALARM);
michael@0: }
michael@0:
michael@0: /**
michael@0: * Constructor.
michael@0: * @param properties a list of properties
michael@0: */
michael@0: public VAlarm(final PropertyList properties) {
michael@0: super(VALARM, properties);
michael@0: }
michael@0:
michael@0: /**
michael@0: * Constructs a new VALARM instance that will trigger at the specified time.
michael@0: * @param trigger the time the alarm will trigger
michael@0: */
michael@0: public VAlarm(final DateTime trigger) {
michael@0: this();
michael@0: getProperties().add(new Trigger(trigger));
michael@0: }
michael@0:
michael@0: /**
michael@0: * Constructs a new VALARM instance that will trigger at the specified time relative to the event/todo component.
michael@0: * @param trigger a duration of time relative to the parent component that the alarm will trigger at
michael@0: */
michael@0: public VAlarm(final Dur trigger) {
michael@0: this();
michael@0: getProperties().add(new Trigger(trigger));
michael@0: }
michael@0:
michael@0: /**
michael@0: * {@inheritDoc}
michael@0: */
michael@0: public final void validate(final boolean recurse)
michael@0: throws ValidationException {
michael@0:
michael@0: /*
michael@0: * ; 'action' and 'trigger' are both REQUIRED, ; but MUST NOT occur more than once action / trigger /
michael@0: */
michael@0: PropertyValidator.getInstance().assertOne(Property.ACTION, getProperties());
michael@0: PropertyValidator.getInstance().assertOne(Property.TRIGGER, getProperties());
michael@0:
michael@0: /*
michael@0: * ; 'duration' and 'repeat' are both optional, ; and MUST NOT occur more than once each, ; but if one occurs,
michael@0: * so MUST the other duration / repeat /
michael@0: */
michael@0: PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties());
michael@0: PropertyValidator.getInstance().assertOneOrLess(Property.REPEAT, getProperties());
michael@0:
michael@0: try {
michael@0: PropertyValidator.getInstance().assertNone(Property.DURATION, getProperties());
michael@0: PropertyValidator.getInstance().assertNone(Property.REPEAT, getProperties());
michael@0: }
michael@0: catch (ValidationException ve) {
michael@0: PropertyValidator.getInstance().assertOne(Property.DURATION, getProperties());
michael@0: PropertyValidator.getInstance().assertOne(Property.REPEAT, getProperties());
michael@0: }
michael@0:
michael@0: /*
michael@0: * ; the following is optional, ; and MAY occur more than once x-prop
michael@0: */
michael@0:
michael@0: final Validator actionValidator = (Validator) actionValidators.get(getAction());
michael@0: if (actionValidator != null) {
michael@0: actionValidator.validate();
michael@0: }
michael@0:
michael@0: if (recurse) {
michael@0: validateProperties();
michael@0: }
michael@0: }
michael@0:
michael@0: /**
michael@0: * {@inheritDoc}
michael@0: */
michael@0: protected Validator getValidator(Method method) {
michael@0: return itipValidator;
michael@0: }
michael@0:
michael@0: private class AudioValidator implements Validator {
michael@0:
michael@0: private static final long serialVersionUID = 1L;
michael@0:
michael@0: /**
michael@0: * {@inheritDoc}
michael@0: */
michael@0: public void validate() throws ValidationException {
michael@0: /*
michael@0: * ; the following is optional, ; but MUST NOT occur more than once attach /
michael@0: */
michael@0: PropertyValidator.getInstance().assertOneOrLess(Property.ATTACH, getProperties());
michael@0: }
michael@0: }
michael@0:
michael@0: private class DisplayValidator implements Validator {
michael@0:
michael@0: private static final long serialVersionUID = 1L;
michael@0:
michael@0: /**
michael@0: * {@inheritDoc}
michael@0: */
michael@0: public void validate() throws ValidationException {
michael@0: /*
michael@0: * ; the following are all REQUIRED, ; but MUST NOT occur more than once action / description / trigger /
michael@0: */
michael@0: PropertyValidator.getInstance().assertOne(Property.DESCRIPTION, getProperties());
michael@0: }
michael@0: }
michael@0:
michael@0: private class EmailValidator implements Validator {
michael@0:
michael@0: private static final long serialVersionUID = 1L;
michael@0:
michael@0: /**
michael@0: * {@inheritDoc}
michael@0: */
michael@0: public void validate() throws ValidationException {
michael@0: /*
michael@0: * ; the following are all REQUIRED,
michael@0: * ; but MUST NOT occur more than once action / description / trigger / summary
michael@0: * ; the following is REQUIRED,
michael@0: * ; and MAY occur more than once attendee /
michael@0: * ; 'duration' and 'repeat' are both optional,
michael@0: * ; and MUST NOT occur more than once each,
michael@0: * ; but if one occurs, so MUST the other duration / repeat /
michael@0: * ; the following are optional,
michael@0: * ; and MAY occur more than once attach / x-prop
michael@0: */
michael@0: PropertyValidator.getInstance().assertOne(Property.DESCRIPTION, getProperties());
michael@0: PropertyValidator.getInstance().assertOne(Property.SUMMARY, getProperties());
michael@0:
michael@0: PropertyValidator.getInstance().assertOneOrMore(Property.ATTENDEE, getProperties());
michael@0: }
michael@0: }
michael@0:
michael@0: private class ProcedureValidator implements Validator {
michael@0:
michael@0: private static final long serialVersionUID = 1L;
michael@0:
michael@0: /**
michael@0: * {@inheritDoc}
michael@0: */
michael@0: public void validate() throws ValidationException {
michael@0: /*
michael@0: * ; the following are all REQUIRED,
michael@0: * ; but MUST NOT occur more than once action / attach / trigger /
michael@0: * ; 'duration' and 'repeat' are both optional,
michael@0: * ; and MUST NOT occur more than once each,
michael@0: * ; but if one occurs, so MUST the other duration / repeat /
michael@0: * ; 'description' is optional,
michael@0: * ; and MUST NOT occur more than once description /
michael@0: * ; the following is optional, ; and MAY occur more than once x-prop
michael@0: */
michael@0: PropertyValidator.getInstance().assertOne(Property.ATTACH, getProperties());
michael@0:
michael@0: PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties());
michael@0: }
michael@0: }
michael@0:
michael@0: /**
michael@0: * Common validation for all iTIP methods.
michael@0: *
michael@0: * michael@0: * Component/Property Presence michael@0: * ------------------- ---------------------------------------------- michael@0: * VALARM 0+ michael@0: * ACTION 1 michael@0: * ATTACH 0+ michael@0: * DESCRIPTION 0 or 1 michael@0: * DURATION 0 or 1 if present REPEAT MUST be present michael@0: * REPEAT 0 or 1 if present DURATION MUST be present michael@0: * SUMMARY 0 or 1 michael@0: * TRIGGER 1 michael@0: * X-PROPERTY 0+ michael@0: *michael@0: */ michael@0: private class ITIPValidator implements Validator { michael@0: michael@0: private static final long serialVersionUID = 1L; michael@0: michael@0: /** michael@0: * {@inheritDoc} michael@0: */ michael@0: public void validate() throws ValidationException { michael@0: PropertyValidator.getInstance().assertOne(Property.ACTION, getProperties()); michael@0: PropertyValidator.getInstance().assertOne(Property.TRIGGER, getProperties()); michael@0: michael@0: PropertyValidator.getInstance().assertOneOrLess(Property.DESCRIPTION, getProperties()); michael@0: PropertyValidator.getInstance().assertOneOrLess(Property.DURATION, getProperties()); michael@0: PropertyValidator.getInstance().assertOneOrLess(Property.REPEAT, getProperties()); michael@0: PropertyValidator.getInstance().assertOneOrLess(Property.SUMMARY, getProperties()); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Returns the mandatory action property. michael@0: * @return the ACTION property or null if not specified michael@0: */ michael@0: public final Action getAction() { michael@0: return (Action) getProperty(Property.ACTION); michael@0: } michael@0: michael@0: /** michael@0: * Returns the mandatory trigger property. michael@0: * @return the TRIGGER property or null if not specified michael@0: */ michael@0: public final Trigger getTrigger() { michael@0: return (Trigger) getProperty(Property.TRIGGER); michael@0: } michael@0: michael@0: /** michael@0: * Returns the optional duration property. michael@0: * @return the DURATION property or null if not specified michael@0: */ michael@0: public final Duration getDuration() { michael@0: return (Duration) getProperty(Property.DURATION); michael@0: } michael@0: michael@0: /** michael@0: * Returns the optional repeat property. michael@0: * @return the REPEAT property or null if not specified michael@0: */ michael@0: public final Repeat getRepeat() { michael@0: return (Repeat) getProperty(Property.REPEAT); michael@0: } michael@0: michael@0: /** michael@0: * Returns the optional attachment property. michael@0: * @return the ATTACH property or null if not specified michael@0: */ michael@0: public final Attach getAttachment() { michael@0: return (Attach) getProperty(Property.ATTACH); michael@0: } michael@0: michael@0: /** michael@0: * Returns the optional description property. michael@0: * @return the DESCRIPTION property or null if not specified michael@0: */ michael@0: public final Description getDescription() { michael@0: return (Description) getProperty(Property.DESCRIPTION); michael@0: } michael@0: michael@0: /** michael@0: * Returns the optional summary property. michael@0: * @return the SUMMARY property or null if not specified michael@0: */ michael@0: public final Summary getSummary() { michael@0: return (Summary) getProperty(Property.SUMMARY); michael@0: } michael@0: }