summaryrefslogtreecommitdiff
path: root/src/com/google/wireless/gdata/calendar/parser/xml/XmlEventsGDataParser.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/google/wireless/gdata/calendar/parser/xml/XmlEventsGDataParser.java')
-rw-r--r--src/com/google/wireless/gdata/calendar/parser/xml/XmlEventsGDataParser.java419
1 files changed, 419 insertions, 0 deletions
diff --git a/src/com/google/wireless/gdata/calendar/parser/xml/XmlEventsGDataParser.java b/src/com/google/wireless/gdata/calendar/parser/xml/XmlEventsGDataParser.java
new file mode 100644
index 0000000..6135d1b
--- /dev/null
+++ b/src/com/google/wireless/gdata/calendar/parser/xml/XmlEventsGDataParser.java
@@ -0,0 +1,419 @@
+// Copyright 2007 The Android Open Source Project
+
+package com.google.wireless.gdata.calendar.parser.xml;
+
+import com.google.wireless.gdata.calendar.data.EventEntry;
+import com.google.wireless.gdata.calendar.data.EventsFeed;
+import com.google.wireless.gdata.calendar.data.When;
+import com.google.wireless.gdata.calendar.data.Reminder;
+import com.google.wireless.gdata.calendar.data.Who;
+import com.google.wireless.gdata.data.Entry;
+import com.google.wireless.gdata.data.Feed;
+import com.google.wireless.gdata.data.StringUtils;
+import com.google.wireless.gdata.data.XmlUtils;
+import com.google.wireless.gdata.parser.ParseException;
+import com.google.wireless.gdata.parser.xml.XmlGDataParser;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * GDataParser for an events feed containing events in a calendar.
+ */
+public class XmlEventsGDataParser extends XmlGDataParser {
+
+ // whether or not we've seen reminders directly under the entry.
+ // the calendar feed sends duplicate <reminder> entries in case of
+ // recurrences, if the recurrences are expanded.
+ // if the <reminder> elements precede the <when> elements, we'll only
+ // process the <reminder> elements directly under the entry and ignore
+ // the <reminder> elements within a <when>.
+ // if the <when> elements precede the <reminder> elements, we'll first
+ // process reminders under the when, and then we'll clear them and process
+ // the reminders directly under the entry (which should take precedence).
+ // if we only see <reminder> as direct children of the entry or only see
+ // <reminder> as children of <when> elements, there is no conflict.
+ private boolean hasSeenReminder = false;
+
+ /**
+ * Creates a new XmlEventsGDataParser.
+ * @param is The InputStream that should be parsed.
+ * @throws ParseException Thrown if a parser cannot be created.
+ */
+ public XmlEventsGDataParser(InputStream is, XmlPullParser parser)
+ throws ParseException {
+ super(is, parser);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see com.google.wireless.gdata.parser.xml.XmlGDataParser#createFeed()
+ */
+ protected Feed createFeed() {
+ return new EventsFeed();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see com.google.wireless.gdata.parser.xml.XmlGDataParser#createEntry()
+ */
+ protected Entry createEntry() {
+ return new EventEntry();
+ }
+
+ protected void handleExtraElementInFeed(Feed feed)
+ throws XmlPullParserException, IOException {
+ XmlPullParser parser = getParser();
+ if (!(feed instanceof EventsFeed)) {
+ throw new IllegalArgumentException("Expected EventsFeed!");
+ }
+ EventsFeed eventsFeed = (EventsFeed) feed;
+ String name = parser.getName();
+ if ("timezone".equals(name)) {
+ String timezone = parser.getAttributeValue(null /* ns */, "value");
+ if (!StringUtils.isEmpty(timezone)) {
+ eventsFeed.setTimezone(timezone);
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see XmlGDataParser#handleExtraElementInEntry
+ */
+ protected void handleExtraElementInEntry(Entry entry)
+ throws XmlPullParserException, IOException, ParseException {
+
+ XmlPullParser parser = getParser();
+
+ if (!(entry instanceof EventEntry)) {
+ throw new IllegalArgumentException("Expected EventEntry!");
+ }
+ EventEntry eventEntry = (EventEntry) entry;
+
+ // NOTE: all of these names are assumed to be in the "gd" namespace.
+ // we do not bother checking that here.
+
+ String name = parser.getName();
+ if ("eventStatus".equals(name)) {
+ String eventStatusStr = parser.getAttributeValue(null, "value");
+ byte eventStatus = EventEntry.STATUS_TENTATIVE;
+ if ("http://schemas.google.com/g/2005#event.canceled".
+ equals(eventStatusStr)) {
+ eventStatus = EventEntry.STATUS_CANCELED;
+ } else if ("http://schemas.google.com/g/2005#event.confirmed".
+ equals(eventStatusStr)) {
+ eventStatus = EventEntry.STATUS_CONFIRMED;
+ } else if ("http://schemas.google.com/g/2005#event.tentative".
+ equals(eventStatusStr)) {
+ eventStatus = EventEntry.STATUS_TENTATIVE;
+ }
+ eventEntry.setStatus(eventStatus);
+ } else if ("recurrence".equals(name)) {
+ String recurrence = XmlUtils.extractChildText(parser);
+ eventEntry.setRecurrence(recurrence);
+ } else if ("transparency".equals(name)) {
+ String transparencyStr = parser.getAttributeValue(null, "value");
+ byte transparency = EventEntry.TRANSPARENCY_OPAQUE;
+ if ("http://schemas.google.com/g/2005#event.opaque".
+ equals(transparencyStr)) {
+ transparency = EventEntry.TRANSPARENCY_OPAQUE;
+ } else if ("http://schemas.google.com/g/2005#event.transparent".
+ equals(transparencyStr)) {
+ transparency = EventEntry.TRANSPARENCY_TRANSPARENT;
+ }
+ eventEntry.setTransparency(transparency);
+ } else if ("visibility".equals(name)) {
+ String visibilityStr = parser.getAttributeValue(null, "value");
+ byte visibility = EventEntry.VISIBILITY_DEFAULT;
+ if ("http://schemas.google.com/g/2005#event.confidential".
+ equals(visibilityStr)) {
+ visibility = EventEntry.VISIBILITY_CONFIDENTIAL;
+ } else if ("http://schemas.google.com/g/2005#event.default"
+ .equals(visibilityStr)) {
+ visibility = EventEntry.VISIBILITY_DEFAULT;
+ } else if ("http://schemas.google.com/g/2005#event.private"
+ .equals(visibilityStr)) {
+ visibility = EventEntry.VISIBILITY_PRIVATE;
+ } else if ("http://schemas.google.com/g/2005#event.public"
+ .equals(visibilityStr)) {
+ visibility = EventEntry.VISIBILITY_PUBLIC;
+ }
+ eventEntry.setVisibility(visibility);
+ } else if ("who".equals(name)) {
+ handleWho(eventEntry);
+ } else if ("when".equals(name)) {
+ handleWhen(eventEntry);
+ } else if ("reminder".equals(name)) {
+ if (!hasSeenReminder) {
+ // if this is the first <reminder> we've seen directly under the
+ // entry, clear any previously seen reminders (under <when>s)
+ eventEntry.clearReminders();
+ hasSeenReminder = true;
+ }
+ handleReminder(eventEntry);
+ } else if ("originalEvent".equals(name)) {
+ handleOriginalEvent(eventEntry);
+ } else if ("where".equals(name)) {
+ String where = parser.getAttributeValue(null /* ns */,
+ "valueString");
+ String rel = parser.getAttributeValue(null /* ns */,
+ "rel");
+ if (StringUtils.isEmpty(rel) ||
+ "http://schemas.google.com/g/2005#event".equals(rel)) {
+ eventEntry.setWhere(where);
+ }
+ // TODO: handle entryLink?
+ } else if ("feedLink".equals(name)) {
+ // TODO: check that the parent is a gd:comments
+ String commentsUri = parser.getAttributeValue(null /* ns */, "href");
+ eventEntry.setCommentsUri(commentsUri);
+ } else if ("extendedProperty".equals(name)) {
+ String propertyName = parser.getAttributeValue(null /* ns */, "name");
+ String propertyValue = parser.getAttributeValue(null /* ns */, "value");
+ eventEntry.addExtendedProperty(propertyName, propertyValue);
+ }
+ }
+
+ private void handleWho(EventEntry eventEntry)
+ throws XmlPullParserException, IOException, ParseException {
+
+ XmlPullParser parser = getParser();
+
+ int eventType = parser.getEventType();
+ String name = parser.getName();
+
+ if (eventType != XmlPullParser.START_TAG ||
+ (!"who".equals(parser.getName()))) {
+ // should not happen.
+ throw new
+ IllegalStateException("Expected <who>: Actual "
+ + "element: <"
+ + name + ">");
+ }
+
+ String email =
+ parser.getAttributeValue(null /* ns */, "email");
+ String relString =
+ parser.getAttributeValue(null /* ns */, "rel");
+ String value =
+ parser.getAttributeValue(null /* ns */, "valueString");
+
+ Who who = new Who();
+ who.setEmail(email);
+ who.setValue(value);
+ byte rel = Who.RELATIONSHIP_NONE;
+ if ("http://schemas.google.com/g/2005#event.attendee".equals(relString)) {
+ rel = Who.RELATIONSHIP_ATTENDEE;
+ } else if ("http://schemas.google.com/g/2005#event.organizer".equals(relString)) {
+ rel = Who.RELATIONSHIP_ORGANIZER;
+ } else if ("http://schemas.google.com/g/2005#event.performer".equals(relString)) {
+ rel = Who.RELATIONSHIP_PERFORMER;
+ } else if ("http://schemas.google.com/g/2005#event.speaker".equals(relString)) {
+ rel = Who.RELATIONSHIP_SPEAKER;
+ } else if (StringUtils.isEmpty(relString)) {
+ rel = Who.RELATIONSHIP_ATTENDEE;
+ } else {
+ throw new ParseException("Unexpected rel: " + relString);
+ }
+ who.setRelationship(rel);
+
+ eventEntry.addAttendee(who);
+
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ switch (eventType) {
+ case XmlPullParser.START_TAG:
+ name = parser.getName();
+ if ("attendeeStatus".equals(name)) {
+ String statusString =
+ parser.getAttributeValue(null /* ns */, "value");
+ byte status = Who.STATUS_NONE;
+ if ("http://schemas.google.com/g/2005#event.accepted".
+ equals(statusString)) {
+ status = Who.STATUS_ACCEPTED;
+ } else if ("http://schemas.google.com/g/2005#event.declined".
+ equals(statusString)) {
+ status = Who.STATUS_DECLINED;
+ } else if ("http://schemas.google.com/g/2005#event.invited".
+ equals(statusString)) {
+ status = Who.STATUS_INVITED;
+ } else if ("http://schemas.google.com/g/2005#event.tentative".
+ equals(statusString)) {
+ status = Who.STATUS_TENTATIVE;
+ } else if (StringUtils.isEmpty(statusString)) {
+ status = Who.STATUS_TENTATIVE;
+ } else {
+ throw new ParseException("Unexpected status: " + statusString);
+ }
+ who.setStatus(status);
+ } else if ("attendeeType".equals(name)) {
+ String typeString= XmlUtils.extractChildText(parser);
+ byte type = Who.TYPE_NONE;
+ if ("http://schemas.google.com/g/2005#event.optional".equals(typeString)) {
+ type = Who.TYPE_OPTIONAL;
+ } else if ("http://schemas.google.com/g/2005#event.required".
+ equals(typeString)) {
+ type = Who.TYPE_REQUIRED;
+ } else if (StringUtils.isEmpty(typeString)) {
+ type = Who.TYPE_REQUIRED;
+ } else {
+ throw new ParseException("Unexpected type: " + typeString);
+ }
+ who.setType(type);
+ }
+ break;
+ case XmlPullParser.END_TAG:
+ name = parser.getName();
+ if ("who".equals(name)) {
+ return;
+ }
+ default:
+ // ignore
+ }
+
+ eventType = parser.next();
+ }
+ }
+
+ private void handleWhen(EventEntry eventEntry)
+ throws XmlPullParserException, IOException {
+
+ XmlPullParser parser = getParser();
+
+ int eventType = parser.getEventType();
+ String name = parser.getName();
+
+ if (eventType != XmlPullParser.START_TAG ||
+ (!"when".equals(parser.getName()))) {
+ // should not happen.
+ throw new
+ IllegalStateException("Expected <when>: Actual "
+ + "element: <"
+ + name + ">");
+ }
+
+ String startTime =
+ parser.getAttributeValue(null /* ns */, "startTime");
+ String endTime =
+ parser.getAttributeValue(null /* ns */, "endTime");
+
+ When when = new When(startTime, endTime);
+ eventEntry.addWhen(when);
+ boolean firstWhen = eventEntry.getWhens().size() == 1;
+ // we only parse reminders under the when if reminders have not already
+ // been handled (directly under the entry, or in a previous when for
+ // this entry)
+ boolean handleReminders = firstWhen && !hasSeenReminder;
+
+ eventType = parser.next();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ switch (eventType) {
+ case XmlPullParser.START_TAG:
+ name = parser.getName();
+ if ("reminder".equals(name)) {
+ // only want to store reminders on the first when. they
+ // should have the same values for all other instances.
+ if (handleReminders) {
+ handleReminder(eventEntry);
+ }
+ }
+ break;
+ case XmlPullParser.END_TAG:
+ name = parser.getName();
+ if ("when".equals(name)) {
+ return;
+ }
+ default:
+ // ignore
+ }
+
+ eventType = parser.next();
+ }
+ }
+
+ private void handleReminder(EventEntry eventEntry) {
+ XmlPullParser parser = getParser();
+
+ Reminder reminder = new Reminder();
+ eventEntry.addReminder(reminder);
+
+ String methodStr = parser.getAttributeValue(null /* ns */,
+ "method");
+ String minutesStr = parser.getAttributeValue(null /* ns */,
+ "minutes");
+ String hoursStr = parser.getAttributeValue(null /* ns */,
+ "hours");
+ String daysStr = parser.getAttributeValue(null /* ns */,
+ "days");
+
+ if (!StringUtils.isEmpty(methodStr)) {
+ if ("alert".equals(methodStr)) {
+ reminder.setMethod(Reminder.METHOD_ALERT);
+ } else if ("email".equals(methodStr)) {
+ reminder.setMethod(Reminder.METHOD_EMAIL);
+ } else if ("sms".equals(methodStr)) {
+ reminder.setMethod(Reminder.METHOD_SMS);
+ }
+ }
+
+ int minutes = Reminder.MINUTES_DEFAULT;
+ if (!StringUtils.isEmpty(minutesStr)) {
+ minutes = StringUtils.parseInt(minutesStr, minutes);
+ } else if (!StringUtils.isEmpty(hoursStr)) {
+ minutes = 60*StringUtils.parseInt(hoursStr, minutes);
+ } else if (!StringUtils.isEmpty(daysStr)) {
+ minutes = 24*60*StringUtils.parseInt(daysStr, minutes);
+ }
+ // TODO: support absolute times?
+ if (minutes < 0) {
+ minutes = Reminder.MINUTES_DEFAULT;
+ }
+ reminder.setMinutes(minutes);
+ }
+
+ private void handleOriginalEvent(EventEntry eventEntry)
+ throws XmlPullParserException, IOException {
+
+ XmlPullParser parser = getParser();
+
+ int eventType = parser.getEventType();
+ String name = parser.getName();
+
+ if (eventType != XmlPullParser.START_TAG ||
+ (!"originalEvent".equals(parser.getName()))) {
+ // should not happen.
+ throw new
+ IllegalStateException("Expected <originalEvent>: Actual "
+ + "element: <"
+ + name + ">");
+ }
+
+ eventEntry.setOriginalEventId(
+ parser.getAttributeValue(null /* ns */, "href"));
+
+ eventType = parser.next();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ switch (eventType) {
+ case XmlPullParser.START_TAG:
+ name = parser.getName();
+ if ("when".equals(name)) {
+ eventEntry.setOriginalEventStartTime(
+ parser.getAttributeValue(null/*ns*/, "startTime"));
+ }
+ break;
+ case XmlPullParser.END_TAG:
+ name = parser.getName();
+ if ("originalEvent".equals(name)) {
+ return;
+ }
+ default:
+ // ignore
+ }
+
+ eventType = parser.next();
+ }
+ }
+}