jfxtras.icalendarfx.components.VAlarm Maven / Gradle / Ivy
package jfxtras.icalendarfx.components;
import java.time.Duration;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import jfxtras.icalendarfx.components.VAlarm;
import jfxtras.icalendarfx.components.VAttendee;
import jfxtras.icalendarfx.components.VComponent;
import jfxtras.icalendarfx.components.VDescribable2;
import jfxtras.icalendarfx.components.VDescribableBase;
import jfxtras.icalendarfx.components.VDuration;
import jfxtras.icalendarfx.components.VEvent;
import jfxtras.icalendarfx.components.VTodo;
import jfxtras.icalendarfx.properties.component.alarm.Action;
import jfxtras.icalendarfx.properties.component.alarm.RepeatCount;
import jfxtras.icalendarfx.properties.component.alarm.Trigger;
import jfxtras.icalendarfx.properties.component.alarm.Action.ActionType;
import jfxtras.icalendarfx.properties.component.descriptive.Attachment;
import jfxtras.icalendarfx.properties.component.descriptive.Description;
import jfxtras.icalendarfx.properties.component.descriptive.Summary;
import jfxtras.icalendarfx.properties.component.misc.NonStandardProperty;
import jfxtras.icalendarfx.properties.component.relationship.Attendee;
import jfxtras.icalendarfx.properties.component.time.DateTimeEnd;
import jfxtras.icalendarfx.properties.component.time.DateTimeStart;
import jfxtras.icalendarfx.properties.component.time.DurationProp;
/**
* VALARM
* Alarm Component
* RFC 5545 iCalendar 3.6.6. page 71
*
* The body of the iCalendar object is defined by the following
* notation:
*
*- alarmc
*
* - "BEGIN" ":" "VALARM" CRLF
*
- (audioprop / dispprop / emailprop)
*
- "END" ":" "VALARM" CRLF
*
* - audioprop
*
* - The following are REQUIRED, but MUST NOT occur more than once.
*
* - {@link Action ACTION}
*
- {@link Trigger TRIGGER}
*
* - The following are OPTIONAL, but MUST NOT occur more than once; but if one occurs, so MUST the other.
*
* - {@link DurationProp DURATION}
*
- {@link RepeatCount REPEAT}
*
* - The following are OPTIONAL, but MUST NOT occur more than once.
*
* - {@link Attachment ATTACH}
*
* - The following are OPTIONAL, and MAY occur more than once.
*
* - {@link IANAProperty IANA-PROP}
*
- {@link NonStandardProperty X-PROP}
*
*
* - dispprop
*
* - The following are REQUIRED, but MUST NOT occur more than once.
*
* - {@link Action ACTION}
*
- {@link Description DESCRIPTION}
*
- {@link Trigger TRIGGER}
*
* - The following are OPTIONAL, but MUST NOT occur more than once; but if one occurs, so MUST the other.
*
* - {@link DurationProp DURATION}
*
- {@link RepeatCount REPEAT}
*
* - The following are OPTIONAL, and MAY occur more than once.
*
* - {@link IANAProperty IANA-PROP}
*
- {@link NonStandardProperty X-PROP}
*
*
* - emailprop
*
* - The following are REQUIRED, but MUST NOT occur more than once.
*
* - {@link Action ACTION}
*
- {@link Description DESCRIPTION}
*
- {@link Summary SUMMARY}
*
- {@link Trigger TRIGGER}
*
* - The following are REQUIRED, but MAY occur more than once.
*
* - {@link Attendee ATTENDEE}
*
* - The following are OPTIONAL, but MUST NOT occur more than once; but if one occurs, so MUST the other.
*
* - {@link DurationProp DURATION}
*
- {@link RepeatCount REPEAT}
*
* - The following are OPTIONAL, and MAY occur more than once.
*
* - {@link Attachment ATTACH}
*
- {@link NonStandardProperty X-PROP}
*
*
*
*
* Provide a grouping of component properties that define an alarm.
*
* Description: A {@link VAlarm VALARM} calendar component is a grouping of
* component properties that is a reminder or alarm for an event or a
* to-do. For example, it may be used to define a reminder for a
* pending event or an overdue to-do.
*
* The {@link VAlarm VALARM} calendar component MUST include the {@link Action ACTION} and
* {@link Trigger TRIGGER} properties. The {@link Action ACTION} property further constrains
* the {@link VAlarm VALARM} calendar component in the following ways:
*
* When the action is "AUDIO", the alarm can also include one and
* only one {@link Attachment ATTACH} property, which MUST point to a sound resource,
* which is rendered when the alarm is triggered.
*
* When the action is "DISPLAY", the alarm MUST also include a
* {@link Description DESCRIPTION} property, which contains the text to be displayed
* when the alarm is triggered.
*
* When the action is "EMAIL", the alarm MUST include a {@link Description DESCRIPTION}
* property, which contains the text to be used as the message body,
* a {@link Summary SUMMARY} property, which contains the text to be used as the
* message subject, and one or more {@link Attendee ATTENDEE} properties, which
* contain the email address of attendees to receive the message. It
* can also include one or more {@link Attachment ATTACH} properties, which are
* intended to be sent as message attachments. When the alarm is
* triggered, the email message is sent.
*
* The {@link VAlarm VALARM} calendar component MUST only appear within either a
* {@link VEvent VEVENT} or {@link VTodo VTODO} calendar component. {@link VAlarm VALARM} calendar
* components cannot be nested. Multiple mutually independent
*
* {@link VAlarm VALARM} calendar components can be specified for a single
* {@link VEvent VEVENT} or {@link VTodo VTODO} calendar component.
*
* The {@link Trigger TRIGGER} property specifies when the alarm will be triggered.
* The {@link Trigger TRIGGER} property specifies a duration prior to the start of
* an event or a to-do. The {@link Trigger TRIGGER} edge may be explicitly set to
* be relative to the "START" or "END" of the event or to-do with the
* "RELATED" parameter of the {@link Trigger TRIGGER} property. The {@link Trigger TRIGGER}
* property value type can alternatively be set to an absolute
* calendar date with UTC time.
*
* In an alarm set to trigger on the "START" of an event or to-do,
* the {@link DateTimeStart DTSTART} property MUST be present in the associated event or
* to-do. In an alarm in a {@link VEvent VEVENT} calendar component set to
* trigger on the "END" of the event, either the {@link DateTimeEnd DTEND} property
* MUST be present, or the {@link DateTimeStart DTSTART} and {@link Duration DURATION} properties MUST
* both be present. In an alarm in a {@link VTodo VTODO} calendar component set
* to trigger on the "END" of the to-do, either the "DUE" property
* MUST be present, or the {@link DateTimeStart DTSTART} and {@link Duration DURATION} properties MUST
* both be present.
*
* The alarm can be defined such that it triggers repeatedly. A
* definition of an alarm with a repeating trigger MUST include both
* the {@link Duration DURATION} and {@link RepeatCount REPEAT} properties. The {@link Duration DURATION} property
* specifies the delay period, after which the alarm will repeat.
* The {@link RepeatCount REPEAT} property specifies the number of additional
* repetitions that the alarm will be triggered. This repetition
* count is in addition to the initial triggering of the alarm. Both
* of these properties MUST be present in order to specify a
* repeating alarm. If one of these two properties is absent, then
* the alarm will not repeat beyond the initial trigger.
*
* The {@link Action ACTION} property is used within the {@link VAlarm VALARM} calendar
* component to specify the type of action invoked when the alarm is
* triggered. The {@link VAlarm VALARM} properties provide enough information for
* a specific action to be invoked. It is typically the
* responsibility of a "Calendar User Agent" (CUA) to deliver the
* alarm in the specified fashion. An {@link Action ACTION} property value of
* AUDIO specifies an alarm that causes a sound to be played to alert
* the user; DISPLAY specifies an alarm that causes a text message to
* be displayed to the user; and EMAIL specifies an alarm that causes
* an electronic email message to be delivered to one or more email
* addresses.
*
* In an AUDIO alarm, if the optional {@link Attachment ATTACH} property is included,
* it MUST specify an audio sound resource. The intention is that
* the sound will be played as the alarm effect. If an {@link Attachment ATTACH}
* property is specified that does not refer to a sound resource, or
* if the specified sound resource cannot be rendered (because its
* format is unsupported, or because it cannot be retrieved), then
* the CUA or other entity responsible for playing the sound may
* choose a fallback action, such as playing a built-in default
* sound, or playing no sound at all.
*
* In a DISPLAY alarm, the intended alarm effect is for the text
* value of the {@link Description DESCRIPTION} property to be displayed to the user.
*
* In an EMAIL alarm, the intended alarm effect is for an email
* message to be composed and delivered to all the addresses
* specified by the {@link Attendee ATTENDEE} properties in the {@link VAlarm VALARM} calendar
* component. The {@link Description DESCRIPTION} property of the {@link VAlarm VALARM} calendar
* component MUST be used as the body text of the message, and the
* {@link Summary SUMMARY} property MUST be used as the subject text. Any {@link Attachment ATTACH}
* properties in the {@link VAlarm VALARM} calendar component SHOULD be sent as
* attachments to the message.
*
* Note: Implementations should carefully consider whether they
* accept alarm components from untrusted sources, e.g., when
* importing calendar objects from external sources. One
* reasonable policy is to always ignore alarm components that the
* calendar user has not set herself, or at least ask for
* confirmation in such a case.
*
* @author David Bal
* @see VEvent
* @see VTodo
*/
// TODO - add to isValid tests to verify audioprop / dispprop / emailprop
public class VAlarm extends VDescribableBase implements VDescribable2,
VAttendee, VDuration
{
/**
* Defines the action to be invoked when an alarm is triggered.
* RFC 5545 iCalendar 3.8.6.1 page 132
* actionvalue = "AUDIO" / "DISPLAY" / "EMAIL" / iana-token / x-name
*
* Example:
*
* - ACTION:DISPLAY
*
*
*/
private Action action;
public Action getAction() { return action; }
public void setAction(String action) { setAction(Action.parse(action)); }
public void setAction(Action action)
{
orderer.replaceChild(this.action, action);
this.action = action;
}
public void setAction(ActionType action) { setAction(new Action(action)); }
/**
* Sets the value of the {@link #actionProperty()}
*
* @return this class for chaining
*/
public VAlarm withAction(Action action)
{
setAction(action);
return this;
}
/**
* Sets the value of the {@link #actionProperty()} by creating a new {@link Action} from the {@link ActionType} parameter
*
* @return this class for chaining
*/
public VAlarm withAction(ActionType actionType)
{
setAction(actionType);
return this;
}
/** Sets the value of the {@link #actionProperty()} by parsing iCalendar content text
* @return this class for chaining */
public VAlarm withAction(String action)
{
setAction(Action.parse(action));
return this;
}
/*
* ATTENDEE: Attendee
* RFC 5545 iCalendar 3.8.4.1 page 107
* This property defines an {@link Attendee ATTENDEE} within a calendar component.
*
* Examples:
* ATTENDEE;MEMBER="mailto:[email protected]":
* mailto:[email protected]
* ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Jane Doe
* :mailto:[email protected]
*/
private List attendees;
@Override
public List getAttendees() { return attendees; }
@Override
public void setAttendees(List attendees)
{
if (this.attendees != null)
{
this.attendees.forEach(e -> orderChild(e, null)); // remove old elements
}
this.attendees = attendees;
if (attendees != null)
{
attendees.forEach(c -> orderChild(c));
}
}
/*
* DESCRIPTION
* RFC 5545 iCalendar 3.8.1.5. page 84
*
* This property provides a more complete description of the
* calendar component than that provided by the {@link Summary SUMMARY} property.
*
* Example:
* DESCRIPTION:Meeting to provide technical review for "Phoenix"
* design.\nHappy Face Conference Room. Phoenix design team
* MUST attend this meeting.\nRSVP to team leader.
*
* Note: Only VJournal allows multiple instances of DESCRIPTION
*/
@Override
public Description getDescription() { return description; }
private Description description;
@Override
public void setDescription(Description description)
{
orderer.replaceChild(this.description, description);
this.description = description;
}
/*
* DURATION
* RFC 5545 iCalendar 3.8.2.5 page 99, 3.3.6 page 34
* Can't be used if DTEND is used. Must be one or the other.
*
* Example:
* DURATION:PT15M
* */
private DurationProp duration;
@Override
public DurationProp getDuration() { return duration; }
@Override
public void setDuration(DurationProp duration)
{
orderer.replaceChild(this.duration, duration);
this.duration = duration;
}
/**
* This property defines the number of times the alarm should
* be repeated, after the initial trigger.
* RFC 5545 iCalendar 3.8.6.2 page 133,
*
* If the alarm triggers more than once, then this property MUST be specified
* along with the {@link Duration DURATION} property.
*
* Example: The following is an example of this property for an alarm
* that repeats 4 additional times with a 5-minute delay after the
* initial triggering of the alarm:
*
* REPEAT:4
* DURATION:PT5M
*
*/
private RepeatCount repeatCount;
public RepeatCount getRepeatCount() { return repeatCount; }
public void setRepeatCount(RepeatCount repeatCount)
{
orderChild(this.repeatCount, repeatCount);
this.repeatCount = repeatCount;
}
public void setRepeatCount(int repeatCount) { setRepeatCount(new RepeatCount(repeatCount)); }
public void setRepeatCount(String repeatCount) { setRepeatCount(RepeatCount.parse(repeatCount)); }
/** Sets the value of the {@link #repeatCountProperty()}
* @return this class for chaining */
public VAlarm withRepeatCount(RepeatCount repeatCount)
{
setRepeatCount(repeatCount);
return this;
}
/** Sets the value of the {@link #repeatCountProperty()} by creating new {@link RepeatCount} from int parameter
* @return this class for chaining */
public VAlarm withRepeatCount(int repeatCount)
{
setRepeatCount(repeatCount);
return this;
}
/** Sets the value of the {@link #repeatCountProperty()} by parsing iCalendar content text
* @return this class for chaining */
public VAlarm withRepeatCount(String repeatCount)
{
setRepeatCount(repeatCount);
return this;
}
/**
* This property specifies when an alarm will trigger.
* RFC 5545 iCalendar 3.8.6.3 page 133
*
* Examples:
*
* A trigger set 15 minutes prior to the start of the event or to-do.
* - TRIGGER:-PT15M
*
* A trigger set five minutes after the end of an event or the due
* date of a to-do.
* - TRIGGER;RELATED=END:PT5M
*
* A trigger set to an absolute DATE-TIME.
* - TRIGGER;VALUE=DATE-TIME:19980101T050000Z
*
*
*/
private Trigger> trigger;
public Trigger> getTrigger() { return trigger; }
public void setTrigger(String trigger) { setTrigger(Trigger.parse(trigger)); }
public void setTrigger(Trigger> trigger)
{
orderChild(this.trigger, trigger);
this.trigger = trigger;
}
public void setTrigger(Duration trigger) { setTrigger(new Trigger(trigger)); }
public void setTrigger(ZonedDateTime trigger) { setTrigger(new Trigger(trigger)); }
/** Sets the value of the {@link #triggerProperty()}
* @return this class for chaining */
public VAlarm withTrigger(Trigger> trigger)
{
setTrigger(trigger);
return this;
}
/** Sets the value of the {@link #triggerProperty()} by creating new {@link Trigger} from Duration parameter
* @return this class for chaining */
public VAlarm withTrigger(Duration trigger)
{
setTrigger(trigger);
return this;
}
/** Sets the value of the {@link #triggerProperty()} by creating new {@link Trigger} from ZonedDateTime parameter
* @return this class for chaining */
public VAlarm withTrigger(ZonedDateTime trigger)
{
setTrigger(trigger);
return this;
}
/** Sets the value of the {@link #triggerProperty()} by parsing iCalendar content text
* @return this class for chaining */
public VAlarm withTrigger(String trigger)
{
setTrigger(trigger);
return this;
}
/*
* CONSTRUCTORS
*/
/**
* Creates a default VAlarm calendar component with no properties
*/
public VAlarm()
{
super();
}
/**
* Creates a deep copy of a VAlarm calendar component
*/
public VAlarm(VAlarm source)
{
super(source);
}
@Override
public List errors()
{
List errors = new ArrayList<>();
if (getAction() == null)
{
errors.add("ACTION is not present. ACTION is REQUIRED and MUST NOT occur more than once");
}
if (getTrigger() == null)
{
errors.add("TRIGGER is not present. TRIGGER is REQUIRED and MUST NOT occur more than once");
}
boolean isDurationNull = getDuration() == null;
boolean isRepeatNull = getRepeatCount() == null;
if (isDurationNull && ! isRepeatNull)
{
errors.add("DURATION is present but REPEAT is not present. DURATION and REPEAT are both OPTIONAL, and MUST NOT occur more than once each, but if one occurs, so MUST the other.");
}
if (! isDurationNull && isRepeatNull)
{
errors.add("REPEAT is present but DURATION is not present. DURATION and REPEAT are both OPTIONAL, and MUST NOT occur more than once each, but if one occurs, so MUST the other.");
}
return Collections.unmodifiableList(errors);
}
@Override
public List extends VComponent> calendarList()
{
throw new RuntimeException("VAlarm " + name() + " is embedded in VEVENT or VTODO not VCalendar");
}
/**
* Creates a new VAlarm calendar component by parsing a String of iCalendar content lines
*
* @param content the text to parse, not null
* @return the parsed VAlarm
*/
public static VAlarm parse(String content)
{
return VAlarm.parse(new VAlarm(), content);
}
}