summaryrefslogtreecommitdiff
path: root/src/com/google/wireless/gdata/contacts/parser/xml/XmlContactsGDataParser.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/google/wireless/gdata/contacts/parser/xml/XmlContactsGDataParser.java')
-rw-r--r--src/com/google/wireless/gdata/contacts/parser/xml/XmlContactsGDataParser.java302
1 files changed, 302 insertions, 0 deletions
diff --git a/src/com/google/wireless/gdata/contacts/parser/xml/XmlContactsGDataParser.java b/src/com/google/wireless/gdata/contacts/parser/xml/XmlContactsGDataParser.java
new file mode 100644
index 0000000..5c7f551
--- /dev/null
+++ b/src/com/google/wireless/gdata/contacts/parser/xml/XmlContactsGDataParser.java
@@ -0,0 +1,302 @@
+// Copyright 2007 The Android Open Source Project
+
+package com.google.wireless.gdata.contacts.parser.xml;
+
+import com.google.wireless.gdata.contacts.data.ContactEntry;
+import com.google.wireless.gdata.contacts.data.ContactsElement;
+import com.google.wireless.gdata.contacts.data.ContactsFeed;
+import com.google.wireless.gdata.contacts.data.EmailAddress;
+import com.google.wireless.gdata.contacts.data.ImAddress;
+import com.google.wireless.gdata.contacts.data.Organization;
+import com.google.wireless.gdata.contacts.data.PhoneNumber;
+import com.google.wireless.gdata.contacts.data.PostalAddress;
+import com.google.wireless.gdata.contacts.data.GroupMembershipInfo;
+import com.google.wireless.gdata.data.Entry;
+import com.google.wireless.gdata.data.Feed;
+import com.google.wireless.gdata.data.XmlUtils;
+import com.google.wireless.gdata.data.ExtendedProperty;
+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;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+/**
+ * GDataParser for a contacts feed.
+ */
+public class XmlContactsGDataParser extends XmlGDataParser {
+ /** Namespace prefix for Contacts */
+ public static final String NAMESPACE_CONTACTS = "gContact";
+
+ /** Namespace URI for Contacts */
+ public static final String NAMESPACE_CONTACTS_URI =
+ "http://schemas.google.com/contact/2008";
+
+ /** The photo link rels */
+ public static final String LINK_REL_PHOTO = "http://schemas.google.com/contacts/2008/rel#photo";
+ public static final String LINK_REL_EDIT_PHOTO =
+ "http://schemas.google.com/contacts/2008/rel#edit-photo";
+
+ /** The phone number type gdata string. */
+ private static final String GD_NAMESPACE = "http://schemas.google.com/g/2005#";
+ public static final String TYPESTRING_MOBILE = GD_NAMESPACE + "mobile";
+ public static final String TYPESTRING_HOME = GD_NAMESPACE + "home";
+ public static final String TYPESTRING_WORK = GD_NAMESPACE + "work";
+ public static final String TYPESTRING_HOME_FAX = GD_NAMESPACE + "home_fax";
+ public static final String TYPESTRING_WORK_FAX = GD_NAMESPACE + "work_fax";
+ public static final String TYPESTRING_PAGER = GD_NAMESPACE + "pager";
+ public static final String TYPESTRING_OTHER = GD_NAMESPACE + "other";
+
+ public static final String IM_PROTOCOL_AIM = GD_NAMESPACE + "AIM";
+ public static final String IM_PROTOCOL_MSN = GD_NAMESPACE + "MSN";
+ public static final String IM_PROTOCOL_YAHOO = GD_NAMESPACE + "YAHOO";
+ public static final String IM_PROTOCOL_SKYPE = GD_NAMESPACE + "SKYPE";
+ public static final String IM_PROTOCOL_QQ = GD_NAMESPACE + "QQ";
+ public static final String IM_PROTOCOL_GOOGLE_TALK = GD_NAMESPACE + "GOOGLE_TALK";
+ public static final String IM_PROTOCOL_ICQ = GD_NAMESPACE + "ICQ";
+ public static final String IM_PROTOCOL_JABBER = GD_NAMESPACE + "JABBER";
+
+ private static final Hashtable REL_TO_TYPE_EMAIL;
+ private static final Hashtable REL_TO_TYPE_PHONE;
+ private static final Hashtable REL_TO_TYPE_POSTAL;
+ private static final Hashtable REL_TO_TYPE_IM;
+ private static final Hashtable REL_TO_TYPE_ORGANIZATION;
+ private static final Hashtable IM_PROTOCOL_STRING_TO_TYPE_MAP;
+
+ public static final Hashtable TYPE_TO_REL_EMAIL;
+ public static final Hashtable TYPE_TO_REL_PHONE;
+ public static final Hashtable TYPE_TO_REL_POSTAL;
+ public static final Hashtable TYPE_TO_REL_IM;
+ public static final Hashtable TYPE_TO_REL_ORGANIZATION;
+ public static final Hashtable IM_PROTOCOL_TYPE_TO_STRING_MAP;
+
+ static {
+ Hashtable map;
+
+ map = new Hashtable();
+ map.put(TYPESTRING_HOME, new Byte(EmailAddress.TYPE_HOME));
+ map.put(TYPESTRING_WORK, new Byte(EmailAddress.TYPE_WORK));
+ map.put(TYPESTRING_OTHER, new Byte(EmailAddress.TYPE_OTHER));
+ // TODO: this is a hack to support the old feed
+ map.put(GD_NAMESPACE + "primary", (byte)4);
+ REL_TO_TYPE_EMAIL = map;
+ TYPE_TO_REL_EMAIL = swapMap(map);
+
+ map = new Hashtable();
+ map.put(TYPESTRING_HOME, new Byte(PhoneNumber.TYPE_HOME));
+ map.put(TYPESTRING_MOBILE, new Byte(PhoneNumber.TYPE_MOBILE));
+ map.put(TYPESTRING_PAGER, new Byte(PhoneNumber.TYPE_PAGER));
+ map.put(TYPESTRING_WORK, new Byte(PhoneNumber.TYPE_WORK));
+ map.put(TYPESTRING_HOME_FAX, new Byte(PhoneNumber.TYPE_HOME_FAX));
+ map.put(TYPESTRING_WORK_FAX, new Byte(PhoneNumber.TYPE_WORK_FAX));
+ map.put(TYPESTRING_OTHER, new Byte(PhoneNumber.TYPE_OTHER));
+ REL_TO_TYPE_PHONE = map;
+ TYPE_TO_REL_PHONE = swapMap(map);
+
+ map = new Hashtable();
+ map.put(TYPESTRING_HOME, new Byte(PostalAddress.TYPE_HOME));
+ map.put(TYPESTRING_WORK, new Byte(PostalAddress.TYPE_WORK));
+ map.put(TYPESTRING_OTHER, new Byte(PostalAddress.TYPE_OTHER));
+ REL_TO_TYPE_POSTAL = map;
+ TYPE_TO_REL_POSTAL = swapMap(map);
+
+ map = new Hashtable();
+ map.put(TYPESTRING_HOME, new Byte(ImAddress.TYPE_HOME));
+ map.put(TYPESTRING_WORK, new Byte(ImAddress.TYPE_WORK));
+ map.put(TYPESTRING_OTHER, new Byte(ImAddress.TYPE_OTHER));
+ REL_TO_TYPE_IM = map;
+ TYPE_TO_REL_IM = swapMap(map);
+
+ map = new Hashtable();
+ map.put(TYPESTRING_WORK, new Byte(Organization.TYPE_WORK));
+ map.put(TYPESTRING_OTHER, new Byte(Organization.TYPE_OTHER));
+ REL_TO_TYPE_ORGANIZATION = map;
+ TYPE_TO_REL_ORGANIZATION = swapMap(map);
+
+ map = new Hashtable();
+ map.put(IM_PROTOCOL_AIM, new Byte(ImAddress.PROTOCOL_AIM));
+ map.put(IM_PROTOCOL_MSN, new Byte(ImAddress.PROTOCOL_MSN));
+ map.put(IM_PROTOCOL_YAHOO, new Byte(ImAddress.PROTOCOL_YAHOO));
+ map.put(IM_PROTOCOL_SKYPE, new Byte(ImAddress.PROTOCOL_SKYPE));
+ map.put(IM_PROTOCOL_QQ, new Byte(ImAddress.PROTOCOL_QQ));
+ map.put(IM_PROTOCOL_GOOGLE_TALK, new Byte(ImAddress.PROTOCOL_GOOGLE_TALK));
+ map.put(IM_PROTOCOL_ICQ, new Byte(ImAddress.PROTOCOL_ICQ));
+ map.put(IM_PROTOCOL_JABBER, new Byte(ImAddress.PROTOCOL_JABBER));
+ IM_PROTOCOL_STRING_TO_TYPE_MAP = map;
+ IM_PROTOCOL_TYPE_TO_STRING_MAP = swapMap(map);
+ }
+
+ private static Hashtable swapMap(Hashtable originalMap) {
+ Hashtable newMap = new Hashtable();
+ Enumeration enumeration = originalMap.keys();
+ while (enumeration.hasMoreElements()) {
+ Object key = enumeration.nextElement();
+ Object value = originalMap.get(key);
+ if (newMap.containsKey(value)) {
+ throw new IllegalArgumentException("value " + value
+ + " was already encountered");
+ }
+ newMap.put(value, key);
+ }
+ return newMap;
+ }
+
+ /**
+ * Creates a new XmlEventsGDataParser.
+ * @param is The InputStream that should be parsed.
+ * @throws ParseException Thrown if a parser cannot be created.
+ */
+ public XmlContactsGDataParser(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 ContactsFeed();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see com.google.wireless.gdata.parser.xml.XmlGDataParser#createEntry()
+ */
+ protected Entry createEntry() {
+ return new ContactEntry();
+ }
+
+ protected void handleExtraElementInEntry(Entry entry) throws XmlPullParserException, IOException {
+ XmlPullParser parser = getParser();
+
+ if (!(entry instanceof ContactEntry)) {
+ throw new IllegalArgumentException("Expected ContactEntry!");
+ }
+ ContactEntry contactEntry = (ContactEntry) entry;
+ String name = parser.getName();
+ if ("email".equals(name)) {
+ EmailAddress emailAddress = new EmailAddress();
+ parseContactsElement(emailAddress, parser, REL_TO_TYPE_EMAIL);
+ // TODO: remove this when the feed is upgraded
+ if (emailAddress.getType() == 4) {
+ emailAddress.setType(EmailAddress.TYPE_OTHER);
+ emailAddress.setIsPrimary(true);
+ emailAddress.setLabel(null);
+ }
+ emailAddress.setAddress(parser.getAttributeValue(null /* ns */, "address"));
+ contactEntry.addEmailAddress(emailAddress);
+ } else if ("deleted".equals(name)) {
+ contactEntry.setDeleted(true);
+ } else if ("im".equals(name)) {
+ ImAddress imAddress = new ImAddress();
+ parseContactsElement(imAddress, parser, REL_TO_TYPE_IM);
+ imAddress.setAddress(parser.getAttributeValue(null /* ns */, "address"));
+ imAddress.setLabel(parser.getAttributeValue(null /* ns */, "label"));
+ String protocolString = parser.getAttributeValue(null /* ns */, "protocol");
+ if (protocolString == null) {
+ imAddress.setProtocolPredefined(ImAddress.PROTOCOL_NONE);
+ imAddress.setProtocolCustom(null);
+ } else {
+ Byte predefinedProtocol = (Byte) IM_PROTOCOL_STRING_TO_TYPE_MAP.get(protocolString);
+ if (predefinedProtocol == null) {
+ imAddress.setProtocolPredefined(ImAddress.PROTOCOL_CUSTOM);
+ imAddress.setProtocolCustom(protocolString);
+ } else {
+ imAddress.setProtocolPredefined(predefinedProtocol.byteValue());
+ imAddress.setProtocolCustom(null);
+ }
+ }
+ contactEntry.addImAddress(imAddress);
+ } else if ("postalAddress".equals(name)) {
+ PostalAddress postalAddress = new PostalAddress();
+ parseContactsElement(postalAddress, parser, REL_TO_TYPE_POSTAL);
+ postalAddress.setValue(XmlUtils.extractChildText(parser));
+ contactEntry.addPostalAddress(postalAddress);
+ } else if ("phoneNumber".equals(name)) {
+ PhoneNumber phoneNumber = new PhoneNumber();
+ parseContactsElement(phoneNumber, parser, REL_TO_TYPE_PHONE);
+ phoneNumber.setPhoneNumber(XmlUtils.extractChildText(parser));
+ contactEntry.addPhoneNumber(phoneNumber);
+ } else if ("organization".equals(name)) {
+ Organization organization = new Organization();
+ parseContactsElement(organization, parser, REL_TO_TYPE_ORGANIZATION);
+ handleOrganizationSubElement(organization, parser);
+ contactEntry.addOrganization(organization);
+ } else if ("extendedProperty".equals(name)) {
+ ExtendedProperty extendedProperty = new ExtendedProperty();
+ parseExtendedProperty(extendedProperty);
+ contactEntry.addExtendedProperty(extendedProperty);
+ } else if ("groupMembershipInfo".equals(name)) {
+ GroupMembershipInfo group = new GroupMembershipInfo();
+ group.setGroup(parser.getAttributeValue(null /* ns */, "href"));
+ group.setDeleted("true".equals(parser.getAttributeValue(null /* ns */, "deleted")));
+ contactEntry.addGroup(group);
+ }
+ }
+
+ @Override
+ protected void handleExtraLinkInEntry(String rel, String type, String href, Entry entry)
+ throws XmlPullParserException, IOException {
+ if (LINK_REL_PHOTO.equals(rel)) {
+ ContactEntry contactEntry = (ContactEntry) entry;
+ contactEntry.setLinkPhoto(href, type);
+ } else if (LINK_REL_EDIT_PHOTO.equals(rel)) {
+ ContactEntry contactEntry = (ContactEntry) entry;
+ contactEntry.setLinkEditPhoto(href, type);
+ }
+ }
+
+ private static void parseContactsElement(ContactsElement element, XmlPullParser parser,
+ Hashtable relToTypeMap) throws XmlPullParserException {
+ String rel = parser.getAttributeValue(null /* ns */, "rel");
+ String label = parser.getAttributeValue(null /* ns */, "label");
+
+ if ((label == null && rel == null) || (label != null && rel != null)) {
+ // TODO: remove this once the focus feed is fixed to not send this case
+ rel = TYPESTRING_OTHER;
+ }
+
+ if (rel != null) {
+ final Object type = relToTypeMap.get(rel.toLowerCase());
+ if (type == null) {
+ throw new XmlPullParserException("unknown rel, " + rel);
+ }
+ element.setType(((Byte) type).byteValue());
+ }
+ element.setLabel(label);
+ element.setIsPrimary("true".equals(parser.getAttributeValue(null /* ns */, "primary")));
+ }
+
+ private static void handleOrganizationSubElement(Organization element, XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ int depth = parser.getDepth();
+ while (true) {
+ String tag = XmlUtils.nextDirectChildTag(parser, depth);
+ if (tag == null) break;
+ if ("orgName".equals(tag)) {
+ element.setName(XmlUtils.extractChildText(parser));
+ } else if ("orgTitle".equals(tag)) {
+ element.setTitle(XmlUtils.extractChildText(parser));
+ }
+ }
+ }
+
+ /**
+ * Parse the ExtendedProperty. The parser is assumed to be at the beginning of the tag
+ * for the ExtendedProperty.
+ * @param extendedProperty the ExtendedProperty object to populate
+ */
+ private void parseExtendedProperty(ExtendedProperty extendedProperty)
+ throws IOException, XmlPullParserException {
+ XmlPullParser parser = getParser();
+ extendedProperty.setName(parser.getAttributeValue(null /* ns */, "name"));
+ extendedProperty.setValue(parser.getAttributeValue(null /* ns */, "value"));
+ extendedProperty.setXmlBlob(XmlUtils.extractFirstChildTextIgnoreRest(parser));
+ }
+}