diff options
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.java | 419 |
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(); + } + } +} |