/*
  * Reset address book data. Replace local with remote contact data, but
  * preserve non-Yahoo related contact fields. Also, remove all local
  * contacts which have been deleted remotely, and reset sync state.
  *
  * Reset is done after a metadata version change or irrecoverable sync
  * error. Reset does not depend on metadata format since the data is
  * completely replaced.
  */
 private void reset() throws IOException, YabException, ServiceException {
   // Fetch all remote contacts and merge with local data
   Mailbox mbox = localData.getMailbox();
   contactChanges = Collections.emptyMap();
   SyncRequest req = getSyncRequest(0);
   SyncResponse res = (SyncResponse) req.send();
   mbox.lock.lock();
   try {
     processContactResults(req.getEvents());
     List<SyncResponseEvent> events = res.getEvents();
     if (!events.isEmpty()) {
       // Categories are not returned unless there are contact changes
       processEvents(events);
       processCategories(res.getCategories());
     }
     // Remove contacts which no longer exist remotely
     localData.deleteMissingContacts(getRemoteIds(events));
     SyncState ss = new SyncState();
     // Save new sync state
     ss.setLastRevision(String.valueOf(res.getRevision()));
     ss.setLastModSequence(mbox.getLastChangeID());
     localData.saveState(ss);
   } finally {
     mbox.lock.release();
   }
 }
 public void sync() throws IOException, YabException, ServiceException {
   SyncState ss = localData.loadState();
   if (ss == null) {
     LOG.info("Sync state version change - resetting contact data");
     reset();
     return;
   }
   Mailbox mbox = localData.getMailbox();
   SyncRequest req;
   mbox.lock.lock();
   try {
     getLocalChanges(ss);
     ss.setLastModSequence(mbox.getLastChangeID());
     req = getSyncRequest(getLastRevision(ss));
   } finally {
     mbox.lock.release();
   }
   while (req != null) {
     SyncResponse res = (SyncResponse) req.send();
     mbox.lock.lock();
     try {
       getLocalChanges(ss);
       ss.setLastRevision(String.valueOf(res.getRevision()));
       processContactResults(req.getEvents());
       List<SyncResponseEvent> events = res.getEvents();
       if (!events.isEmpty()) {
         // Categories are not returned unless there are contact changes
         processEvents(events);
         processCategories(res.getCategories());
       }
       ss.setLastModSequence(mbox.getLastChangeID());
       localData.saveState(ss);
       req = hasLocalChanges() ? getSyncRequest(res.getRevision()) : null;
     } finally {
       mbox.lock.release();
     }
   }
 }
 private static int getLastRevision(SyncState ss) {
   String s = ss.getLastRevision();
   return s != null ? Integer.parseInt(s) : 0;
 }
 private void getLocalChanges(SyncState ss) throws ServiceException {
   contactChanges = localData.getContactChanges(ss.getLastModSequence());
   LOG.debug("Found %d local contact changes", contactChanges.size());
 }