Update of /cvsroot/wonder/Wonder/Common/Frameworks/ERCalendar/Sources/er/calendar
In directory usw-pr-cvs1:/tmp/cvs-serv12415/Common/Frameworks/ERCalendar/Sources/er/calendar
Added Files:
ERCalendarEvent.java ERPublishCalendarPage.java
ERSimpleEvent.java
Log Message:
Adding ERCalendar framework.
--- NEW FILE: ERCalendarEvent.java ---
package er.calendar;
import com.webobjects.foundation.*;
import com.webobjects.appserver.*;
/**
* ERCalendarEvent is an interface for events used by
* {@link ERPublishCalendarPage the ERPublishCalendarPage component}.
* <p>
* {@link ERPublishCalendarPage ERPublishCalendarPage} can use objects of any class
* that implements this interface. Existing classes (for example
* EOCustomObject subclasses), that correspond to calendar events,
* can easily be modified to implement this interface and thus be
* added directly to {@link ERPublishCalendarPage ERPublishCalendarPage}. If existing
* classes does not directly correspond to calendar events, create
* events from business data (or some algorithm) using either the
* included {@link ERSimpleEvent ERSimpleEvent class}, a subclass of
* {@link ERSimpleEvent ERSimpleEvent}, or any other class implementing
* this interface.
*
* @author Johan Carlberg <johan@...>
* @version 1.0, 2002-09-30
*/
public interface ERCalendarEvent {
/**
* @return <code>false</code> if this event have specified
* start and ending times.
* <code>true</code> if this event is a whole-day
* event without a specific starting and ending hour
* and minute.
* @see ERSimpleEvent#wholeDay
*/
public boolean wholeDay();
/**
* @return the start time of this event. For whole-day events,
* the time part of the NSTimestamp is ignored.
* @see #endTime
*/
public NSTimestamp startTime();
/**
* @return the end time of this event. For whole-day events,
* this should be a time on the day following the
* last day of this event (the time part of the
* NSTimestamp is ignored, and the iCalendar standard
* requires that the end time of an event is later
* than the start time.
* @see #startTime
*/
public NSTimestamp endTime();
/**
* @return the change counter of this event. The sequence of a
* calendar event is supposed to increase every time
* any information in the event is modified, so that
* updates to events can be ordered.
* @see ERSimpleEvent#sequence
*/
public int sequence();
/**
* @return status of this event. Values defined by the iCalendar
* standard are: "TENTATIVE", "CONFIRMED", "CANCELLED".
* Return null if event status is unspecified.
*/
public String status();
/**
* @return summary or textual description of this event.
*/
public String summary();
/**
* @return a persistent, globally unique identifier for this
* event.
* The unique identifier <b>must</b> be a globally unique
* identifier. The generator of the identifier <b>must</b>
* guarantee that the identifier is unique. There are
* several algorithms that can be used to accomplish this.
* The identifier is recommended to be the identical
* syntax to the RFC 822 addr-spec. A good method to
* assure uniqueness is to put the domain name or a
* domain literal IP address of the host on which the
* identifier was created on the right hand side of the
* "@", and on the left hand side, put a combination of
* the current calendar date and time of day (that is,
* formatted in as a date-time value) along with some
* other currently unique (perhaps sequential) identifier
* available on the system (for example, a process id
* number). Using a date/time value on the left hand side
* and a domain name or domain literal on the right hand
* side makes it possible to guarantee uniqueness since no
* two hosts should be using the same domain name or IP
* address at the same time. Though other algorithms will
* work, it is recommended that the right hand side
* contain some domain identifier (either of the host
* itself or otherwise) such that the generator of the
* message identifier can guarantee the uniqueness of the left
* hand side within the scope of that domain.
* @see ERSimpleEvent#sequence
*/
public String uniqueId();
/**
* @return the frequency of a repeating event, or 0 for a one time
* event. Can be specified as one of the
* <code>java.util.Calendar</code> field numbers
* <code>YEAR</code>, <code>MONTH</code>,
* <code>WEEK_OF_YEAR</code>, <code>DAY_OF_MONTH</code>,
* <code>HOUR_OF_DAY</code>, <code>MINUTE</code> or
* <code>SECOND</code>.
* @see #repeatCount
*/
public int repeatFrequency();
/**
* @return the number of occurences of a repeating event. Ignored
* if {@link #repeatFrequency} returns 0.
* @see #repeatFrequency
*/
public int repeatCount();
/**
* @return the day of week of a repeating event, or 0 for unspecified
* day of week. Can be specified as one of the
* <code>java.util.Calendar</code> <code>DAY_OF_WEEK</code>
* field values <code>SUNDAY</code>, <code>MONDAY</code>,
* <code>TUESDAY</code>, <code>WEDNESDAY</code>,
* <code>THURSDAY</code>, <code>FRIDAY</code>,
* <code>SATURDAY</code> or as the value 0. Ignored if
* {@link #repeatFrequency} returns 0.
* @see #repeatFrequency
*/
public int repeatDayOfWeek();
/**
* @return the ordinal number of day of the week within a month
* at which the event repeats. Together with
* {@link #repeatDayOfWeek} it uniquely specifies a day
* within the month. Ignored if {@link #repeatFrequency}
* returns 0.
* @see #repeatDayOfWeek
*/
public int repeatDayOfWeekInMonth();
/**
* @return an array of {@link Integer} indicating the days
* within a month, at which the event repeats, or
* <code>null</code> for not restricting repeating
* to certain days.
* Together with {@link #repeatDayOfWeek} it uniquely
* specifies a day within the month (Keep in mind
* that iCal 1.0 does not properly handle this).
* Ignored if {@link #repeatFrequency} returns 0.
* @see #repeatDayOfWeek
*/
public NSArray repeatDaysOfMonth();
}
--- NEW FILE: ERPublishCalendarPage.java ---
package er.calendar;
import com.webobjects.foundation.*;
import com.webobjects.appserver.*;
import java.util.*;
/**
* ERPublishCalendarPage is a WebObjects component for dynamically
* generated iCalendar documents.
* <p>
* The response created by ERPublishCalendarPage is an iCalendar
* document (.ics) containing the events added to ERPublishCalendarPage
* by the application (see {@link #addEvent(ERCalendarEvent) addEvent}).
* An iCalendar-aware application, such as Apple's iCal, can
* subscribe to such a calendar, provided that the page has a fixed
* URL (either is the "Main" page, or a direct action serves the page).
* <p>
* Events added to a ERPublishCalendarPage is objects of any class that
* implements {@link ERCalendarEvent the ERCalendarEvent interface}.
* Existing classes (for example EOCustomObject subclasses), that
* correspond to calendar events, can easily be modified to
* implement {@link ERCalendarEvent ERCalendarEvent} and thus be added
* directly to ERPublishCalendarPage. If existing classes does not
* directly correspond to calendar events, create events from business
* data (or some algorithm) using either the included
* {@link ERSimpleEvent ERSimpleEvent class}, a subclass of
* {@link ERSimpleEvent ERSimpleEvent}, or any other class implementing
* {@link ERCalendarEvent the ERCalendarEvent interface}.
*
* @author Johan Carlberg <johan@...>
* @version 1.0, 2002-09-30
*/
public class ERPublishCalendarPage extends WOComponent {
protected String calendarName;
protected String calendarTimeZone;
protected final int maxLineLength = 75;
/** @TypeInfo er.calendar.ERCalendarEvent */
protected NSMutableArray events;
public ERCalendarEvent event;
protected NSTimestamp eventTimestamp;
protected NSTimestampFormatter dateTimeFormatter;
protected NSTimestampFormatter dateFormatter;
protected NSTimestampFormatter utcDateTimeFormatter;
protected NSTimestampFormatter timeZoneFormatter;
/**
* Standard constructor for WOComponent subclasses.
*
* @param context context of a transaction
* @see WOComponent#pageWithName(String)
* @see WOApplication#pageWithName(String, WOContext)
*/
public ERPublishCalendarPage(WOContext context) {
super(context);
events = new NSMutableArray();
calendarTimeZone = new NSTimestampFormatter ("%Z").format (new NSTimestamp());
dateTimeFormatter = new NSTimestampFormatter ("%Y%m%dT%H%M%S");
dateTimeFormatter.setDefaultFormatTimeZone (NSTimeZone.localTimeZone());
dateFormatter = new NSTimestampFormatter ("%Y%m%d");
dateFormatter.setDefaultFormatTimeZone (NSTimeZone.localTimeZone());
utcDateTimeFormatter = new NSTimestampFormatter ("%Y%m%dT%H%M%SZ");
utcDateTimeFormatter.setDefaultFormatTimeZone (NSTimeZone.timeZoneWithName ("UTC", false));
timeZoneFormatter = new NSTimestampFormatter ("%Z");
timeZoneFormatter.setDefaultFormatTimeZone (NSTimeZone.localTimeZone());
}
/**
* Modifies content encoding to UTF8, and content type to text/calendar.
*
* @param aResponse the HTTP response that an application returns to a Web server to complete a cycle of the request-response loop
* @param aContext context of a transaction
*/
public void appendToResponse (WOResponse aResponse, WOContext aContext)
{
eventTimestamp = new NSTimestamp();
aResponse.setContentEncoding ("UTF8");
super.appendToResponse (aResponse, aContext);
aResponse.setHeader ("text/calendar","content-type");
try {
aResponse.setContent (new NSData (foldLongLinesInString (new String (aResponse.content().bytes(), "UTF-8")).getBytes ("UTF-8")));
} catch (java.io.UnsupportedEncodingException exception) {
// If encoding is not supported, content of response is left unmodified
// (although exceptions will be thrown elsewhere if UTF-8 is unsupported).
}
}
/**
* Adds an event to the calendar.
*
* @param event the event to be included in the calendar
* @see ERCalendarEvent
* @see #addEventsFromArray(NSArray)
*/
public void addEvent (ERCalendarEvent event) {
events.addObject (event);
}
/**
* Adds an array of events to the calendar.
*
* @param eventsArray the events to be included in the calendar
* @see ERCalendarEvent
* @see #addEvent(ERCalendarEvent)
*/
public void addEventsFromArray (NSArray eventsArray) {
events.addObjectsFromArray (eventsArray);
}
/**
* Removes a previously added event from the calendar.
*
* @param event the event to be removed from the calendar
* @see ERCalendarEvent
* @see #removeEventsInArray(NSArray)
*/
public void removeEvent (ERCalendarEvent event) {
events.removeObject (event);
}
/**
* Removes an array of previously added events from the calendar.
*
* @param eventsArray the events to be removed from the calendar
* @see ERCalendarEvent
* @see #removeEvent(ERCalendarEvent)
*/
public void removeEventsInArray (NSArray eventsArray) {
events.removeObjectsInArray (eventsArray);
}
/** @TypeInfo er.calendar.ERCalendarEvent */
public NSMutableArray events() {
return events;
}
/**
* @return name of the calendar
* @see #setCalendarName(String)
*/
public String calendarName()
{
return calendarName;
}
/**
* @return name of the calendar, backslash escaped for inclusion in
* iCalendar document.
* @see #calendarName
*/
public String escapedCalendarName()
{
return escapedString (calendarName);
}
/**
* Sets the name of the calendar.
*
* @param value name of the calendar
* @see #calendarName
*/
public void setCalendarName (String value)
{
calendarName = value;
}
/**
* @return originating time zone for the calendar (name of the
* system default time zone, if not changed by
* {@link #setCalendarTimeZone(String) setCalendarTimeZone}
* @see #setCalendarTimeZone(String)
*/
public String calendarTimeZone()
{
return calendarTimeZone;
}
/**
* @return time zone name of the calendar, backslash escaped
* for inclusion in iCalendar document.
* @see #calendarTimeZone
*/
public String escapedCalendarTimeZone()
{
return escapedString (calendarTimeZone);
}
/**
* Sets the name of the time zone for the calendar.
*
* @param value name of the time zone
* @see #calendarTimeZone
*/
public void setCalendarTimeZone (String value)
{
calendarTimeZone = value;
}
/**
* @return status of the current event, backslash escaped
* for inclusion in iCalendar document.
* @see ERCalendarEvent#status
*/
public String escapedEventStatus()
{
return escapedString (event.status());
}
/**
* @return summary of the current event, backslash escaped
* for inclusion in iCalendar document.
* @see ERCalendarEvent#summary
*/
public String escapedEventSummary()
{
return escapedString (event.summary());
}
/**
* @return unique id of the current event, backslash escaped
* for inclusion in iCalendar document.
* @see ERCalendarEvent#uniqueId
*/
public String escapedEventUniqueId()
{
return escapedString (event.uniqueId());
}
/**
* @return timestamp of the current event.
* This will always be the current time, as this is
* the time the event is converted to an iCalendar
* event.
*/
public NSTimestamp eventTimestamp()
{
return eventTimestamp;
}
/**
* @return the recurring rule frequency, as one of "YEARLY", "MONTHLY",
* "WEEKLY", "DAILY", "HOURLY", "MINUTELY", "SECONDLY" depending
* on the value returned by {@link ERCalendarEvent#repeatFrequency
* repeatFrequency}.
* @see ERCalendarEvent#repeatFrequency
*/
public String eventRepeatFrequency()
{
switch (event.repeatFrequency()) {
case Calendar.YEAR:
return "YEARLY";
case Calendar.MONTH:
return "MONTHLY";
case Calendar.WEEK_OF_YEAR:
return "WEEKLY";
case Calendar.DAY_OF_MONTH:
return "DAILY";
case Calendar.HOUR_OF_DAY:
return "HOURLY";
case Calendar.MINUTE:
return "MINUTELY";
case Calendar.SECOND:
return "SECONDLY";
default:
return null;
}
}
/**
* @return month number of a repeating event for use in
* the "BYMONTH" parameter.
*/
public Number eventRepeatMonth()
{
GregorianCalendar calendarDate = new GregorianCalendar();
calendarDate.setTime (event.startTime());
return new Integer (calendarDate.get (Calendar.MONTH) + 1);
}
/**
* @return day of week of a repeating event for use in
* the "BYDAY" parameter.
*/
public String eventRepeatDayOfWeekString()
{
String byDay = "";
if (event.repeatDayOfWeekInMonth() != 0) {
byDay = new Integer (event.repeatDayOfWeekInMonth()).toString();
}
switch (event.repeatDayOfWeek()) {
case Calendar.SUNDAY:
byDay += "SU";
break;
case Calendar.MONDAY:
byDay += "MO";
break;
case Calendar.TUESDAY:
byDay += "TU";
break;
case Calendar.WEDNESDAY:
byDay += "WE";
break;
case Calendar.THURSDAY:
byDay += "TH";
break;
case Calendar.FRIDAY:
byDay += "FR";
break;
case Calendar.SATURDAY:
byDay += "SA";
break;
}
return byDay;
}
/**
* @return days of month of a repeating event for use in
* the "BYMONTHDAY" parameter.
*/
public String eventRepeatDaysOfMonthString()
{
return event.repeatDaysOfMonth().componentsJoinedByString (",");
}
/**
* @return formatter for date/time.
* Will format date/times as "20021003T191234",
* specified in the local time zone.
*/
public NSTimestampFormatter dateTimeFormatter()
{
return dateTimeFormatter;
}
/**
* @return formatter for dates.
* Will format dates as "20021003",
* specified in the local time zone.
*/
public NSTimestampFormatter dateFormatter()
{
return dateFormatter;
}
/**
* @return formatter for date/time stamps.
* Will format date/times as "20021003T171234Z",
* specified in UTC (GMT).
*/
public NSTimestampFormatter utcDateTimeFormatter()
{
return utcDateTimeFormatter;
}
/**
* @return formatter for time zone.
* Will format date/times as only the name
* of the local time zone.
*/
public NSTimestampFormatter timeZoneFormatter()
{
return timeZoneFormatter;
}
/**
* @return backslash escaped text string, with special characters
* replaced with its backslash escaped equivalent.
*/
protected String escapedString (String string)
{
StringBuffer escapedString = new StringBuffer (string);
int index;
for (index = escapedString.length() - 1; index >= 0; index -= 1) {
switch (escapedString.charAt (index)) {
case '"':
case ';':
case ':':
case '\\':
case ',':
escapedString.insert (index, '\\');
break;
case '\n':
escapedString.setCharAt (index, 'n');
escapedString.insert (index, '\\');
break;
}
}
return escapedString.toString();
}
/**
* Folds lines that are longer than the maximum allowed 75 characters.
*
* @param content unfolded iCalendar content
* @return folded content, with no line longer than 75 characters
*/
protected String foldLongLinesInString (String content) {
Enumeration enumerator = NSArray.componentsSeparatedByString (content, "\r\n").objectEnumerator();
NSMutableArray foldedContent = new NSMutableArray();
String line;
while (enumerator.hasMoreElements()) {
line = (String)enumerator.nextElement();
while (line.length() > maxLineLength) {
foldedContent.addObject (line.substring (0, 75));
line = " " + line.substring (75);
}
foldedContent.addObject (line);
}
return foldedContent.componentsJoinedByString ("\r\n");
}
}
--- NEW FILE: ERSimpleEvent.java ---
package er.calendar;
import com.webobjects.foundation.*;
import com.webobjects.appserver.*;
/**
* ERSimpleEvent is an simple implementation of an event class,
* implementing the {@link ERCalendarEvent ERCalendarEvent interface},
* for use by {@link ERPublishCalendarPage the ERPublishCalendarPage component}.
* <p>
* ERSimpleEvent objects can be created corresponding to your events
* and added to ERPublishCalendarPage to create a calendar.
* <p>
* Subclass ERSimpleEvent if more advanced features are needed.
*
* @author Johan Carlberg <johan@...>
* @version 1.0, 2002-09-30
*/
public class ERSimpleEvent extends Object implements ERCalendarEvent {
protected NSTimestamp endTime;
protected NSTimestamp startTime;
protected String status;
protected String summary;
protected String uniqueId;
protected boolean wholeDay;
/**
* @param aStartTime start time of this event
* @param anEndTime end time of this event
* @param aSummary summary or textual description of this
* event
* @param aUniqueId a persistent, globally unique identifier
* for this event
* @see ERCalendarEvent#startTime
* @see ERCalendarEvent#endTime
* @see ERCalendarEvent#summary
* @see ERCalendarEvent#uniqueId
*/
public ERSimpleEvent (NSTimestamp aStartTime, NSTimestamp anEndTime, String aSummary, String aUniqueId) {
startTime = aStartTime;
endTime = anEndTime;
summary = aSummary;
uniqueId = aUniqueId;
}
/**
* @return always returns <code>false</code>.
* ERSimpleEvent doesn't support whole-day events.
* @see ERCalendarEvent#wholeDay
*/
public boolean wholeDay() {
return false;
}
/**
* @return the start time of this event as specified in the
* {@link #ERSimpleEvent(NSTimestamp, NSTimestamp, String, String) constructor}
* @see ERCalendarEvent#startTime
*/
public NSTimestamp startTime() {
return startTime;
}
/**
* @return the end time of this event as specified in the
* {@link #ERSimpleEvent(NSTimestamp, NSTimestamp, String, String) constructor}
* @see ERCalendarEvent#endTime
*/
public NSTimestamp endTime() {
return endTime;
}
/**
* @return the change counter of this event.
* Computed from the current time, and will increase every
* ten seconds.
* @see ERCalendarEvent#sequence
*/
public int sequence() {
return (int)(new NSTimestamp().getTime() / 10000);
}
/**
* @return <code>null</code> since ERSimpleEvent doesn't support
* event status.
* @see ERCalendarEvent#status
*/
public String status() {
return status;
}
/**
* @return the summary of this event as specified in the
* {@link #ERSimpleEvent(NSTimestamp, NSTimestamp, String, String) constructor}
* @see ERCalendarEvent#summary
*/
public String summary() {
return summary;
}
/**
* @return the unique id of this event as specified in the
* {@link #ERSimpleEvent(NSTimestamp, NSTimestamp, String, String) constructor}
* @see ERCalendarEvent#uniqueId
*/
public String uniqueId() {
return uniqueId;
}
/**
* @return 0 indicating a non-repeating event. ERSimpleEvent doesn't
* support repeating events.
*/
public int repeatFrequency() {
return 0;
}
/**
* @return 1 indicating a one-time event (although this method is
* never called since {@link #repeatFrequency} always return 0).
* @see #repeatFrequency
*/
public int repeatCount() {
return 1;
}
/**
* @return 0 indicating unspecified day of week (although this
* method is never called since {@link #repeatFrequency}
* always returns 0).
* @see #repeatFrequency
*/
public int repeatDayOfWeek() {
return 0;
}
/**
* @return 0 indicating unspecified day of week in month
* (although this method is never called since
* {@link #repeatFrequency} always returns 0).
* @see #repeatFrequency
*/
public int repeatDayOfWeekInMonth() {
return 0;
}
/**
* @return <code>null</code> indicating unspecified days
* within a month (although this method is never
* called since {@link #repeatFrequency} always
* returns 0.
* @see #repeatFrequency
*/
public NSArray repeatDaysOfMonth() {
return null;
}
}
|