public GlobalSession( SyncConfiguration config, BaseGlobalSessionCallback callback, Context context, Bundle extras, ClientsDataDelegate clientsDelegate, NodeAssignmentCallback nodeAssignmentCallback) throws SyncConfigurationException, IllegalArgumentException, IOException, ParseException, NonObjectJSONException { if (callback == null) { throw new IllegalArgumentException("Must provide a callback to GlobalSession constructor."); } Logger.debug(LOG_TAG, "GlobalSession initialized with bundle " + extras); this.callback = callback; this.context = context; this.clientsDelegate = clientsDelegate; this.nodeAssignmentCallback = nodeAssignmentCallback; this.config = config; registerCommands(); prepareStages(); Collection<String> knownStageNames = SyncConfiguration.validEngineNames(); config.stagesToSync = Utils.getStagesToSyncFromBundle(knownStageNames, extras); // TODO: data-driven plan for the sync, referring to prepareStages. }
/** * Engines to include in a fresh meta/global record. * * <p>Returns either the persisted engine names (perhaps we have been node re-assigned and are * initializing a clean server: we want to upload the persisted engine names so that we don't * accidentally disable engines that Android Sync doesn't recognize), or the set of engines names * that Android Sync implements. * * @return set of engine names. */ protected Set<String> enabledEngineNames() { if (config.enabledEngineNames != null) { return config.enabledEngineNames; } // These are the default set of engine names. Set<String> validEngineNames = SyncConfiguration.validEngineNames(); // If the user hasn't set any selected engines, that's okay -- default to // everything. if (config.userSelectedEngines == null) { return validEngineNames; } // userSelectedEngines has keys that are engine names, and boolean values // corresponding to whether the user asked for the engine to sync or not. If // an engine is not present, that means the user didn't change its sync // setting. Since we default to everything on, that means the user didn't // turn it off; therefore, it's included in the set of engines to sync. Set<String> validAndSelectedEngineNames = new HashSet<String>(); for (String engineName : validEngineNames) { if (config.userSelectedEngines.containsKey(engineName) && !config.userSelectedEngines.get(engineName)) { continue; } validAndSelectedEngineNames.add(engineName); } return validAndSelectedEngineNames; }
/** Perform appropriate backoff etc. extraction. */ public void interpretHTTPFailure(HttpResponse response) { // TODO: handle permanent rejection. long responseBackoff = (new SyncResponse(response)).totalBackoffInMilliseconds(); if (responseBackoff > 0) { callback.requestBackoff(responseBackoff); } if (response.getStatusLine() != null) { final int statusCode = response.getStatusLine().getStatusCode(); switch (statusCode) { case 400: SyncStorageResponse storageResponse = new SyncStorageResponse(response); this.interpretHTTPBadRequestBody(storageResponse); break; case 401: /* * Alert our callback we have a 401 on a cluster URL. This GlobalSession * will fail, but the next one will fetch a new cluster URL and will * distinguish between "node reassignment" and "user password changed". */ callback.informUnauthorizedResponse(this, config.getClusterURL()); break; } } }
protected void wipeServer( final AuthHeaderProvider authHeaderProvider, final WipeServerDelegate wipeDelegate) { SyncStorageRequest request; final GlobalSession self = this; try { request = new SyncStorageRequest(config.storageURL()); } catch (URISyntaxException ex) { Logger.warn(LOG_TAG, "Invalid URI in wipeServer."); wipeDelegate.onWipeFailed(ex); return; } request.delegate = new SyncStorageRequestDelegate() { @Override public String ifUnmodifiedSince() { return null; } @Override public void handleRequestSuccess(SyncStorageResponse response) { BaseResource.consumeEntity(response); wipeDelegate.onWiped(response.normalizedWeaveTimestamp()); } @Override public void handleRequestFailure(SyncStorageResponse response) { Logger.warn( LOG_TAG, "Got request failure " + response.getStatusCode() + " in wipeServer."); // Process HTTP failures here to pick up backoffs, etc. self.interpretHTTPFailure(response.httpResponse()); BaseResource.consumeEntity( response); // The exception thrown should not need the body of the response. wipeDelegate.onWipeFailed(new HTTPFailureException(response)); } @Override public void handleRequestError(Exception ex) { Logger.warn(LOG_TAG, "Got exception in wipeServer.", ex); wipeDelegate.onWipeFailed(ex); } @Override public AuthHeaderProvider getAuthHeaderProvider() { return GlobalSession.this.getAuthHeaderProvider(); } }; request.delete(); }
public URI wboURI(String collection, String id) throws URISyntaxException { return config.wboURI(collection, id); }
/* * Config passthrough for convenience. */ public AuthHeaderProvider getAuthHeaderProvider() { return config.getAuthHeaderProvider(); }
/* * Key accessors. */ public KeyBundle keyBundleForCollection(String collection) throws NoCollectionKeysSetException { return config.getCollectionKeys().keyBundleForCollection(collection); }
/* * meta/global callbacks. */ public void processMetaGlobal(MetaGlobal global) { config.metaGlobal = global; Long storageVersion = global.getStorageVersion(); if (storageVersion == null) { Logger.warn( LOG_TAG, "Malformed remote meta/global: could not retrieve remote storage version."); freshStart(); return; } if (storageVersion < STORAGE_VERSION) { Logger.warn( LOG_TAG, "Outdated server: reported " + "remote storage version " + storageVersion + " < " + "local storage version " + STORAGE_VERSION); freshStart(); return; } if (storageVersion > STORAGE_VERSION) { Logger.warn( LOG_TAG, "Outdated client: reported " + "remote storage version " + storageVersion + " > " + "local storage version " + STORAGE_VERSION); requiresUpgrade(); return; } String remoteSyncID = global.getSyncID(); if (remoteSyncID == null) { Logger.warn(LOG_TAG, "Malformed remote meta/global: could not retrieve remote syncID."); freshStart(); return; } String localSyncID = config.syncID; if (!remoteSyncID.equals(localSyncID)) { Logger.warn( LOG_TAG, "Remote syncID different from local syncID: resetting client and assuming remote syncID."); resetAllStages(); config.purgeCryptoKeys(); config.syncID = remoteSyncID; } // Compare lastModified timestamps for remote/local engine selection times. Logger.debug( LOG_TAG, "Comparing local engine selection timestamp [" + config.userSelectedEnginesTimestamp + "] to server meta/global timestamp [" + config.persistedMetaGlobal().lastModified() + "]."); if (config.userSelectedEnginesTimestamp < config.persistedMetaGlobal().lastModified()) { // Remote has later meta/global timestamp. Don't upload engine changes. config.userSelectedEngines = null; } // Persist enabled engine names. config.enabledEngineNames = global.getEnabledEngineNames(); if (config.enabledEngineNames == null) { Logger.warn(LOG_TAG, "meta/global reported no enabled engine names!"); } else { if (Logger.shouldLogVerbose(LOG_TAG)) { Logger.trace( LOG_TAG, "Persisting enabled engine names '" + Utils.toCommaSeparatedString(config.enabledEngineNames) + "' from meta/global."); } } config.persistToPrefs(); advance(); }
public void fetchInfoCollections(JSONRecordFetchDelegate callback) throws URISyntaxException { final JSONRecordFetcher fetcher = new JSONRecordFetcher(config.infoCollectionsURL(), getAuthHeaderProvider()); fetcher.fetch(callback); }