зеркало из https://github.com/mozilla/pjs.git
Bug 730626 - Implement resetting. r=nalexander, a=blocking-fennec
This commit is contained in:
Родитель
75ea8ab159
Коммит
46a49ddccd
|
@ -0,0 +1,15 @@
|
|||
/* 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;
|
||||
|
||||
public class EngineSettings {
|
||||
public final String syncID;
|
||||
public final int version;
|
||||
|
||||
public EngineSettings(final String syncID, final int version) {
|
||||
this.syncID = syncID;
|
||||
this.version = version;
|
||||
}
|
||||
}
|
|
@ -131,6 +131,30 @@ public class ExtendedJSONObject {
|
|||
return (String) this.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an Integer if the value for this key is an Integer, Long, or String
|
||||
* that can be parsed as a base 10 Integer.
|
||||
* Passes through null.
|
||||
*
|
||||
* @throws NumberFormatException
|
||||
*/
|
||||
public Integer getIntegerSafely(String key) throws NumberFormatException {
|
||||
Object val = this.object.get(key);
|
||||
if (val == null) {
|
||||
return null;
|
||||
}
|
||||
if (val instanceof Integer) {
|
||||
return (Integer) val;
|
||||
}
|
||||
if (val instanceof Long) {
|
||||
return new Integer(((Long) val).intValue());
|
||||
}
|
||||
if (val instanceof String) {
|
||||
return Integer.parseInt((String) val, 10);
|
||||
}
|
||||
throw new NumberFormatException("Expecting Integer, got " + val.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a server timestamp value as milliseconds since epoch.
|
||||
* @param key
|
||||
|
|
|
@ -8,7 +8,11 @@ import java.io.IOException;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
@ -31,9 +35,7 @@ import org.mozilla.gecko.sync.net.SyncStorageRequest;
|
|||
import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
|
||||
import org.mozilla.gecko.sync.net.SyncStorageResponse;
|
||||
import org.mozilla.gecko.sync.stage.AndroidBrowserBookmarksServerSyncStage;
|
||||
import org.mozilla.gecko.sync.stage.FormHistoryServerSyncStage;
|
||||
import org.mozilla.gecko.sync.stage.AndroidBrowserHistoryServerSyncStage;
|
||||
import org.mozilla.gecko.sync.stage.PasswordsServerSyncStage;
|
||||
import org.mozilla.gecko.sync.stage.CheckPreconditionsStage;
|
||||
import org.mozilla.gecko.sync.stage.CompletedStage;
|
||||
import org.mozilla.gecko.sync.stage.EnsureClusterURLStage;
|
||||
|
@ -41,9 +43,11 @@ import org.mozilla.gecko.sync.stage.EnsureCrypto5KeysStage;
|
|||
import org.mozilla.gecko.sync.stage.FennecTabsServerSyncStage;
|
||||
import org.mozilla.gecko.sync.stage.FetchInfoCollectionsStage;
|
||||
import org.mozilla.gecko.sync.stage.FetchMetaGlobalStage;
|
||||
import org.mozilla.gecko.sync.stage.FormHistoryServerSyncStage;
|
||||
import org.mozilla.gecko.sync.stage.GlobalSyncStage;
|
||||
import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
|
||||
import org.mozilla.gecko.sync.stage.NoSuchStageException;
|
||||
import org.mozilla.gecko.sync.stage.PasswordsServerSyncStage;
|
||||
import org.mozilla.gecko.sync.stage.SyncClientsEngineStage;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -152,6 +156,8 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
|||
|
||||
registerCommands();
|
||||
prepareStages();
|
||||
|
||||
// TODO: data-driven plan for the sync, referring to prepareStages.
|
||||
}
|
||||
|
||||
protected void registerCommands() {
|
||||
|
@ -160,14 +166,32 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
|||
processor.registerCommand("resetEngine", new CommandRunner() {
|
||||
@Override
|
||||
public void executeCommand(List<String> args) {
|
||||
resetClient(new String[] { args.get(0) });
|
||||
HashSet<String> names = new HashSet<String>();
|
||||
names.add(args.get(0));
|
||||
resetStagesByName(names);
|
||||
}
|
||||
});
|
||||
|
||||
processor.registerCommand("resetAll", new CommandRunner() {
|
||||
@Override
|
||||
public void executeCommand(List<String> args) {
|
||||
resetClient(null);
|
||||
resetAllStages();
|
||||
}
|
||||
});
|
||||
|
||||
processor.registerCommand("wipeEngine", new CommandRunner() {
|
||||
@Override
|
||||
public void executeCommand(List<String> args) {
|
||||
HashSet<String> names = new HashSet<String>();
|
||||
names.add(args.get(0));
|
||||
wipeStagesByName(names);
|
||||
}
|
||||
});
|
||||
|
||||
processor.registerCommand("wipeAll", new CommandRunner() {
|
||||
@Override
|
||||
public void executeCommand(List<String> args) {
|
||||
wipeAllStages();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -180,24 +204,31 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
|||
}
|
||||
|
||||
protected void prepareStages() {
|
||||
stages = new HashMap<Stage, GlobalSyncStage>();
|
||||
stages.put(Stage.checkPreconditions, new CheckPreconditionsStage());
|
||||
stages.put(Stage.ensureClusterURL, new EnsureClusterURLStage());
|
||||
stages.put(Stage.fetchInfoCollections, new FetchInfoCollectionsStage());
|
||||
stages.put(Stage.fetchMetaGlobal, new FetchMetaGlobalStage());
|
||||
stages.put(Stage.ensureKeysStage, new EnsureCrypto5KeysStage());
|
||||
stages.put(Stage.syncClientsEngine, new SyncClientsEngineStage());
|
||||
HashMap<Stage, GlobalSyncStage> stages = new HashMap<Stage, GlobalSyncStage>();
|
||||
|
||||
// TODO: more stages.
|
||||
stages.put(Stage.syncTabs, new FennecTabsServerSyncStage());
|
||||
stages.put(Stage.syncPasswords, new PasswordsServerSyncStage());
|
||||
stages.put(Stage.syncBookmarks, new AndroidBrowserBookmarksServerSyncStage());
|
||||
stages.put(Stage.syncHistory, new AndroidBrowserHistoryServerSyncStage());
|
||||
stages.put(Stage.syncFormHistory, new FormHistoryServerSyncStage());
|
||||
stages.put(Stage.completed, new CompletedStage());
|
||||
stages.put(Stage.checkPreconditions, new CheckPreconditionsStage(this));
|
||||
stages.put(Stage.ensureClusterURL, new EnsureClusterURLStage(this));
|
||||
stages.put(Stage.fetchInfoCollections, new FetchInfoCollectionsStage(this));
|
||||
stages.put(Stage.fetchMetaGlobal, new FetchMetaGlobalStage(this));
|
||||
stages.put(Stage.ensureKeysStage, new EnsureCrypto5KeysStage(this));
|
||||
stages.put(Stage.syncClientsEngine, new SyncClientsEngineStage(this));
|
||||
|
||||
stages.put(Stage.syncTabs, new FennecTabsServerSyncStage(this));
|
||||
stages.put(Stage.syncPasswords, new PasswordsServerSyncStage(this));
|
||||
stages.put(Stage.syncBookmarks, new AndroidBrowserBookmarksServerSyncStage(this));
|
||||
stages.put(Stage.syncHistory, new AndroidBrowserHistoryServerSyncStage(this));
|
||||
stages.put(Stage.syncFormHistory, new FormHistoryServerSyncStage(this));
|
||||
|
||||
stages.put(Stage.completed, new CompletedStage(this));
|
||||
|
||||
this.stages = Collections.unmodifiableMap(stages);
|
||||
}
|
||||
|
||||
protected GlobalSyncStage getStageByName(Stage next) throws NoSuchStageException {
|
||||
public GlobalSyncStage getSyncStageByName(String name) throws NoSuchStageException {
|
||||
return getSyncStageByName(Stage.byName(name));
|
||||
}
|
||||
|
||||
public GlobalSyncStage getSyncStageByName(Stage next) throws NoSuchStageException {
|
||||
GlobalSyncStage stage = stages.get(next);
|
||||
if (stage == null) {
|
||||
throw new NoSuchStageException(next);
|
||||
|
@ -205,6 +236,32 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
|||
return stage;
|
||||
}
|
||||
|
||||
public Collection<GlobalSyncStage> getSyncStagesByEnum(Collection<Stage> enums) {
|
||||
ArrayList<GlobalSyncStage> out = new ArrayList<GlobalSyncStage>();
|
||||
for (Stage name : enums) {
|
||||
try {
|
||||
GlobalSyncStage stage = this.getSyncStageByName(name);
|
||||
out.add(stage);
|
||||
} catch (NoSuchStageException e) {
|
||||
Logger.warn(LOG_TAG, "Unable to find stage with name " + name);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public Collection<GlobalSyncStage> getSyncStagesByName(Collection<String> names) {
|
||||
ArrayList<GlobalSyncStage> out = new ArrayList<GlobalSyncStage>();
|
||||
for (String name : names) {
|
||||
try {
|
||||
GlobalSyncStage stage = this.getSyncStageByName(name);
|
||||
out.add(stage);
|
||||
} catch (NoSuchStageException e) {
|
||||
Logger.warn(LOG_TAG, "Unable to find stage with name " + name);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance and loop around the stages of a sync.
|
||||
* @param current
|
||||
|
@ -232,7 +289,7 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
|||
Stage next = nextStage(this.currentState);
|
||||
GlobalSyncStage nextStage;
|
||||
try {
|
||||
nextStage = this.getStageByName(next);
|
||||
nextStage = this.getSyncStageByName(next);
|
||||
} catch (NoSuchStageException e) {
|
||||
this.abort(e, "No such stage " + next);
|
||||
return;
|
||||
|
@ -240,7 +297,7 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
|||
this.currentState = next;
|
||||
Logger.info(LOG_TAG, "Running next stage " + next + " (" + nextStage + ")...");
|
||||
try {
|
||||
nextStage.execute(this);
|
||||
nextStage.execute();
|
||||
} catch (Exception ex) {
|
||||
Logger.warn(LOG_TAG, "Caught exception " + ex + " running stage " + next);
|
||||
this.abort(ex, "Uncaught exception in stage.");
|
||||
|
@ -435,10 +492,9 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
|||
String localSyncID = this.getSyncID();
|
||||
if (!remoteSyncID.equals(localSyncID)) {
|
||||
// Sync ID has changed. Reset timestamps and fetch new keys.
|
||||
resetClient(null);
|
||||
resetAllStages();
|
||||
config.purgeCryptoKeys();
|
||||
config.syncID = remoteSyncID;
|
||||
// TODO TODO TODO
|
||||
}
|
||||
config.persistToPrefs();
|
||||
advance();
|
||||
|
@ -486,7 +542,7 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
|||
|
||||
@Override
|
||||
public void onWiped(long timestamp) {
|
||||
session.resetClient(null);
|
||||
session.resetAllStages();
|
||||
session.config.purgeCryptoKeys();
|
||||
session.config.persistToPrefs();
|
||||
|
||||
|
@ -558,9 +614,26 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
|||
freshStartDelegate.onFreshStartFailed(e);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Note that we do not yet implement wipeRemote: it's only necessary for
|
||||
// first sync options.
|
||||
// -- reset local stages, wipe server for each stage *except* clients
|
||||
// (stages only, not whole server!), send wipeEngine commands to each client.
|
||||
//
|
||||
// Similarly for startOver (because we don't receive that notification).
|
||||
// -- remove client data from server, reset local stages, clear keys, reset
|
||||
// backoff, clear all prefs, discard credentials.
|
||||
//
|
||||
// Change passphrase: wipe entire server, reset client to force upload, sync.
|
||||
//
|
||||
// When an engine is disabled: wipe its collections on the server, reupload
|
||||
// meta/global.
|
||||
//
|
||||
// On syncing each stage: if server has engine version 0 or old, wipe server,
|
||||
// reset client to prompt reupload.
|
||||
// If sync ID mismatch: take that syncID and reset client.
|
||||
|
||||
private void wipeServer(final CredentialsSource credentials, final WipeServerDelegate wipeDelegate) {
|
||||
SyncStorageRequest request;
|
||||
final GlobalSession self = this;
|
||||
|
@ -609,16 +682,62 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
|||
request.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset our state. Clear our sync ID, reset each engine, drop any
|
||||
* cached records.
|
||||
*/
|
||||
private void resetClient(String[] engines) {
|
||||
if (engines == null) {
|
||||
// Set `engines` to be *all* the engines.
|
||||
public void wipeAllStages() {
|
||||
Logger.info(LOG_TAG, "Wiping all stages.");
|
||||
// Includes "clients".
|
||||
this.wipeStagesByEnum(Stage.getNamedStages());
|
||||
}
|
||||
|
||||
public static void wipeStages(Collection<GlobalSyncStage> stages) {
|
||||
for (GlobalSyncStage stage : stages) {
|
||||
try {
|
||||
Logger.info(LOG_TAG, "Wiping " + stage);
|
||||
stage.wipeLocal();
|
||||
} catch (Exception e) {
|
||||
Logger.error(LOG_TAG, "Ignoring wipe failure for stage " + stage, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void wipeStagesByEnum(Collection<Stage> stages) {
|
||||
GlobalSession.wipeStages(this.getSyncStagesByEnum(stages));
|
||||
}
|
||||
|
||||
public void wipeStagesByName(Collection<String> names) {
|
||||
GlobalSession.wipeStages(this.getSyncStagesByName(names));
|
||||
}
|
||||
|
||||
public void resetAllStages() {
|
||||
Logger.info(LOG_TAG, "Resetting all stages.");
|
||||
// Includes "clients".
|
||||
this.resetStagesByEnum(Stage.getNamedStages());
|
||||
}
|
||||
|
||||
public static void resetStages(Collection<GlobalSyncStage> stages) {
|
||||
for (GlobalSyncStage stage : stages) {
|
||||
try {
|
||||
Logger.info(LOG_TAG, "Resetting " + stage);
|
||||
stage.resetLocal();
|
||||
} catch (Exception e) {
|
||||
Logger.error(LOG_TAG, "Ignoring reset failure for stage " + stage, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void resetStagesByEnum(Collection<Stage> stages) {
|
||||
GlobalSession.resetStages(this.getSyncStagesByEnum(stages));
|
||||
}
|
||||
|
||||
public void resetStagesByName(Collection<String> names) {
|
||||
for (String name : names) {
|
||||
try {
|
||||
GlobalSyncStage stage = this.getSyncStageByName(name);
|
||||
Logger.info(LOG_TAG, "Resetting " + name + "(" + stage + ")");
|
||||
stage.resetLocal();
|
||||
} catch (NoSuchStageException e) {
|
||||
Logger.warn(LOG_TAG, "Cannot reset stage " + name + ": no such stage.");
|
||||
}
|
||||
}
|
||||
// TODO: futz with config?!
|
||||
// TODO: engines?!
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -635,21 +754,40 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
|||
* Otherwise, returns true if there is an entry for this engine in the
|
||||
* meta/global "engines" object.
|
||||
*
|
||||
* @param engineName
|
||||
* @param engineName the name to check (e.g., "bookmarks").
|
||||
* @param engineSettings
|
||||
* if non-null, verify that the server engine settings are congruent
|
||||
* with this, throwing the appropriate MetaGlobalException if not.
|
||||
* @return
|
||||
* true if the engine with the provided name is present in the
|
||||
* meta/global "engines" object.
|
||||
* meta/global "engines" object, and verification passed.
|
||||
*
|
||||
* @throws MetaGlobalException
|
||||
*/
|
||||
public boolean engineIsEnabled(String engineName) throws MetaGlobalException {
|
||||
public boolean engineIsEnabled(String engineName, EngineSettings engineSettings) throws MetaGlobalException {
|
||||
if (this.config.metaGlobal == null) {
|
||||
throw new MetaGlobalNotSetException();
|
||||
}
|
||||
if (this.config.metaGlobal.engines == null) {
|
||||
throw new MetaGlobalMissingEnginesException();
|
||||
}
|
||||
return this.config.metaGlobal.engines.get(engineName) != null;
|
||||
ExtendedJSONObject engineEntry;
|
||||
try {
|
||||
engineEntry = this.config.metaGlobal.engines.getObject(engineName);
|
||||
} catch (NonObjectJSONException e) {
|
||||
Logger.error(LOG_TAG, "Engine field for " + engineName + " in meta/global is not an object.");
|
||||
throw new MetaGlobalMissingEnginesException();
|
||||
}
|
||||
|
||||
if (engineEntry == null) {
|
||||
Logger.debug(LOG_TAG, "Engine " + engineName + " not enabled: no meta/global entry.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (engineSettings != null) {
|
||||
MetaGlobal.verifyEngineSettings(engineEntry, engineSettings);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public ClientsDataDelegate getClientsDelegate() {
|
||||
|
|
|
@ -8,6 +8,10 @@ import java.io.IOException;
|
|||
import java.net.URISyntaxException;
|
||||
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.mozilla.gecko.sync.MetaGlobalException.MetaGlobalMalformedSyncIDException;
|
||||
import org.mozilla.gecko.sync.MetaGlobalException.MetaGlobalMalformedVersionException;
|
||||
import org.mozilla.gecko.sync.MetaGlobalException.MetaGlobalStaleClientSyncIDException;
|
||||
import org.mozilla.gecko.sync.MetaGlobalException.MetaGlobalStaleClientVersionException;
|
||||
import org.mozilla.gecko.sync.delegates.MetaGlobalDelegate;
|
||||
import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
|
||||
import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
|
||||
|
@ -105,6 +109,55 @@ public class MetaGlobal implements SyncStorageRequestDelegate {
|
|||
this.engines = engines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the server settings and local settings match.
|
||||
* Throws a specific exception if that's not the case.
|
||||
*/
|
||||
public static void verifyEngineSettings(ExtendedJSONObject engineEntry,
|
||||
EngineSettings engineSettings)
|
||||
throws MetaGlobalMalformedVersionException, MetaGlobalMalformedSyncIDException, MetaGlobalStaleClientVersionException, MetaGlobalStaleClientSyncIDException {
|
||||
|
||||
if (engineEntry == null) {
|
||||
throw new IllegalArgumentException("engineEntry cannot be null.");
|
||||
}
|
||||
if (engineSettings == null) {
|
||||
throw new IllegalArgumentException("engineSettings cannot be null.");
|
||||
}
|
||||
try {
|
||||
Integer version = engineEntry.getIntegerSafely("version");
|
||||
if (version == null ||
|
||||
version.intValue() == 0) {
|
||||
// Invalid version. Wipe the server.
|
||||
throw new MetaGlobalException.MetaGlobalMalformedVersionException();
|
||||
}
|
||||
if (version > engineSettings.version) {
|
||||
// We're out of date.
|
||||
throw new MetaGlobalException.MetaGlobalStaleClientVersionException(version);
|
||||
}
|
||||
try {
|
||||
String syncID = engineEntry.getString("syncID");
|
||||
if (syncID == null) {
|
||||
// No syncID. This should never happen. Wipe the server.
|
||||
throw new MetaGlobalException.MetaGlobalMalformedSyncIDException();
|
||||
}
|
||||
if (!syncID.equals(engineSettings.syncID)) {
|
||||
// Our syncID is wrong. Reset client and take the server syncID.
|
||||
throw new MetaGlobalException.MetaGlobalStaleClientSyncIDException(syncID);
|
||||
}
|
||||
// Great!
|
||||
return;
|
||||
|
||||
} catch (ClassCastException e) {
|
||||
// Malformed syncID on the server. Wipe the server.
|
||||
throw new MetaGlobalException.MetaGlobalMalformedSyncIDException();
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// Invalid version. Wipe the server.
|
||||
throw new MetaGlobalException.MetaGlobalMalformedVersionException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getSyncID() {
|
||||
return syncID;
|
||||
}
|
||||
|
|
|
@ -1,42 +1,37 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Android Sync Client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Richard Newman <rnewman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
/* 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;
|
||||
|
||||
public class MetaGlobalException extends SyncException {
|
||||
private static final long serialVersionUID = -6182315615113508925L;
|
||||
|
||||
public static class MetaGlobalMalformedSyncIDException extends MetaGlobalException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
|
||||
public static class MetaGlobalMalformedVersionException extends MetaGlobalException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
|
||||
public static class MetaGlobalOutdatedVersionException extends MetaGlobalException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
|
||||
public static class MetaGlobalStaleClientVersionException extends MetaGlobalException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public final int serverVersion;
|
||||
public MetaGlobalStaleClientVersionException(final int version) {
|
||||
this.serverVersion = version;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MetaGlobalStaleClientSyncIDException extends MetaGlobalException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public final String serverSyncID;
|
||||
public MetaGlobalStaleClientSyncIDException(final String syncID) {
|
||||
this.serverSyncID = syncID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -786,13 +786,13 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo
|
|||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// Clear our queued deletions.
|
||||
deletionManager.clear();
|
||||
super.run();
|
||||
} catch (Exception ex) {
|
||||
delegate.onWipeFailed(ex);
|
||||
return;
|
||||
}
|
||||
// Clear our queued deletions.
|
||||
deletionManager.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/* 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 org.mozilla.gecko.sync.GlobalSession;
|
||||
|
||||
/**
|
||||
* This is simply a stage that is not responsible for synchronizing repositories.
|
||||
*/
|
||||
public abstract class AbstractNonRepositorySyncStage implements GlobalSyncStage {
|
||||
protected final GlobalSession session;
|
||||
|
||||
public AbstractNonRepositorySyncStage(GlobalSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetLocal() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wipeLocal() {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
|
@ -1,44 +1,12 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Android Sync Client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Richard Newman <rnewman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
/* 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 java.net.URISyntaxException;
|
||||
|
||||
import org.mozilla.gecko.sync.GlobalSession;
|
||||
import org.mozilla.gecko.sync.Logger;
|
||||
import org.mozilla.gecko.sync.MetaGlobalException;
|
||||
import org.mozilla.gecko.sync.repositories.ConstrainedServer11Repository;
|
||||
|
@ -56,6 +24,10 @@ public class AndroidBrowserBookmarksServerSyncStage extends ServerSyncStage {
|
|||
private static final String BOOKMARKS_SORT = "index";
|
||||
private static final long BOOKMARKS_REQUEST_LIMIT = 5000; // Sanity limit.
|
||||
|
||||
public AndroidBrowserBookmarksServerSyncStage(GlobalSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCollection() {
|
||||
return "bookmarks";
|
||||
|
@ -87,7 +59,7 @@ public class AndroidBrowserBookmarksServerSyncStage extends ServerSyncStage {
|
|||
|
||||
@Override
|
||||
protected boolean isEnabled() throws MetaGlobalException {
|
||||
if (session == null || session.getContext() == null) {
|
||||
if (session.getContext() == null) {
|
||||
return false;
|
||||
}
|
||||
boolean migrated = FennecControlHelper.areBookmarksMigrated(session.getContext());
|
||||
|
|
|
@ -39,6 +39,7 @@ package org.mozilla.gecko.sync.stage;
|
|||
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.mozilla.gecko.sync.GlobalSession;
|
||||
import org.mozilla.gecko.sync.Logger;
|
||||
import org.mozilla.gecko.sync.MetaGlobalException;
|
||||
import org.mozilla.gecko.sync.repositories.ConstrainedServer11Repository;
|
||||
|
@ -56,6 +57,10 @@ public class AndroidBrowserHistoryServerSyncStage extends ServerSyncStage {
|
|||
private static final String HISTORY_SORT = "index";
|
||||
private static final long HISTORY_REQUEST_LIMIT = 250;
|
||||
|
||||
public AndroidBrowserHistoryServerSyncStage(GlobalSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCollection() {
|
||||
return "history";
|
||||
|
|
|
@ -1,46 +1,18 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Android Sync Client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Richard Newman <rnewman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
/* 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 org.mozilla.gecko.sync.GlobalSession;
|
||||
|
||||
public class CheckPreconditionsStage implements GlobalSyncStage {
|
||||
public void execute(GlobalSession session) throws NoSuchStageException {
|
||||
public class CheckPreconditionsStage extends AbstractNonRepositorySyncStage {
|
||||
public CheckPreconditionsStage(GlobalSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws NoSuchStageException {
|
||||
session.advance();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,51 +1,22 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Android Sync Client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Richard Newman <rnewman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
/* 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 org.mozilla.gecko.sync.GlobalSession;
|
||||
|
||||
public class CompletedStage implements GlobalSyncStage {
|
||||
|
||||
public class CompletedStage extends AbstractNonRepositorySyncStage {
|
||||
|
||||
public CompletedStage(GlobalSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(GlobalSession session) throws NoSuchStageException {
|
||||
public void execute() throws NoSuchStageException {
|
||||
// TODO: Update tracking timestamps, close connections, etc.
|
||||
// TODO: call clean() on each Repository in the sync constellation.
|
||||
session.completeSync();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,11 @@ import ch.boye.httpclientandroidlib.HttpEntity;
|
|||
import ch.boye.httpclientandroidlib.HttpResponse;
|
||||
import ch.boye.httpclientandroidlib.client.ClientProtocolException;
|
||||
|
||||
public class EnsureClusterURLStage implements GlobalSyncStage {
|
||||
public class EnsureClusterURLStage extends AbstractNonRepositorySyncStage {
|
||||
public EnsureClusterURLStage(GlobalSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
public interface ClusterURLFetchDelegate {
|
||||
/**
|
||||
* 200 - Success.
|
||||
|
@ -172,7 +176,7 @@ public class EnsureClusterURLStage implements GlobalSyncStage {
|
|||
resource.get();
|
||||
}
|
||||
|
||||
public void execute(final GlobalSession session) throws NoSuchStageException {
|
||||
public void execute() throws NoSuchStageException {
|
||||
final URI oldClusterURL = session.config.getClusterURL();
|
||||
final boolean wantNodeAssignment = session.callback.wantNodeAssignment();
|
||||
|
||||
|
|
|
@ -23,16 +23,20 @@ import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
|
|||
import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
|
||||
import org.mozilla.gecko.sync.net.SyncStorageResponse;
|
||||
|
||||
public class EnsureCrypto5KeysStage implements GlobalSyncStage, SyncStorageRequestDelegate, KeyUploadDelegate {
|
||||
public class EnsureCrypto5KeysStage
|
||||
extends AbstractNonRepositorySyncStage
|
||||
implements SyncStorageRequestDelegate, KeyUploadDelegate {
|
||||
|
||||
public EnsureCrypto5KeysStage(GlobalSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
private static final String LOG_TAG = "EnsureC5KeysStage";
|
||||
private static final String CRYPTO_COLLECTION = "crypto";
|
||||
protected GlobalSession session;
|
||||
protected boolean retrying = false;
|
||||
|
||||
@Override
|
||||
public void execute(GlobalSession session) throws NoSuchStageException {
|
||||
this.session = session;
|
||||
|
||||
public void execute() throws NoSuchStageException {
|
||||
InfoCollections infoCollections = session.config.infoCollections;
|
||||
if (infoCollections == null) {
|
||||
session.abort(null, "No info/collections set in EnsureCrypto5KeysStage.");
|
||||
|
@ -161,7 +165,7 @@ public class EnsureCrypto5KeysStage implements GlobalSyncStage, SyncStorageReque
|
|||
Logger.debug(LOG_TAG, "New keys uploaded. Starting stage again to fetch them.");
|
||||
try {
|
||||
retrying = true;
|
||||
this.execute(this.session);
|
||||
this.execute();
|
||||
} catch (NoSuchStageException e) {
|
||||
session.abort(e, "No such stage.");
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ package org.mozilla.gecko.sync.stage;
|
|||
|
||||
import org.mozilla.gecko.sync.repositories.domain.TabsRecord;
|
||||
import org.mozilla.gecko.sync.CryptoRecord;
|
||||
import org.mozilla.gecko.sync.GlobalSession;
|
||||
import org.mozilla.gecko.sync.repositories.RecordFactory;
|
||||
import org.mozilla.gecko.sync.repositories.Repository;
|
||||
import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
|
||||
|
@ -14,6 +15,10 @@ import org.mozilla.gecko.sync.repositories.domain.Record;
|
|||
public class FennecTabsServerSyncStage extends ServerSyncStage {
|
||||
private static final String COLLECTION = "tabs";
|
||||
|
||||
public FennecTabsServerSyncStage(GlobalSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
public class FennecTabsRecordFactory extends RecordFactory {
|
||||
@Override
|
||||
public Record createRecord(Record record) {
|
||||
|
|
|
@ -1,39 +1,6 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Android Sync Client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Richard Newman <rnewman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
/* 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;
|
||||
|
||||
|
@ -46,15 +13,14 @@ import org.mozilla.gecko.sync.net.SyncStorageResponse;
|
|||
|
||||
import android.util.Log;
|
||||
|
||||
public class FetchInfoCollectionsStage implements GlobalSyncStage {
|
||||
public class FetchInfoCollectionsStage extends AbstractNonRepositorySyncStage {
|
||||
private static final String LOG_TAG = "FetchInfoCollStage";
|
||||
|
||||
public class StageInfoCollectionsDelegate implements InfoCollectionsDelegate {
|
||||
public FetchInfoCollectionsStage(GlobalSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
private GlobalSession session;
|
||||
public StageInfoCollectionsDelegate(GlobalSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
public class StageInfoCollectionsDelegate implements InfoCollectionsDelegate {
|
||||
|
||||
@Override
|
||||
public void handleSuccess(InfoCollections global) {
|
||||
|
@ -77,9 +43,9 @@ public class FetchInfoCollectionsStage implements GlobalSyncStage {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void execute(GlobalSession session) throws NoSuchStageException {
|
||||
public void execute() throws NoSuchStageException {
|
||||
try {
|
||||
session.fetchInfoCollections(new StageInfoCollectionsDelegate(session));
|
||||
session.fetchInfoCollections(new StageInfoCollectionsDelegate());
|
||||
} catch (URISyntaxException e) {
|
||||
session.abort(e, "Invalid URI.");
|
||||
}
|
||||
|
|
|
@ -12,7 +12,11 @@ import org.mozilla.gecko.sync.PersistedMetaGlobal;
|
|||
import org.mozilla.gecko.sync.delegates.MetaGlobalDelegate;
|
||||
import org.mozilla.gecko.sync.net.SyncStorageResponse;
|
||||
|
||||
public class FetchMetaGlobalStage implements GlobalSyncStage {
|
||||
public class FetchMetaGlobalStage extends AbstractNonRepositorySyncStage {
|
||||
public FetchMetaGlobalStage(GlobalSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
private static final String LOG_TAG = "FetchMetaGlobalStage";
|
||||
private static final String META_COLLECTION = "meta";
|
||||
|
||||
|
@ -51,7 +55,7 @@ public class FetchMetaGlobalStage implements GlobalSyncStage {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void execute(GlobalSession session) throws NoSuchStageException {
|
||||
public void execute() throws NoSuchStageException {
|
||||
InfoCollections infoCollections = session.config.infoCollections;
|
||||
if (infoCollections == null) {
|
||||
session.abort(null, "No info/collections set in FetchMetaGlobalStage.");
|
||||
|
|
|
@ -7,6 +7,7 @@ package org.mozilla.gecko.sync.stage;
|
|||
import java.net.URISyntaxException;
|
||||
|
||||
import org.mozilla.gecko.sync.CryptoRecord;
|
||||
import org.mozilla.gecko.sync.GlobalSession;
|
||||
import org.mozilla.gecko.sync.repositories.ConstrainedServer11Repository;
|
||||
import org.mozilla.gecko.sync.repositories.RecordFactory;
|
||||
import org.mozilla.gecko.sync.repositories.Repository;
|
||||
|
@ -21,9 +22,13 @@ public class FormHistoryServerSyncStage extends ServerSyncStage {
|
|||
private static final String FORM_HISTORY_SORT = "index";
|
||||
private static final long FORM_HISTORY_REQUEST_LIMIT = 5000; // Sanity limit.
|
||||
|
||||
public FormHistoryServerSyncStage(GlobalSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(org.mozilla.gecko.sync.GlobalSession session) throws NoSuchStageException {
|
||||
super.execute(session);
|
||||
public void execute() throws NoSuchStageException {
|
||||
super.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -4,7 +4,12 @@
|
|||
|
||||
package org.mozilla.gecko.sync.stage;
|
||||
|
||||
import org.mozilla.gecko.sync.GlobalSession;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public interface GlobalSyncStage {
|
||||
public static enum Stage {
|
||||
|
@ -18,19 +23,59 @@ public interface GlobalSyncStage {
|
|||
ensureSpecialRecords,
|
||||
updateEngineTimestamps,
|
||||
*/
|
||||
syncClientsEngine,
|
||||
syncClientsEngine("clients"),
|
||||
/*
|
||||
processFirstSyncPref,
|
||||
processClientCommands,
|
||||
updateEnabledEngines,
|
||||
*/
|
||||
syncTabs,
|
||||
syncPasswords,
|
||||
syncBookmarks,
|
||||
syncHistory,
|
||||
syncFormHistory,
|
||||
completed,
|
||||
syncTabs("tabs"),
|
||||
syncPasswords("passwords"),
|
||||
syncBookmarks("bookmarks"),
|
||||
syncHistory("history"),
|
||||
syncFormHistory("forms"),
|
||||
completed;
|
||||
|
||||
// Maintain a mapping from names ("bookmarks") to Stage enumerations (syncBookmarks).
|
||||
private static final Map<String, Stage> named = new HashMap<String, Stage>();
|
||||
static {
|
||||
for (Stage s : EnumSet.allOf(Stage.class)) {
|
||||
if (s.getRepositoryName() != null) {
|
||||
named.put(s.getRepositoryName(), s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Stage byName(final String name) {
|
||||
if (name == null) {
|
||||
return null;
|
||||
}
|
||||
return named.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an immutable collection of Stages.
|
||||
*/
|
||||
public static Collection<Stage> getNamedStages() {
|
||||
return Collections.unmodifiableCollection(named.values());
|
||||
}
|
||||
|
||||
// Each Stage tracks its repositoryName.
|
||||
private final String repositoryName;
|
||||
public String getRepositoryName() {
|
||||
return repositoryName;
|
||||
}
|
||||
|
||||
private Stage() {
|
||||
this.repositoryName = null;
|
||||
}
|
||||
|
||||
private Stage(final String name) {
|
||||
this.repositoryName = name;
|
||||
}
|
||||
}
|
||||
|
||||
public void execute(GlobalSession session) throws NoSuchStageException;
|
||||
public void execute() throws NoSuchStageException;
|
||||
public void resetLocal();
|
||||
public void wipeLocal() throws Exception;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package org.mozilla.gecko.sync.stage;
|
||||
|
||||
import org.mozilla.gecko.sync.CryptoRecord;
|
||||
import org.mozilla.gecko.sync.GlobalSession;
|
||||
import org.mozilla.gecko.sync.repositories.RecordFactory;
|
||||
import org.mozilla.gecko.sync.repositories.Repository;
|
||||
import org.mozilla.gecko.sync.repositories.android.PasswordsRepositorySession;
|
||||
|
@ -12,11 +13,15 @@ import org.mozilla.gecko.sync.repositories.domain.PasswordRecord;
|
|||
import org.mozilla.gecko.sync.repositories.domain.Record;
|
||||
|
||||
public class PasswordsServerSyncStage extends ServerSyncStage {
|
||||
public PasswordsServerSyncStage(GlobalSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCollection() {
|
||||
return "passwords";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getEngineName() {
|
||||
return "passwords";
|
||||
|
@ -41,5 +46,4 @@ public class PasswordsServerSyncStage extends ServerSyncStage {
|
|||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ package org.mozilla.gecko.sync.stage;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.mozilla.gecko.sync.GlobalSession;
|
||||
|
@ -17,12 +18,22 @@ import org.mozilla.gecko.sync.NonObjectJSONException;
|
|||
import org.mozilla.gecko.sync.SynchronizerConfiguration;
|
||||
import org.mozilla.gecko.sync.crypto.KeyBundle;
|
||||
import org.mozilla.gecko.sync.middleware.Crypto5MiddlewareRepository;
|
||||
import org.mozilla.gecko.sync.repositories.InactiveSessionException;
|
||||
import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
|
||||
import org.mozilla.gecko.sync.repositories.RecordFactory;
|
||||
import org.mozilla.gecko.sync.repositories.Repository;
|
||||
import org.mozilla.gecko.sync.repositories.RepositorySession;
|
||||
import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
|
||||
import org.mozilla.gecko.sync.repositories.Server11Repository;
|
||||
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
|
||||
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
|
||||
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
|
||||
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
|
||||
import org.mozilla.gecko.sync.synchronizer.Synchronizer;
|
||||
import org.mozilla.gecko.sync.synchronizer.SynchronizerDelegate;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* Fetch from a server collection into a local repository, encrypting
|
||||
* and decrypting along the way.
|
||||
|
@ -34,8 +45,16 @@ public abstract class ServerSyncStage implements
|
|||
GlobalSyncStage,
|
||||
SynchronizerDelegate {
|
||||
|
||||
protected GlobalSession session;
|
||||
protected String LOG_TAG = "ServerSyncStage";
|
||||
protected static final String LOG_TAG = "ServerSyncStage";
|
||||
|
||||
protected final GlobalSession session;
|
||||
|
||||
public ServerSyncStage(GlobalSession session) {
|
||||
if (session == null) {
|
||||
throw new IllegalArgumentException("session must not be null.");
|
||||
}
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override these in your subclasses.
|
||||
|
@ -44,8 +63,11 @@ public abstract class ServerSyncStage implements
|
|||
* @throws MetaGlobalException
|
||||
*/
|
||||
protected boolean isEnabled() throws MetaGlobalException {
|
||||
return session.engineIsEnabled(this.getEngineName());
|
||||
// TODO: pass EngineSettings here to check syncID and storage version.
|
||||
// Catch the subclasses of MetaGlobalException to trigger various resets and wipes.
|
||||
return session.engineIsEnabled(this.getEngineName(), null);
|
||||
}
|
||||
|
||||
protected abstract String getCollection();
|
||||
protected abstract String getEngineName();
|
||||
protected abstract Repository getLocalRepository();
|
||||
|
@ -77,6 +99,14 @@ public abstract class ServerSyncStage implements
|
|||
return this.getCollection() + ".";
|
||||
}
|
||||
|
||||
protected SynchronizerConfiguration getConfig() throws NonObjectJSONException, IOException, ParseException {
|
||||
return new SynchronizerConfiguration(session.config.getBranch(bundlePrefix()));
|
||||
}
|
||||
|
||||
protected void persistConfig(SynchronizerConfiguration synchronizerConfiguration) {
|
||||
synchronizerConfiguration.persist(session.config.getBranch(bundlePrefix()));
|
||||
}
|
||||
|
||||
public Synchronizer getConfiguredSynchronizer(GlobalSession session) throws NoCollectionKeysSetException, URISyntaxException, NonObjectJSONException, IOException, ParseException {
|
||||
Repository remote = wrappedServerRepo();
|
||||
|
||||
|
@ -84,7 +114,7 @@ public abstract class ServerSyncStage implements
|
|||
synchronizer.repositoryA = remote;
|
||||
synchronizer.repositoryB = this.getLocalRepository();
|
||||
|
||||
SynchronizerConfiguration config = new SynchronizerConfiguration(session.config.getBranch(bundlePrefix()));
|
||||
SynchronizerConfiguration config = this.getConfig();
|
||||
synchronizer.load(config);
|
||||
|
||||
// TODO: should wipe in either direction?
|
||||
|
@ -93,11 +123,178 @@ public abstract class ServerSyncStage implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public void execute(GlobalSession session) throws NoSuchStageException {
|
||||
public void resetLocal() {
|
||||
// Clear both timestamps.
|
||||
SynchronizerConfiguration config;
|
||||
try {
|
||||
config = this.getConfig();
|
||||
} catch (Exception e) {
|
||||
Logger.warn(LOG_TAG, "Unable to reset " + this + ": fetching config failed.", e);
|
||||
return;
|
||||
}
|
||||
|
||||
config.localBundle.setTimestamp(0L);
|
||||
config.remoteBundle.setTimestamp(0L);
|
||||
Logger.info(LOG_TAG, "Reset timestamps for " + this);
|
||||
persistConfig(config);
|
||||
}
|
||||
|
||||
// Not thread-safe. Use with caution.
|
||||
private class WipeWaiter {
|
||||
public boolean sessionSucceeded = true;
|
||||
public boolean wipeSucceeded = true;
|
||||
public Exception error;
|
||||
|
||||
public void notify(Exception e, boolean sessionSucceeded) {
|
||||
this.sessionSucceeded = sessionSucceeded;
|
||||
this.wipeSucceeded = false;
|
||||
this.error = e;
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously wipe this stage by instantiating a local repository session
|
||||
* and wiping that.
|
||||
*
|
||||
* Logs and rethrows an exception on failure.
|
||||
*/
|
||||
@Override
|
||||
public void wipeLocal() throws Exception {
|
||||
// Reset, then clear data.
|
||||
this.resetLocal();
|
||||
|
||||
final WipeWaiter monitor = new WipeWaiter();
|
||||
final Context context = session.getContext();
|
||||
final Repository r = this.getLocalRepository();
|
||||
|
||||
final Runnable doWipe = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
r.createSession(new RepositorySessionCreationDelegate() {
|
||||
|
||||
@Override
|
||||
public void onSessionCreated(final RepositorySession session) {
|
||||
try {
|
||||
session.begin(new RepositorySessionBeginDelegate() {
|
||||
|
||||
@Override
|
||||
public void onBeginSucceeded(final RepositorySession session) {
|
||||
session.wipe(new RepositorySessionWipeDelegate() {
|
||||
@Override
|
||||
public void onWipeSucceeded() {
|
||||
try {
|
||||
session.finish(new RepositorySessionFinishDelegate() {
|
||||
|
||||
@Override
|
||||
public void onFinishSucceeded(RepositorySession session,
|
||||
RepositorySessionBundle bundle) {
|
||||
// Hurrah.
|
||||
synchronized (monitor) {
|
||||
monitor.notify();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishFailed(Exception ex) {
|
||||
// Assume that no finish => no wipe.
|
||||
synchronized (monitor) {
|
||||
monitor.notify(ex, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepositorySessionFinishDelegate deferredFinishDelegate(ExecutorService executor) {
|
||||
return this;
|
||||
}
|
||||
});
|
||||
} catch (InactiveSessionException e) {
|
||||
// Cannot happen. Call for safety.
|
||||
synchronized (monitor) {
|
||||
monitor.notify(e, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWipeFailed(Exception ex) {
|
||||
session.abort();
|
||||
synchronized (monitor) {
|
||||
monitor.notify(ex, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepositorySessionWipeDelegate deferredWipeDelegate(ExecutorService executor) {
|
||||
return this;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBeginFailed(Exception ex) {
|
||||
session.abort();
|
||||
synchronized (monitor) {
|
||||
monitor.notify(ex, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepositorySessionBeginDelegate deferredBeginDelegate(ExecutorService executor) {
|
||||
return this;
|
||||
}
|
||||
});
|
||||
} catch (InvalidSessionTransitionException e) {
|
||||
session.abort();
|
||||
synchronized (monitor) {
|
||||
monitor.notify(e, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionCreateFailed(Exception ex) {
|
||||
synchronized (monitor) {
|
||||
monitor.notify(ex, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepositorySessionCreationDelegate deferredCreationDelegate() {
|
||||
return this;
|
||||
}
|
||||
}, context);
|
||||
}
|
||||
};
|
||||
|
||||
final Thread wiping = new Thread(doWipe);
|
||||
synchronized (monitor) {
|
||||
wiping.start();
|
||||
try {
|
||||
monitor.wait();
|
||||
} catch (InterruptedException e) {
|
||||
Logger.error(LOG_TAG, "Wipe interrupted.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!monitor.sessionSucceeded) {
|
||||
Logger.error(LOG_TAG, "Failed to create session for wipe.");
|
||||
throw monitor.error;
|
||||
}
|
||||
|
||||
if (!monitor.wipeSucceeded) {
|
||||
Logger.error(LOG_TAG, "Failed to wipe session.");
|
||||
throw monitor.error;
|
||||
}
|
||||
|
||||
Logger.info(LOG_TAG, "Wiping stage complete.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws NoSuchStageException {
|
||||
final String name = getEngineName();
|
||||
Logger.debug(LOG_TAG, "Starting execute for " + name);
|
||||
|
||||
this.session = session;
|
||||
try {
|
||||
if (!this.isEnabled()) {
|
||||
Logger.info(LOG_TAG, "Stage " + name + " disabled; skipping.");
|
||||
|
@ -141,7 +338,7 @@ public abstract class ServerSyncStage implements
|
|||
|
||||
SynchronizerConfiguration synchronizerConfiguration = synchronizer.save();
|
||||
if (synchronizerConfiguration != null) {
|
||||
synchronizerConfiguration.persist(session.config.getBranch(bundlePrefix()));
|
||||
persistConfig(synchronizerConfiguration);
|
||||
} else {
|
||||
Logger.warn(LOG_TAG, "Didn't get configuration from synchronizer after success");
|
||||
}
|
||||
|
|
|
@ -41,16 +41,44 @@ public class SyncClientsEngineStage implements GlobalSyncStage {
|
|||
public static final int CLIENTS_TTL_REFRESH = 604800000; // 7 days
|
||||
public static final int MAX_UPLOAD_FAILURE_COUNT = 5;
|
||||
|
||||
protected GlobalSession session;
|
||||
protected final GlobalSession session;
|
||||
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 commandsProcessedShouldUpload;
|
||||
protected final AtomicInteger uploadAttemptsCount = new AtomicInteger();
|
||||
|
||||
public SyncClientsEngineStage(GlobalSession session) {
|
||||
if (session == null) {
|
||||
throw new IllegalArgumentException("session must not be null.");
|
||||
}
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -93,11 +121,11 @@ public class SyncClientsEngineStage implements GlobalSyncStage {
|
|||
|
||||
final int clientsCount;
|
||||
try {
|
||||
clientsCount = db.clientsCount();
|
||||
clientsCount = getClientsCount();
|
||||
} finally {
|
||||
// Close the database to clear cached readableDatabase/writableDatabase
|
||||
// after we've completed our last transaction (db.store()).
|
||||
db.close();
|
||||
closeDataAccessor();
|
||||
}
|
||||
|
||||
Logger.debug(LOG_TAG, "Database contains " + clientsCount + " clients.");
|
||||
|
@ -119,7 +147,7 @@ public class SyncClientsEngineStage implements GlobalSyncStage {
|
|||
session.abort(new HTTPFailureException(response), "Client download failed.");
|
||||
} finally {
|
||||
// Close the database upon failure.
|
||||
db.close();
|
||||
closeDataAccessor();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,7 +159,7 @@ public class SyncClientsEngineStage implements GlobalSyncStage {
|
|||
session.abort(ex, "Failure fetching client record.");
|
||||
} finally {
|
||||
// Close the database upon error.
|
||||
db.close();
|
||||
closeDataAccessor();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,10 +278,7 @@ public class SyncClientsEngineStage implements GlobalSyncStage {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void execute(GlobalSession session) throws NoSuchStageException {
|
||||
this.session = session;
|
||||
init();
|
||||
|
||||
public void execute() throws NoSuchStageException {
|
||||
if (shouldDownload()) {
|
||||
downloadClientRecords(); // Will kick off upload, too…
|
||||
} else {
|
||||
|
@ -261,6 +286,24 @@ public class SyncClientsEngineStage implements GlobalSyncStage {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetLocal() {
|
||||
// Clear timestamps and local data.
|
||||
session.config.persistServerClientRecordTimestamp(0L);
|
||||
session.getClientsDelegate().setClientsCount(0);
|
||||
try {
|
||||
getClientsDatabaseAccessor().wipe();
|
||||
} finally {
|
||||
closeDataAccessor();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wipeLocal() throws Exception {
|
||||
// Nothing more to do.
|
||||
this.resetLocal();
|
||||
}
|
||||
|
||||
protected ClientRecord newLocalClientRecord(ClientsDataDelegate delegate) {
|
||||
final String ourGUID = delegate.getAccountGUID();
|
||||
final String ourName = delegate.getClientName();
|
||||
|
@ -270,10 +313,6 @@ public class SyncClientsEngineStage implements GlobalSyncStage {
|
|||
return r;
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
db = new ClientsDatabaseAccessor(session.getContext());
|
||||
}
|
||||
|
||||
// TODO: Bug 726055 - More considered handling of when to sync.
|
||||
protected boolean shouldDownload() {
|
||||
// Ask info/collections whether a download is needed.
|
||||
|
@ -309,7 +348,7 @@ public class SyncClientsEngineStage implements GlobalSyncStage {
|
|||
|
||||
// TODO: Bug 715792 - Process commands here.
|
||||
for (int i = 0; i < commands.size(); i++) {
|
||||
processor.processCommand(new ExtendedJSONObject((JSONObject)commands.get(i)));
|
||||
processor.processCommand(new ExtendedJSONObject((JSONObject) commands.get(i)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,6 +409,7 @@ public class SyncClientsEngineStage implements GlobalSyncStage {
|
|||
}
|
||||
|
||||
protected void wipeAndStore(ClientRecord record) {
|
||||
ClientsDatabaseAccessor db = getClientsDatabaseAccessor();
|
||||
if (shouldWipe) {
|
||||
db.wipe();
|
||||
shouldWipe = false;
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Загрузка…
Ссылка в новой задаче