summaryrefslogtreecommitdiffstats
path: root/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/SyncClientsEngineStage.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/SyncClientsEngineStage.java')
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/SyncClientsEngineStage.java691
1 files changed, 0 insertions, 691 deletions
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/SyncClientsEngineStage.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/SyncClientsEngineStage.java
deleted file mode 100644
index 04d3e7ce2..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/SyncClientsEngineStage.java
+++ /dev/null
@@ -1,691 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.stage;
-
-import android.accounts.Account;
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.fxa.FxAccountClient;
-import org.mozilla.gecko.background.fxa.FxAccountClient20;
-import org.mozilla.gecko.background.fxa.FxAccountClientException;
-import org.mozilla.gecko.fxa.FirefoxAccounts;
-import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
-import org.mozilla.gecko.sync.CommandProcessor;
-import org.mozilla.gecko.sync.CommandProcessor.Command;
-import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.HTTPFailureException;
-import org.mozilla.gecko.sync.NoCollectionKeysSetException;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.SyncStorageCollectionRequest;
-import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-import org.mozilla.gecko.sync.net.WBOCollectionRequestDelegate;
-import org.mozilla.gecko.sync.net.WBORequestDelegate;
-import org.mozilla.gecko.sync.repositories.NullCursorException;
-import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
-import org.mozilla.gecko.sync.repositories.android.RepoUtils;
-import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
-import org.mozilla.gecko.sync.repositories.domain.ClientRecordFactory;
-import org.mozilla.gecko.sync.repositories.domain.VersionConstants;
-
-import ch.boye.httpclientandroidlib.HttpStatus;
-
-public class SyncClientsEngineStage extends AbstractSessionManagingSyncStage {
- private static final String LOG_TAG = "SyncClientsEngineStage";
-
- public static final String COLLECTION_NAME = "clients";
- public static final String STAGE_NAME = COLLECTION_NAME;
- public static final int CLIENTS_TTL_REFRESH = 604800000; // 7 days in milliseconds.
- public static final int MAX_UPLOAD_FAILURE_COUNT = 5;
- public static final long NOTIFY_TAB_SENT_TTL_SECS = TimeUnit.SECONDS.convert(1L, TimeUnit.HOURS); // 1 hour
-
- protected final ClientRecordFactory factory = new ClientRecordFactory();
- protected ClientUploadDelegate clientUploadDelegate;
- protected ClientDownloadDelegate clientDownloadDelegate;
-
- // Be sure to use this safely via getClientsDatabaseAccessor/closeDataAccessor.
- protected ClientsDatabaseAccessor db;
-
- protected volatile boolean shouldWipe;
- protected volatile boolean shouldUploadLocalRecord; // Set if, e.g., we received commands or need to refresh our version.
- protected final AtomicInteger uploadAttemptsCount = new AtomicInteger();
- protected final List<ClientRecord> modifiedClientsToUpload = new ArrayList<ClientRecord>();
-
- protected int getClientsCount() {
- return getClientsDatabaseAccessor().clientsCount();
- }
-
- protected synchronized ClientsDatabaseAccessor getClientsDatabaseAccessor() {
- if (db == null) {
- db = new ClientsDatabaseAccessor(session.getContext());
- }
- return db;
- }
-
- protected synchronized void closeDataAccessor() {
- if (db == null) {
- return;
- }
- db.close();
- db = null;
- }
-
- /**
- * The following two delegates, ClientDownloadDelegate and ClientUploadDelegate
- * are both triggered in a chain, starting when execute() calls
- * downloadClientRecords().
- *
- * Client records are downloaded using a get() request. Upon success of the
- * get() request, the local client record is uploaded.
- *
- * @author Marina Samuel
- *
- */
- public class ClientDownloadDelegate extends WBOCollectionRequestDelegate {
-
- // We use this on each WBO, so lift it out.
- final ClientsDataDelegate clientsDelegate = session.getClientsDelegate();
- boolean localAccountGUIDDownloaded = false;
-
- @Override
- public AuthHeaderProvider getAuthHeaderProvider() {
- return session.getAuthHeaderProvider();
- }
-
- @Override
- public String ifUnmodifiedSince() {
- // TODO last client download time?
- return null;
- }
-
- @Override
- public void handleRequestSuccess(SyncStorageResponse response) {
-
- // Hang onto the server's last modified timestamp to use
- // in X-If-Unmodified-Since for upload.
- session.config.persistServerClientsTimestamp(response.normalizedWeaveTimestamp());
- BaseResource.consumeEntity(response);
-
- // Wipe the clients table if it still hasn't been wiped but needs to be.
- wipeAndStore(null);
-
- // If we successfully downloaded all records but ours was not one of them
- // then reset the timestamp.
- if (!localAccountGUIDDownloaded) {
- Logger.info(LOG_TAG, "Local client GUID does not exist on the server. Upload timestamp will be reset.");
- session.config.persistServerClientRecordTimestamp(0);
- }
- localAccountGUIDDownloaded = false;
-
- final int clientsCount;
- try {
- clientsCount = getClientsCount();
- } finally {
- // Close the database to clear cached readableDatabase/writableDatabase
- // after we've completed our last transaction (db.store()).
- closeDataAccessor();
- }
-
- Logger.debug(LOG_TAG, "Database contains " + clientsCount + " clients.");
- Logger.debug(LOG_TAG, "Server response asserts " + response.weaveRecords() + " records.");
-
- // TODO: persist the response timestamp to know whether to download next time (Bug 726055).
- clientUploadDelegate = new ClientUploadDelegate();
- clientsDelegate.setClientsCount(clientsCount);
-
- // If we upload remote records, checkAndUpload() will be called upon
- // upload success in the delegate. Otherwise call checkAndUpload() now.
- if (modifiedClientsToUpload.size() > 0) {
- // modifiedClientsToUpload is cleared in uploadRemoteRecords, save what we need here
- final List<String> devicesToNotify = new ArrayList<>();
- for (ClientRecord record : modifiedClientsToUpload) {
- if (!TextUtils.isEmpty(record.fxaDeviceId)) {
- devicesToNotify.add(record.fxaDeviceId);
- }
- }
-
- // This method is synchronous, there's no risk of notifying the clients
- // before we actually uploaded the records
- uploadRemoteRecords();
-
- // Notify the clients who got their record written
- notifyClients(devicesToNotify);
-
- return;
- }
- checkAndUpload();
- }
-
- private void notifyClients(final List<String> devicesToNotify) {
- final ExecutorService executor = Executors.newSingleThreadExecutor();
- final Context context = session.getContext();
- final Account account = FirefoxAccounts.getFirefoxAccount(context);
- if (account == null) {
- Log.e(LOG_TAG, "Can't notify other clients: no account");
- return;
- }
- final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account);
- final ExtendedJSONObject payload = createNotifyDevicesPayload();
-
- final byte[] sessionToken;
- try {
- sessionToken = fxAccount.getSessionToken();
- } catch (AndroidFxAccount.InvalidFxAState invalidFxAState) {
- Log.e(LOG_TAG, "Could not get session token", invalidFxAState);
- return;
- }
-
- // API doc : https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#post-v1accountdevicesnotify
- final FxAccountClient fxAccountClient = new FxAccountClient20(fxAccount.getAccountServerURI(), executor);
- fxAccountClient.notifyDevices(sessionToken, devicesToNotify, payload, NOTIFY_TAB_SENT_TTL_SECS, new FxAccountClient20.RequestDelegate<ExtendedJSONObject>() {
- @Override
- public void handleError(Exception e) {
- Log.e(LOG_TAG, "Error while notifying devices", e);
- }
-
- @Override
- public void handleFailure(FxAccountClientException.FxAccountClientRemoteException e) {
- Log.e(LOG_TAG, "Error while notifying devices", e);
- }
-
- @Override
- public void handleSuccess(ExtendedJSONObject result) {
- Log.i(LOG_TAG, devicesToNotify.size() + " devices notified");
- }
- });
- }
-
- @NonNull
- @SuppressWarnings("unchecked")
- private ExtendedJSONObject createNotifyDevicesPayload() {
- final ExtendedJSONObject payload = new ExtendedJSONObject();
- payload.put("version", 1);
- payload.put("command", "sync:collection_changed");
- final ExtendedJSONObject data = new ExtendedJSONObject();
- final JSONArray collections = new JSONArray();
- collections.add("clients");
- data.put("collections", collections);
- payload.put("data", data);
- return payload;
- }
-
- @Override
- public void handleRequestFailure(SyncStorageResponse response) {
- BaseResource.consumeEntity(response); // We don't need the response at all, and any exception handling shouldn't need the response body.
- localAccountGUIDDownloaded = false;
-
- try {
- Logger.info(LOG_TAG, "Client upload failed. Aborting sync.");
- session.abort(new HTTPFailureException(response), "Client download failed.");
- } finally {
- // Close the database upon failure.
- closeDataAccessor();
- }
- }
-
- @Override
- public void handleRequestError(Exception ex) {
- localAccountGUIDDownloaded = false;
- try {
- Logger.info(LOG_TAG, "Client upload error. Aborting sync.");
- session.abort(ex, "Failure fetching client record.");
- } finally {
- // Close the database upon error.
- closeDataAccessor();
- }
- }
-
- @Override
- public void handleWBO(CryptoRecord record) {
- ClientRecord r;
- try {
- r = (ClientRecord) factory.createRecord(record.decrypt());
- if (clientsDelegate.isLocalGUID(r.guid)) {
- Logger.info(LOG_TAG, "Local client GUID exists on server and was downloaded.");
- localAccountGUIDDownloaded = true;
- handleDownloadedLocalRecord(r);
- } else {
- // Only need to store record if it isn't our local one.
- wipeAndStore(r);
- addCommands(r);
- }
- RepoUtils.logClient(r);
- } catch (Exception e) {
- session.abort(e, "Exception handling client WBO.");
- return;
- }
- }
-
- @Override
- public KeyBundle keyBundle() {
- try {
- return session.keyBundleForCollection(COLLECTION_NAME);
- } catch (NoCollectionKeysSetException e) {
- return null;
- }
- }
- }
-
- public class ClientUploadDelegate extends WBORequestDelegate {
- protected static final String LOG_TAG = "ClientUploadDelegate";
- public Long currentlyUploadingRecordTimestamp;
- public boolean currentlyUploadingLocalRecord;
-
- @Override
- public AuthHeaderProvider getAuthHeaderProvider() {
- return session.getAuthHeaderProvider();
- }
-
- private void setUploadDetails(boolean isLocalRecord) {
- // Use the timestamp for the whole collection per Sync storage 1.1 spec.
- currentlyUploadingRecordTimestamp = session.config.getPersistedServerClientsTimestamp();
- currentlyUploadingLocalRecord = isLocalRecord;
- }
-
- @Override
- public String ifUnmodifiedSince() {
- Long timestampInMilliseconds = currentlyUploadingRecordTimestamp;
-
- // It's the first upload so we don't care about X-If-Unmodified-Since.
- if (timestampInMilliseconds <= 0) {
- return null;
- }
-
- return Utils.millisecondsToDecimalSecondsString(timestampInMilliseconds);
- }
-
- @Override
- public void handleRequestSuccess(SyncStorageResponse response) {
- Logger.debug(LOG_TAG, "Upload succeeded.");
- uploadAttemptsCount.set(0);
-
- // X-Weave-Timestamp is the modified time of uploaded records.
- // Always persist this.
- final long responseTimestamp = response.normalizedWeaveTimestamp();
- Logger.trace(LOG_TAG, "Timestamp from header is: " + responseTimestamp);
-
- if (responseTimestamp == -1) {
- final String message = "Response did not contain a valid timestamp.";
- session.abort(new RuntimeException(message), message);
- return;
- }
-
- BaseResource.consumeEntity(response);
- session.config.persistServerClientsTimestamp(responseTimestamp);
-
- // If we're not uploading our record, we're done here; just
- // clean up and finish.
- if (!currentlyUploadingLocalRecord) {
- // TODO: check failed uploads in body.
- clearRecordsToUpload();
- checkAndUpload();
- return;
- }
-
- // If we're processing our record, we have a little more cleanup
- // to do.
- shouldUploadLocalRecord = false;
- session.config.persistServerClientRecordTimestamp(responseTimestamp);
- session.advance();
- }
-
- @Override
- public void handleRequestFailure(SyncStorageResponse response) {
- int statusCode = response.getStatusCode();
-
- // If upload failed because of `ifUnmodifiedSince` then there are new
- // commands uploaded to our record. We must download and process them first.
- if (!shouldUploadLocalRecord ||
- statusCode == HttpStatus.SC_PRECONDITION_FAILED ||
- uploadAttemptsCount.incrementAndGet() > MAX_UPLOAD_FAILURE_COUNT) {
-
- Logger.debug(LOG_TAG, "Client upload failed. Aborting sync.");
- if (!currentlyUploadingLocalRecord) {
- modifiedClientsToUpload.clear(); // These will be redownloaded.
- }
- BaseResource.consumeEntity(response); // The exception thrown should need the response body.
- session.abort(new HTTPFailureException(response), "Client upload failed.");
- return;
- }
- Logger.trace(LOG_TAG, "Retrying upload…");
- // Preconditions:
- // shouldUploadLocalRecord == true &&
- // statusCode != 412 &&
- // uploadAttemptCount < MAX_UPLOAD_FAILURE_COUNT
- checkAndUpload();
- }
-
- @Override
- public void handleRequestError(Exception ex) {
- Logger.info(LOG_TAG, "Client upload error. Aborting sync.");
- session.abort(ex, "Client upload failed.");
- }
-
- @Override
- public KeyBundle keyBundle() {
- try {
- return session.keyBundleForCollection(COLLECTION_NAME);
- } catch (NoCollectionKeysSetException e) {
- return null;
- }
- }
- }
-
- @Override
- public void execute() throws NoSuchStageException {
- // We can be disabled just for this sync.
- boolean enabledThisSync = session.isEngineLocallyEnabled(STAGE_NAME);
- if (!enabledThisSync) {
- // These log messages look best when they match the messages in ServerSyncStage.
- Logger.debug(LOG_TAG, "Stage " + STAGE_NAME + " disabled just for this sync.");
- Logger.info(LOG_TAG, "Skipping stage " + STAGE_NAME + ".");
- session.advance();
- return;
- }
-
- if (shouldDownload()) {
- downloadClientRecords(); // Will kick off upload, too…
- } else {
- // Upload if necessary.
- }
- }
-
- @Override
- protected void resetLocal() {
- // Clear timestamps and local data.
- session.config.persistServerClientRecordTimestamp(0L); // TODO: roll these into one.
- session.config.persistServerClientsTimestamp(0L);
-
- session.getClientsDelegate().setClientsCount(0);
- try {
- getClientsDatabaseAccessor().wipeDB();
- } finally {
- closeDataAccessor();
- }
- }
-
- @Override
- protected void wipeLocal() throws Exception {
- // Nothing more to do.
- this.resetLocal();
- }
-
- @Override
- public Integer getStorageVersion() {
- return VersionConstants.CLIENTS_ENGINE_VERSION;
- }
-
- protected String getLocalClientVersion() {
- return AppConstants.MOZ_APP_VERSION;
- }
-
- @SuppressWarnings("unchecked")
- protected JSONArray getLocalClientProtocols() {
- final JSONArray protocols = new JSONArray();
- protocols.add(ClientRecord.PROTOCOL_LEGACY_SYNC);
- protocols.add(ClientRecord.PROTOCOL_FXA_SYNC);
- return protocols;
- }
-
- protected ClientRecord newLocalClientRecord(ClientsDataDelegate delegate) {
- final String ourGUID = delegate.getAccountGUID();
- final String ourName = delegate.getClientName();
-
- ClientRecord r = new ClientRecord(ourGUID);
- r.name = ourName;
- r.version = getLocalClientVersion();
- r.protocols = getLocalClientProtocols();
-
- r.os = "Android";
- r.application = AppConstants.MOZ_APP_DISPLAYNAME;
- r.appPackage = AppConstants.ANDROID_PACKAGE_NAME;
- r.device = android.os.Build.MODEL;
- r.formfactor = delegate.getFormFactor();
-
- Context context = session.getContext();
- final Account account = FirefoxAccounts.getFirefoxAccount(context);
- if (account != null) {
- final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account);
- final String deviceId = fxAccount.getDeviceId();
- if (!TextUtils.isEmpty(deviceId)) {
- r.fxaDeviceId = deviceId;
- }
- }
-
- return r;
- }
-
- // TODO: Bug 726055 - More considered handling of when to sync.
- protected boolean shouldDownload() {
- // Ask info/collections whether a download is needed.
- return true;
- }
-
- protected boolean shouldUpload() {
- if (shouldUploadLocalRecord) {
- return true;
- }
-
- long lastUpload = session.config.getPersistedServerClientRecordTimestamp(); // Defaults to 0.
- if (lastUpload == 0) {
- return true;
- }
-
- if (session.getClientsDelegate().getLastModifiedTimestamp() > lastUpload) {
- // Something's changed locally since we last uploaded.
- return true;
- }
-
- // Note the opportunity for clock drift problems here.
- // TODO: if we track download times, we can use the timestamp of most
- // recent download response instead of the current time.
- long now = System.currentTimeMillis();
- long age = now - lastUpload;
- return age >= CLIENTS_TTL_REFRESH;
- }
-
- protected void handleDownloadedLocalRecord(ClientRecord r) {
- session.config.persistServerClientRecordTimestamp(r.lastModified);
-
- if (!getLocalClientVersion().equals(r.version) ||
- !getLocalClientProtocols().equals(r.protocols)) {
- shouldUploadLocalRecord = true;
- }
- processCommands(r.commands);
- }
-
- protected void processCommands(JSONArray commands) {
- if (commands == null ||
- commands.size() == 0) {
- return;
- }
-
- shouldUploadLocalRecord = true;
- CommandProcessor processor = CommandProcessor.getProcessor();
-
- for (Object o : commands) {
- processor.processCommand(session, new ExtendedJSONObject((JSONObject) o));
- }
- }
-
- @SuppressWarnings("unchecked")
- protected void addCommands(ClientRecord record) throws NullCursorException {
- Logger.trace(LOG_TAG, "Adding commands to " + record.guid);
- List<Command> commands = db.fetchCommandsForClient(record.guid);
-
- if (commands == null || commands.size() == 0) {
- Logger.trace(LOG_TAG, "No commands to add.");
- return;
- }
-
- for (Command command : commands) {
- JSONObject jsonCommand = command.asJSONObject();
- if (record.commands == null) {
- record.commands = new JSONArray();
- }
- record.commands.add(jsonCommand);
- }
- modifiedClientsToUpload.add(record);
- }
-
- @SuppressWarnings("unchecked")
- protected void uploadRemoteRecords() {
- Logger.trace(LOG_TAG, "In uploadRemoteRecords. Uploading " + modifiedClientsToUpload.size() + " records" );
-
- for (ClientRecord r : modifiedClientsToUpload) {
- Logger.trace(LOG_TAG, ">> Uploading record " + r.guid + ": " + r.name);
- }
-
- if (modifiedClientsToUpload.size() == 1) {
- ClientRecord record = modifiedClientsToUpload.get(0);
- Logger.debug(LOG_TAG, "Only 1 remote record to upload.");
- Logger.debug(LOG_TAG, "Record last modified: " + record.lastModified);
- CryptoRecord cryptoRecord = encryptClientRecord(record);
- if (cryptoRecord != null) {
- clientUploadDelegate.setUploadDetails(false);
- this.uploadClientRecord(cryptoRecord);
- }
- return;
- }
-
- JSONArray cryptoRecords = new JSONArray();
- for (ClientRecord record : modifiedClientsToUpload) {
- Logger.trace(LOG_TAG, "Record " + record.guid + " is being uploaded" );
-
- CryptoRecord cryptoRecord = encryptClientRecord(record);
- cryptoRecords.add(cryptoRecord.toJSONObject());
- }
- Logger.debug(LOG_TAG, "Uploading records: " + cryptoRecords.size());
- clientUploadDelegate.setUploadDetails(false);
- this.uploadClientRecords(cryptoRecords);
- }
-
- protected void checkAndUpload() {
- if (!shouldUpload()) {
- Logger.debug(LOG_TAG, "Not uploading client record.");
- session.advance();
- return;
- }
-
- final ClientRecord localClient = newLocalClientRecord(session.getClientsDelegate());
- clientUploadDelegate.setUploadDetails(true);
- CryptoRecord cryptoRecord = encryptClientRecord(localClient);
- if (cryptoRecord != null) {
- this.uploadClientRecord(cryptoRecord);
- }
- }
-
- protected CryptoRecord encryptClientRecord(ClientRecord recordToUpload) {
- // Generate CryptoRecord from ClientRecord to upload.
- final String encryptionFailure = "Couldn't encrypt new client record.";
-
- try {
- CryptoRecord cryptoRecord = recordToUpload.getEnvelope();
- cryptoRecord.keyBundle = clientUploadDelegate.keyBundle();
- if (cryptoRecord.keyBundle == null) {
- session.abort(new NoCollectionKeysSetException(), "No collection keys set.");
- return null;
- }
- return cryptoRecord.encrypt();
- } catch (UnsupportedEncodingException e) {
- session.abort(e, encryptionFailure + " Unsupported encoding.");
- } catch (CryptoException e) {
- session.abort(e, encryptionFailure);
- }
- return null;
- }
-
- public void clearRecordsToUpload() {
- try {
- getClientsDatabaseAccessor().wipeCommandsTable();
- modifiedClientsToUpload.clear();
- } finally {
- closeDataAccessor();
- }
- }
-
- protected void downloadClientRecords() {
- shouldWipe = true;
- clientDownloadDelegate = makeClientDownloadDelegate();
-
- try {
- final URI getURI = session.config.collectionURI(COLLECTION_NAME, true);
- final SyncStorageCollectionRequest request = new SyncStorageCollectionRequest(getURI);
- request.delegate = clientDownloadDelegate;
-
- Logger.trace(LOG_TAG, "Downloading client records.");
- request.get();
- } catch (URISyntaxException e) {
- session.abort(e, "Invalid URI.");
- }
- }
-
- protected void uploadClientRecords(JSONArray records) {
- Logger.trace(LOG_TAG, "Uploading " + records.size() + " client records.");
- try {
- final URI postURI = session.config.collectionURI(COLLECTION_NAME, false);
- final SyncStorageRecordRequest request = new SyncStorageRecordRequest(postURI);
- request.delegate = clientUploadDelegate;
- request.post(records);
- } catch (URISyntaxException e) {
- session.abort(e, "Invalid URI.");
- } catch (Exception e) {
- session.abort(e, "Unable to parse body.");
- }
- }
-
- /**
- * Upload a client record via HTTP POST to the parent collection.
- */
- protected void uploadClientRecord(CryptoRecord record) {
- Logger.debug(LOG_TAG, "Uploading client record " + record.guid);
- try {
- final URI postURI = session.config.collectionURI(COLLECTION_NAME);
- final SyncStorageRecordRequest request = new SyncStorageRecordRequest(postURI);
- request.delegate = clientUploadDelegate;
- request.post(record);
- } catch (URISyntaxException e) {
- session.abort(e, "Invalid URI.");
- }
- }
-
- protected ClientDownloadDelegate makeClientDownloadDelegate() {
- return new ClientDownloadDelegate();
- }
-
- protected void wipeAndStore(ClientRecord record) {
- final ClientsDatabaseAccessor db = getClientsDatabaseAccessor();
- if (shouldWipe) {
- db.wipeClientsTable();
- shouldWipe = false;
- }
- if (record != null) {
- db.store(record);
- }
- }
-}