private static Set<String> getRemoteIds(List<SyncResponseEvent> events) {
   Set<String> ids = new HashSet<String>(events.size());
   for (SyncResponseEvent event : events) {
     if (event.isAddContact() || event.isUpdateContact()) {
       ids.add(RemoteId.contactId(event.getContactId()).toString());
     }
   }
   return ids;
 }
 private void processEvents(List<SyncResponseEvent> events) throws ServiceException {
   Stats stats = new Stats();
   int errors = 0;
   for (SyncResponseEvent event : events) {
     if (!event.isAddressBookReset()) {
       try {
         processEvent(event, stats);
       } catch (ServiceException e) {
         String msg = String.format("Contact event:\n%s", event);
         localData.syncContactFailed(e, -1, msg);
         errors++;
       }
     }
   }
   LOG.debug("Processed %d remote contact changes: %s", stats.total(), stats);
   if (errors > 0) {
     LOG.debug("%d contact changes could not be processed due to errors", errors);
   }
 }
 private void processEvent(SyncResponseEvent event, Stats stats) throws ServiceException {
   Contact contact = event.getContact();
   RemoteId rid = RemoteId.contactId(contact.getId());
   DataSourceItem dsi = localData.getReverseMapping(rid.toString());
   if (event.isAddContact() || event.isUpdateContact()) {
     if (dsi.itemId > 0) {
       // Don't update contact if it has been modified locally since
       // sync request was sent. Wait until we send the new changes
       // before updating the local contact.
       if (!contactChanges.containsKey(dsi.itemId)) {
         updateContact(contact, dsi, stats);
       }
     } else {
       addContact(contact, stats);
     }
   } else if (event.isRemoveContact()) {
     if (dsi.itemId > 0) {
       deleteContact(dsi.itemId, stats);
     }
   }
 }