AbstractSyncParser.java revision 1431215b5fc40d0d6498b0fe602ad4d1b8a66ff3
1/* 2 * Copyright (C) 2008-2009 Marc Blank 3 * Licensed to The Android Open Source Project. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package com.android.exchange.adapter; 19 20import com.android.email.provider.EmailContent.Account; 21import com.android.email.provider.EmailContent.Mailbox; 22import com.android.email.provider.EmailContent.MailboxColumns; 23import com.android.exchange.EasSyncService; 24import com.android.exchange.SyncManager; 25 26import android.content.ContentResolver; 27import android.content.ContentValues; 28import android.content.Context; 29 30import java.io.IOException; 31import java.io.InputStream; 32 33/** 34 * Base class for the Email and PIM sync parsers 35 * Handles the basic flow of syncKeys, looping to get more data, handling errors, etc. 36 * Each subclass must implement a handful of methods that relate specifically to the data type 37 * 38 */ 39public abstract class AbstractSyncParser extends Parser { 40 41 protected EasSyncService mService; 42 protected Mailbox mMailbox; 43 protected Account mAccount; 44 protected Context mContext; 45 protected ContentResolver mContentResolver; 46 47 public AbstractSyncParser(InputStream in, EasSyncService _service) throws IOException { 48 super(in); 49 mService = _service; 50 mContext = mService.mContext; 51 mContentResolver = mContext.getContentResolver(); 52 mMailbox = mService.mMailbox; 53 mAccount = mService.mAccount; 54 } 55 56 /** 57 * Read, parse, and act on incoming commands from the Exchange server 58 * @throws IOException if the connection is broken 59 */ 60 public abstract void commandsParser() throws IOException; 61 62 /** 63 * Read, parse, and act on server responses 64 * Email doesn't have any, so this isn't yet implemented anywhere. It will become abstract, 65 * in the near future, however. 66 * @throws IOException 67 */ 68 public void responsesParser() throws IOException { 69 // Placeholder until needed; will become an abstract method 70 } 71 72 /** 73 * Delete all records of this class in this account 74 */ 75 public abstract void wipe(); 76 77 /** 78 * Loop through the top-level structure coming from the Exchange server 79 * Sync keys and the more available flag are handled here, whereas specific data parsing 80 * is handled by abstract methods implemented for each data class (e.g. Email, Contacts, etc.) 81 */ 82 @Override 83 public boolean parse() throws IOException { 84 int status; 85 boolean moreAvailable = false; 86 int interval = mMailbox.mSyncInterval; 87 88 // If we're not at the top of the xml tree, throw an exception 89 if (nextTag(START_DOCUMENT) != Tags.SYNC_SYNC) { 90 throw new EasParserException(); 91 } 92 // Loop here through the remaining xml 93 while (nextTag(START_DOCUMENT) != END_DOCUMENT) { 94 if (tag == Tags.SYNC_COLLECTION || tag == Tags.SYNC_COLLECTIONS) { 95 // Ignore these tags, since we've only got one collection syncing in this loop 96 } else if (tag == Tags.SYNC_STATUS) { 97 // Status = 1 is success; everything else is a failure 98 status = getValueInt(); 99 if (status != 1) { 100 mService.errorLog("Sync failed: " + status); 101 // Status = 3 means invalid sync key 102 if (status == 3) { 103 // Must delete all of the data and start over with syncKey of "0" 104 mMailbox.mSyncKey = "0"; 105 // Make this a push box through the first sync 106 // TODO Make frequency conditional on user settings! 107 mMailbox.mSyncInterval = Mailbox.CHECK_INTERVAL_PUSH; 108 mService.errorLog("Bad sync key; RESET and delete data"); 109 wipe(); 110 // Indicate there's more so that we'll start syncing again 111 moreAvailable = true; 112 } else if (status == 8) { 113 // This is Bad; it means the server doesn't recognize the serverId it 114 // sent us. What's needed is a refresh of the folder list. 115 SyncManager.reloadFolderList(mContext, mAccount.mId, true); 116 } 117 // TODO Look at other error codes and consider what's to be done 118 } 119 } else if (tag == Tags.SYNC_COMMANDS) { 120 commandsParser(); 121 } else if (tag == Tags.SYNC_RESPONSES) { 122 responsesParser(); 123 } else if (tag == Tags.SYNC_MORE_AVAILABLE) { 124 moreAvailable = true; 125 } else if (tag == Tags.SYNC_SYNC_KEY) { 126 if (mMailbox.mSyncKey.equals("0")) { 127 moreAvailable = true; 128 } 129 String newKey = getValue(); 130 userLog("Parsed key for ", mMailbox.mDisplayName, ": ", newKey); 131 mMailbox.mSyncKey = newKey; 132 // If we were pushing (i.e. auto-start), now we'll become ping-triggered 133 if (mMailbox.mSyncInterval == Mailbox.CHECK_INTERVAL_PUSH) { 134 mMailbox.mSyncInterval = Mailbox.CHECK_INTERVAL_PING; 135 } 136 } else { 137 skipTag(); 138 } 139 } 140 141 // If the sync interval has changed, or if no commands were parsed save the change 142 if (mMailbox.mSyncInterval != interval || mService.mChangeCount == 0) { 143 synchronized (mService.getSynchronizer()) { 144 if (!mService.isStopped()) { 145 // Make sure we save away the new syncFrequency 146 ContentValues cv = new ContentValues(); 147 if (mService.mChangeCount == 0) { 148 cv.put(MailboxColumns.SYNC_KEY, mMailbox.mSyncKey); 149 } 150 cv.put(MailboxColumns.SYNC_INTERVAL, mMailbox.mSyncInterval); 151 mMailbox.update(mContext, cv); 152 } 153 } 154 // If this box has backed off of push, and there were changes, try to change back to 155 // ping; it seems to help at times 156 } else if (mService.mChangeCount > 0 && 157 mAccount.mSyncInterval == Account.CHECK_INTERVAL_PUSH && 158 mMailbox.mSyncInterval > 0) { 159 synchronized (mService.getSynchronizer()) { 160 if (!mService.isStopped()) { 161 ContentValues cv = new ContentValues(); 162 cv.put(MailboxColumns.SYNC_INTERVAL, Mailbox.CHECK_INTERVAL_PING); 163 mMailbox.update(mContext, cv); 164 userLog("Changes found to ping loop mailbox ", mMailbox.mDisplayName, 165 ": switch back to ping."); 166 } 167 } 168 } 169 170 // Let the caller know that there's more to do 171 return moreAvailable; 172 } 173 174 void userLog(String ...strings) { 175 mService.userLog(strings); 176 } 177 178 void userLog(String string, int num, String string2) { 179 mService.userLog(string, num, string2); 180 } 181} 182