private int pushDeleted() throws URISyntaxException, LocalStorageException, IOException, HttpException { int count = 0; long[] deletedIDs = local.findDeleted(); try { Log.i( TAG, "Remotely removing " + deletedIDs.length + " deleted resource(s) (if not changed)"); for (long id : deletedIDs) try { Resource res = local.findById(id, false); if (res.getName() != null) // is this resource even present remotely? try { remote.delete(res); } catch (NotFoundException e) { Log.i(TAG, "Locally-deleted resource has already been removed from server"); } catch (PreconditionFailedException e) { Log.i( TAG, "Locally-deleted resource has been changed on the server in the meanwhile"); } // always delete locally so that the record with the DELETED flag doesn't cause another // deletion attempt local.delete(res); count++; } catch (RecordNotFoundException e) { Log.wtf(TAG, "Couldn't read locally-deleted record", e); } } finally { local.commit(); } return count; }
private int pullChanged(Resource[] resourcesToUpdate) throws URISyntaxException, LocalStorageException, IOException, HttpException, DavException { int count = 0; Log.i(TAG, "Fetching " + resourcesToUpdate.length + " updated remote resource(s)"); for (Resource[] resources : ArrayUtils.partition(resourcesToUpdate, MAX_MULTIGET_RESOURCES)) for (Resource res : remote.multiGet(resources)) { Log.i(TAG, "Updating " + res.getName()); local.updateByRemoteName(res); local.commit(); count++; } return count; }
private int pullNew(Resource[] resourcesToAdd) throws URISyntaxException, LocalStorageException, IOException, HttpException, DavException { int count = 0; Log.i(TAG, "Fetching " + resourcesToAdd.length + " new remote resource(s)"); for (Resource[] resources : ArrayUtils.partition(resourcesToAdd, MAX_MULTIGET_RESOURCES)) for (Resource res : remote.multiGet(resources)) { Log.d(TAG, "Adding " + res.getName()); local.add(res); local.commit(); count++; } return count; }
public void synchronize(boolean manualSync, SyncResult syncResult) throws URISyntaxException, LocalStorageException, IOException, HttpException, DavException { // PHASE 1: push local changes to server int deletedRemotely = pushDeleted(), addedRemotely = pushNew(), updatedRemotely = pushDirty(); syncResult.stats.numEntries = deletedRemotely + addedRemotely + updatedRemotely; // PHASE 2A: check if there's a reason to do a sync with remote (= forced sync or remote CTag // changed) boolean fetchCollection = syncResult.stats.numEntries > 0; if (manualSync) { Log.i(TAG, "Synchronization forced"); fetchCollection = true; } if (!fetchCollection) { String currentCTag = remote.getCTag(), lastCTag = local.getCTag(); Log.d(TAG, "Last local CTag = " + lastCTag + "; current remote CTag = " + currentCTag); if (currentCTag == null || !currentCTag.equals(lastCTag)) fetchCollection = true; } if (!fetchCollection) { Log.i(TAG, "No local changes and CTags match, no need to sync"); return; } // PHASE 2B: detect details of remote changes Log.i(TAG, "Fetching remote resource list"); Set<Resource> remotelyAdded = new HashSet<Resource>(), remotelyUpdated = new HashSet<Resource>(); Resource[] remoteResources = remote.getMemberETags(); for (Resource remoteResource : remoteResources) { try { Resource localResource = local.findByRemoteName(remoteResource.getName(), false); if (localResource.getETag() == null || !localResource.getETag().equals(remoteResource.getETag())) remotelyUpdated.add(remoteResource); } catch (RecordNotFoundException e) { remotelyAdded.add(remoteResource); } } // PHASE 3: pull remote changes from server syncResult.stats.numInserts = pullNew(remotelyAdded.toArray(new Resource[0])); syncResult.stats.numUpdates = pullChanged(remotelyUpdated.toArray(new Resource[0])); syncResult.stats.numEntries += syncResult.stats.numInserts + syncResult.stats.numUpdates; Log.i(TAG, "Removing non-dirty resources that are not present remotely anymore"); local.deleteAllExceptRemoteNames(remoteResources); local.commit(); // update collection CTag Log.i(TAG, "Sync complete, fetching new CTag"); local.setCTag(remote.getCTag()); }