merge fx-team to mozilla-central

This commit is contained in:
Carsten "Tomcat" Book 2013-12-16 10:14:26 +01:00
commit e2ffa4d059
30 changed files with 344 additions and 288 deletions

View File

@ -539,12 +539,14 @@ sync_java_files = [
'sync/crypto/PersistedCrypto5Keys.java',
'sync/CryptoRecord.java',
'sync/DelayedWorkTracker.java',
'sync/delegates/BaseGlobalSessionCallback.java',
'sync/delegates/ClientsDataDelegate.java',
'sync/delegates/FreshStartDelegate.java',
'sync/delegates/GlobalSessionCallback.java',
'sync/delegates/JSONRecordFetchDelegate.java',
'sync/delegates/KeyUploadDelegate.java',
'sync/delegates/MetaGlobalDelegate.java',
'sync/delegates/NodeAssignmentCallback.java',
'sync/delegates/WipeServerDelegate.java',
'sync/EngineSettings.java',
'sync/ExtendedJSONObject.java',
@ -662,9 +664,11 @@ sync_java_files = [
'sync/repositories/domain/HistoryRecord.java',
'sync/repositories/domain/HistoryRecordFactory.java',
'sync/repositories/domain/PasswordRecord.java',
'sync/repositories/domain/PasswordRecordFactory.java',
'sync/repositories/domain/Record.java',
'sync/repositories/domain/RecordParseException.java',
'sync/repositories/domain/TabsRecord.java',
'sync/repositories/domain/TabsRecordFactory.java',
'sync/repositories/domain/VersionConstants.java',
'sync/repositories/FetchFailedException.java',
'sync/repositories/HashSetStoreTracker.java',
@ -715,6 +719,8 @@ sync_java_files = [
'sync/setup/InvalidSyncKeyException.java',
'sync/setup/SyncAccounts.java',
'sync/setup/SyncAuthenticatorService.java',
'sync/SharedPreferencesClientsDataDelegate.java',
'sync/SharedPreferencesNodeAssignmentCallback.java',
'sync/stage/AbstractNonRepositorySyncStage.java',
'sync/stage/AbstractSessionManagingSyncStage.java',
'sync/stage/AndroidBrowserBookmarksServerSyncStage.java',

View File

@ -22,12 +22,13 @@ import org.json.simple.parser.ParseException;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.sync.crypto.CryptoException;
import org.mozilla.gecko.sync.crypto.KeyBundle;
import org.mozilla.gecko.sync.delegates.BaseGlobalSessionCallback;
import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
import org.mozilla.gecko.sync.delegates.FreshStartDelegate;
import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
import org.mozilla.gecko.sync.delegates.JSONRecordFetchDelegate;
import org.mozilla.gecko.sync.delegates.KeyUploadDelegate;
import org.mozilla.gecko.sync.delegates.MetaGlobalDelegate;
import org.mozilla.gecko.sync.delegates.NodeAssignmentCallback;
import org.mozilla.gecko.sync.delegates.WipeServerDelegate;
import org.mozilla.gecko.sync.net.AuthHeaderProvider;
import org.mozilla.gecko.sync.net.BaseResource;
@ -70,9 +71,10 @@ public class GlobalSession implements PrefsSource, HttpResponseObserver {
protected Map<Stage, GlobalSyncStage> stages;
public Stage currentState = Stage.idle;
public final GlobalSessionCallback callback;
private Context context;
private ClientsDataDelegate clientsDelegate;
public final BaseGlobalSessionCallback callback;
protected final Context context;
protected final ClientsDataDelegate clientsDelegate;
protected final NodeAssignmentCallback nodeAssignmentCallback;
/**
* Map from engine name to new settings for an updated meta/global record.
@ -98,15 +100,15 @@ public class GlobalSession implements PrefsSource, HttpResponseObserver {
return config.wboURI(collection, id);
}
public GlobalSession(String serverURL,
String username,
public GlobalSession(String username,
AuthHeaderProvider authHeaderProvider,
String prefsPath,
KeyBundle syncKeyBundle,
GlobalSessionCallback callback,
BaseGlobalSessionCallback callback,
Context context,
Bundle extras,
ClientsDataDelegate clientsDelegate)
ClientsDataDelegate clientsDelegate,
NodeAssignmentCallback nodeAssignmentCallback)
throws SyncConfigurationException, IllegalArgumentException, IOException, ParseException, NonObjectJSONException {
if (username == null) {
throw new IllegalArgumentException("username must not be null.");
@ -116,12 +118,6 @@ public class GlobalSession implements PrefsSource, HttpResponseObserver {
}
Logger.debug(LOG_TAG, "GlobalSession initialized with bundle " + extras);
URI serverURI;
try {
serverURI = (serverURL == null) ? null : new URI(serverURL);
} catch (URISyntaxException e) {
throw new SyncConfigurationException();
}
if (syncKeyBundle == null ||
syncKeyBundle.getEncryptionKey() == null ||
@ -132,10 +128,9 @@ public class GlobalSession implements PrefsSource, HttpResponseObserver {
this.callback = callback;
this.context = context;
this.clientsDelegate = clientsDelegate;
this.nodeAssignmentCallback = nodeAssignmentCallback;
config = new SyncConfiguration(username, authHeaderProvider, prefsPath, this);
config.serverURL = serverURI;
config.syncKeyBundle = syncKeyBundle;
registerCommands();
@ -199,7 +194,7 @@ public class GlobalSession implements PrefsSource, HttpResponseObserver {
HashMap<Stage, GlobalSyncStage> stages = new HashMap<Stage, GlobalSyncStage>();
stages.put(Stage.checkPreconditions, new CheckPreconditionsStage());
stages.put(Stage.ensureClusterURL, new EnsureClusterURLStage());
stages.put(Stage.ensureClusterURL, new EnsureClusterURLStage(nodeAssignmentCallback));
stages.put(Stage.fetchInfoCollections, new FetchInfoCollectionsStage());
stages.put(Stage.fetchMetaGlobal, new FetchMetaGlobalStage());
stages.put(Stage.ensureKeysStage, new EnsureCrypto5KeysStage());

View File

@ -27,6 +27,9 @@ public class JSONRecordFetcher {
protected JSONRecordFetchDelegate delegate;
public JSONRecordFetcher(final String uri, final AuthHeaderProvider authHeaderProvider) {
if (uri == null) {
throw new IllegalArgumentException("uri must not be null");
}
this.uri = uri;
this.authHeaderProvider = authHeaderProvider;
}

View File

@ -0,0 +1,57 @@
/* 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;
import org.mozilla.gecko.background.common.GlobalConstants;
import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
import android.content.SharedPreferences;
/**
* A <code>ClientsDataDelegate</code> implementation that persists to a
* <code>SharedPreferences</code> instance.
*/
public class SharedPreferencesClientsDataDelegate implements ClientsDataDelegate {
protected final SharedPreferences sharedPreferences;
public SharedPreferencesClientsDataDelegate(SharedPreferences sharedPreferences) {
this.sharedPreferences = sharedPreferences;
}
@Override
public synchronized String getAccountGUID() {
String accountGUID = sharedPreferences.getString(SyncConfiguration.PREF_ACCOUNT_GUID, null);
if (accountGUID == null) {
accountGUID = Utils.generateGuid();
sharedPreferences.edit().putString(SyncConfiguration.PREF_ACCOUNT_GUID, accountGUID).commit();
}
return accountGUID;
}
@Override
public synchronized String getClientName() {
String clientName = sharedPreferences.getString(SyncConfiguration.PREF_CLIENT_NAME, null);
if (clientName == null) {
clientName = GlobalConstants.MOZ_APP_DISPLAYNAME + " on " + android.os.Build.MODEL;
sharedPreferences.edit().putString(SyncConfiguration.PREF_CLIENT_NAME, clientName).commit();
}
return clientName;
}
@Override
public synchronized void setClientsCount(int clientsCount) {
sharedPreferences.edit().putLong(SyncConfiguration.PREF_NUM_CLIENTS, (long) clientsCount).commit();
}
@Override
public boolean isLocalGUID(String guid) {
return getAccountGUID().equals(guid);
}
@Override
public synchronized int getClientsCount() {
return (int) sharedPreferences.getLong(SyncConfiguration.PREF_NUM_CLIENTS, 0);
}
}

View File

@ -0,0 +1,63 @@
/* 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;
import java.net.URI;
import java.net.URISyntaxException;
import org.mozilla.gecko.sync.delegates.NodeAssignmentCallback;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
public class SharedPreferencesNodeAssignmentCallback implements NodeAssignmentCallback {
protected final SharedPreferences sharedPreferences;
protected final String nodeWeaveURL;
public SharedPreferencesNodeAssignmentCallback(SharedPreferences sharedPreferences, String nodeWeaveURL)
throws SyncConfigurationException {
this.sharedPreferences = sharedPreferences;
if (nodeWeaveURL == null) {
throw new IllegalArgumentException("nodeWeaveURL must not be null");
}
try {
new URI(nodeWeaveURL);
} catch (URISyntaxException e) {
throw new SyncConfigurationException();
}
this.nodeWeaveURL = nodeWeaveURL;
}
public synchronized boolean getClusterURLIsStale() {
return sharedPreferences.getBoolean(SyncConfiguration.PREF_CLUSTER_URL_IS_STALE, false);
}
public synchronized void setClusterURLIsStale(boolean clusterURLIsStale) {
Editor edit = sharedPreferences.edit();
edit.putBoolean(SyncConfiguration.PREF_CLUSTER_URL_IS_STALE, clusterURLIsStale);
edit.commit();
}
@Override
public boolean wantNodeAssignment() {
return getClusterURLIsStale();
}
@Override
public void informNodeAuthenticationFailed(GlobalSession session, URI failedClusterURL) {
// TODO: communicate to the user interface that we need a new user password!
// TODO: only freshen the cluster URL (better yet, forget the cluster URL) after the user has provided new credentials.
setClusterURLIsStale(false);
}
@Override
public void informNodeAssigned(GlobalSession session, URI oldClusterURL, URI newClusterURL) {
setClusterURLIsStale(false);
}
@Override
public String nodeWeaveURL() {
return this.nodeWeaveURL;
}
}

View File

@ -175,12 +175,9 @@ public class SyncConfiguration {
}
}
public static final String DEFAULT_USER_API = "https://auth.services.mozilla.com/user/1.0/";
private static final String LOG_TAG = "SyncConfiguration";
// These must be set in GlobalSession's constructor.
public URI serverURL;
public URI clusterURL;
public KeyBundle syncKeyBundle;
@ -453,21 +450,6 @@ public class SyncConfiguration {
collectionKeys = k;
}
public String nodeWeaveURL() {
return this.nodeWeaveURL((this.serverURL == null) ? null : this.serverURL.toASCIIString());
}
public String nodeWeaveURL(String serverURL) {
String userPart = username + "/node/weave";
if (serverURL == null) {
return DEFAULT_USER_API + userPart;
}
if (!serverURL.endsWith("/")) {
serverURL = serverURL + "/";
}
return serverURL + "user/1.0/" + userPart;
}
protected String infoBaseURL() {
return clusterURL + GlobalSession.API_VERSION + "/" + username + "/info/";
}

View File

@ -53,4 +53,6 @@ public class SyncConstants {
* Account type.
*/
public static final String PER_ACCOUNT_TYPE_PERMISSION = "@MOZ_ANDROID_SHARED_ACCOUNT_TYPE@.permission.PER_ACCOUNT_TYPE";
public static final String DEFAULT_AUTH_SERVER = "https://auth.services.mozilla.com/";
}

View File

@ -530,4 +530,15 @@ public class Utils {
public static String obfuscateEmail(final String in) {
return in.replaceAll("[^@\\.]", "X");
}
public static String nodeWeaveURL(String serverURL, String username) {
String userPart = username + "/node/weave";
if (serverURL == null) {
return SyncConstants.DEFAULT_AUTH_SERVER + "user/1.0/" + userPart;
}
if (!serverURL.endsWith("/")) {
serverURL = serverURL + "/";
}
return serverURL + "user/1.0/" + userPart;
}
}

View File

@ -0,0 +1,36 @@
/* 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.delegates;
import java.net.URI;
import org.mozilla.gecko.sync.GlobalSession;
import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
public interface BaseGlobalSessionCallback {
/**
* Request that no further syncs occur within the next `backoff` milliseconds.
* @param backoff a duration in milliseconds.
*/
void requestBackoff(long backoff);
/**
* Called on a 401 HTTP response.
*/
void informUnauthorizedResponse(GlobalSession globalSession, URI oldClusterURL);
/**
* Called when an HTTP failure indicates that a software upgrade is required.
*/
void informUpgradeRequiredResponse(GlobalSession session);
void handleAborted(GlobalSession globalSession, String reason);
void handleError(GlobalSession globalSession, Exception ex);
void handleSuccess(GlobalSession globalSession);
void handleStageCompleted(Stage currentState, GlobalSession globalSession);
boolean shouldBackOff();
}

View File

@ -4,63 +4,5 @@
package org.mozilla.gecko.sync.delegates;
import java.net.URI;
import org.mozilla.gecko.sync.GlobalSession;
import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
public interface GlobalSessionCallback {
/**
* Request that no further syncs occur within the next `backoff` milliseconds.
* @param backoff a duration in milliseconds.
*/
void requestBackoff(long backoff);
/**
* If true, request node assignment from the server, i.e., fetch node/weave cluster URL.
*/
boolean wantNodeAssignment();
/**
* Called on a 401 HTTP response.
*/
void informUnauthorizedResponse(GlobalSession globalSession, URI oldClusterURL);
/**
* Called when a new node is assigned. If there already was an old node, the
* new node is different from the old node assignment, indicating node
* reassignment. If there wasn't an old node, we've been freshly assigned.
*
* @param globalSession
* @param oldClusterURL
* The old node/weave cluster URL (possibly null).
* @param newClusterURL
* The new node/weave cluster URL (not null).
*/
void informNodeAssigned(GlobalSession globalSession, URI oldClusterURL, URI newClusterURL);
/**
* Called when wantNodeAssignment() is true, and the new node assignment is
* the same as the old node assignment, indicating a user authentication
* error.
*
* @param globalSession
* @param failedClusterURL
* The new node/weave cluster URL.
*/
void informNodeAuthenticationFailed(GlobalSession globalSession, URI failedClusterURL);
/**
* Called when an HTTP failure indicates that a software upgrade is required.
*/
void informUpgradeRequiredResponse(GlobalSession session);
void handleAborted(GlobalSession globalSession, String reason);
void handleError(GlobalSession globalSession, Exception ex);
void handleSuccess(GlobalSession globalSession);
void handleStageCompleted(Stage currentState, GlobalSession globalSession);
boolean shouldBackOff();
public interface GlobalSessionCallback extends BaseGlobalSessionCallback, NodeAssignmentCallback {
}

View File

@ -0,0 +1,42 @@
/* 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.delegates;
import java.net.URI;
import org.mozilla.gecko.sync.GlobalSession;
public interface NodeAssignmentCallback {
/**
* If true, request node assignment from the server, i.e., fetch node/weave cluster URL.
*/
public boolean wantNodeAssignment();
/**
* Called when a new node is assigned. If there already was an old node, the
* new node is different from the old node assignment, indicating node
* reassignment. If there wasn't an old node, we've been freshly assigned.
*
* @param globalSession
* @param oldClusterURL
* The old node/weave cluster URL (possibly null).
* @param newClusterURL
* The new node/weave cluster URL (not null).
*/
public void informNodeAssigned(GlobalSession globalSession, URI oldClusterURL, URI newClusterURL);
/**
* Called when wantNodeAssignment() is true, and the new node assignment is
* the same as the old node assignment, indicating a user authentication
* error.
*
* @param globalSession
* @param failedClusterURL
* The new node/weave cluster URL.
*/
public void informNodeAuthenticationFailed(GlobalSession globalSession, URI failedClusterURL);
public String nodeWeaveURL();
}

View File

@ -91,7 +91,10 @@ public class BaseResource implements Resource {
}
public BaseResource(URI uri, boolean rewrite) {
if (rewrite && uri.getHost().equals("localhost")) {
if (uri == null) {
throw new IllegalArgumentException("uri must not be null");
}
if (rewrite && "localhost".equals(uri.getHost())) {
// Rewrite localhost URIs to refer to the special Android emulator loopback passthrough interface.
Logger.debug(LOG_TAG, "Rewriting " + uri + " to point to " + ANDROID_LOOPBACK_IP + ".");
try {

View File

@ -0,0 +1,19 @@
/* 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.repositories.domain;
import org.mozilla.gecko.sync.CryptoRecord;
import org.mozilla.gecko.sync.repositories.RecordFactory;
import org.mozilla.gecko.sync.repositories.domain.PasswordRecord;
import org.mozilla.gecko.sync.repositories.domain.Record;
public class PasswordRecordFactory extends RecordFactory {
@Override
public Record createRecord(Record record) {
PasswordRecord r = new PasswordRecord();
r.initFromEnvelope((CryptoRecord) record);
return r;
}
}

View File

@ -0,0 +1,17 @@
/* 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.repositories.domain;
import org.mozilla.gecko.sync.CryptoRecord;
import org.mozilla.gecko.sync.repositories.RecordFactory;
public class TabsRecordFactory extends RecordFactory {
@Override
public Record createRecord(Record record) {
TabsRecord r = new TabsRecord();
r.initFromEnvelope((CryptoRecord) record);
return r;
}
}

View File

@ -51,10 +51,6 @@ public class Constants {
Intent.FLAG_ACTIVITY_NO_ANIMATION;
// Constants for Account Authentication.
public static final String AUTH_NODE_DEFAULT = "https://auth.services.mozilla.com/";
public static final String AUTH_NODE_PATHNAME = "user/";
public static final String AUTH_NODE_VERSION = "1.0/";
public static final String AUTH_NODE_SUFFIX = "node/weave";
public static final String AUTH_SERVER_VERSION = "1.1/";
public static final String AUTH_SERVER_SUFFIX = "info/collections/";

View File

@ -44,8 +44,6 @@ public class SyncAccounts {
private static final String MOTO_BLUR_SETTINGS_ACTIVITY = "com.motorola.blur.settings.AccountsAndServicesPreferenceActivity";
private static final String MOTO_BLUR_PACKAGE = "com.motorola.blur.setup";
public final static String DEFAULT_SERVER = "https://auth.services.mozilla.com/";
/**
* Return Sync accounts.
*
@ -249,10 +247,10 @@ public class SyncAccounts {
final String syncKey = syncAccount.syncKey;
final String password = syncAccount.password;
final String serverURL = (syncAccount.serverURL == null) ?
DEFAULT_SERVER : syncAccount.serverURL;
SyncConstants.DEFAULT_AUTH_SERVER : syncAccount.serverURL;
Logger.debug(LOG_TAG, "Using account manager " + accountManager);
if (!RepoUtils.stringsEqual(syncAccount.serverURL, DEFAULT_SERVER)) {
if (!RepoUtils.stringsEqual(syncAccount.serverURL, SyncConstants.DEFAULT_AUTH_SERVER)) {
Logger.info(LOG_TAG, "Setting explicit server URL: " + serverURL);
}

View File

@ -45,7 +45,7 @@ public class AccountActivity extends AccountAuthenticatorActivity {
private String username;
private String password;
private String key;
private String server = Constants.AUTH_NODE_DEFAULT;
private String server = SyncConstants.DEFAULT_AUTH_SERVER;
// UI elements.
private EditText serverInput;
@ -162,7 +162,7 @@ public class AccountActivity extends AccountAuthenticatorActivity {
username = usernameInput.getText().toString().toLowerCase(Locale.US);
password = passwordInput.getText().toString();
key = synckeyInput.getText().toString();
server = Constants.AUTH_NODE_DEFAULT;
server = SyncConstants.DEFAULT_AUTH_SERVER;
if (serverCheckbox.isChecked()) {
String userServer = serverInput.getText().toString();

View File

@ -15,7 +15,6 @@ import java.security.GeneralSecurityException;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.sync.net.BaseResource;
import org.mozilla.gecko.sync.net.BaseResourceDelegate;
import org.mozilla.gecko.sync.setup.Constants;
import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.client.ClientProtocolException;
@ -53,7 +52,8 @@ public class EnsureUserExistenceStage implements AuthenticatorStage {
};
String userRequestUrl = aa.nodeServer + Constants.AUTH_NODE_PATHNAME + Constants.AUTH_NODE_VERSION + aa.username;
// This is not the same as Utils.nodeWeaveURL: it's missing the trailing node/weave.
String userRequestUrl = aa.nodeServer + "user/1.0/" + aa.username;
final BaseResource httpResource = new BaseResource(userRequestUrl);
httpResource.delegate = new BaseResourceDelegate(httpResource) {

View File

@ -12,9 +12,9 @@ import java.net.URISyntaxException;
import java.security.GeneralSecurityException;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.sync.Utils;
import org.mozilla.gecko.sync.net.BaseResource;
import org.mozilla.gecko.sync.net.BaseResourceDelegate;
import org.mozilla.gecko.sync.setup.Constants;
import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.client.ClientProtocolException;
@ -61,7 +61,7 @@ public class FetchUserNodeStage implements AuthenticatorStage {
aa.abort(AuthenticationResult.FAILURE_OTHER, e);
}
};
String nodeRequestUrl = aa.nodeServer + Constants.AUTH_NODE_PATHNAME + Constants.AUTH_NODE_VERSION + aa.username + "/" + Constants.AUTH_NODE_SUFFIX;
String nodeRequestUrl = Utils.nodeWeaveURL(aa.nodeServer, aa.username);
// Might contain a plaintext username in the case of old Sync accounts.
Logger.pii(LOG_TAG, "NodeUrl: " + nodeRequestUrl);
final BaseResource httpResource = makeFetchNodeRequest(callbackDelegate, nodeRequestUrl);

View File

@ -16,6 +16,7 @@ import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.sync.NodeAuthenticationException;
import org.mozilla.gecko.sync.NullClusterURLException;
import org.mozilla.gecko.sync.ThreadPool;
import org.mozilla.gecko.sync.delegates.NodeAssignmentCallback;
import org.mozilla.gecko.sync.net.BaseResource;
import org.mozilla.gecko.sync.net.BaseResourceDelegate;
@ -24,6 +25,8 @@ import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.client.ClientProtocolException;
public class EnsureClusterURLStage extends AbstractNonRepositorySyncStage {
private static final String LOG_TAG = EnsureClusterURLStage.class.getSimpleName();
public interface ClusterURLFetchDelegate {
/**
* 200 - Success.
@ -50,7 +53,12 @@ public class EnsureClusterURLStage extends AbstractNonRepositorySyncStage {
public void handleError(Exception e);
}
protected static final String LOG_TAG = "EnsureClusterURLStage";
protected final NodeAssignmentCallback callback;
public EnsureClusterURLStage(NodeAssignmentCallback callback) {
super();
this.callback = callback;
}
// TODO: if cluster URL has changed since last time, we need to ensure that we do
// a fresh start. This takes place at the GlobalSession level. Verify!
@ -173,7 +181,7 @@ public class EnsureClusterURLStage extends AbstractNonRepositorySyncStage {
public void execute() throws NoSuchStageException {
final URI oldClusterURL = session.config.getClusterURL();
final boolean wantNodeAssignment = session.callback.wantNodeAssignment();
final boolean wantNodeAssignment = callback.wantNodeAssignment();
if (!wantNodeAssignment && oldClusterURL != null) {
Logger.info(LOG_TAG, "Cluster URL is already set and not stale. Continuing with sync.");
@ -190,12 +198,12 @@ public class EnsureClusterURLStage extends AbstractNonRepositorySyncStage {
if (oldClusterURL != null && oldClusterURL.equals(url)) {
// Our cluster URL is marked as stale and the fresh cluster URL is the same -- this is the user's problem.
session.callback.informNodeAuthenticationFailed(session, url);
callback.informNodeAuthenticationFailed(session, url);
session.abort(new NodeAuthenticationException(), "User password has changed.");
return;
}
session.callback.informNodeAssigned(session, oldClusterURL, url); // No matter what, we're getting a new node/weave clusterURL.
callback.informNodeAssigned(session, oldClusterURL, url); // No matter what, we're getting a new node/weave clusterURL.
session.config.setClusterURL(url);
ThreadPool.run(new Runnable() {
@ -216,7 +224,12 @@ public class EnsureClusterURLStage extends AbstractNonRepositorySyncStage {
int statusCode = response.getStatusLine().getStatusCode();
Logger.warn(LOG_TAG, "Got HTTP failure fetching node assignment: " + statusCode);
if (statusCode == 404) {
URI serverURL = session.config.serverURL;
URI serverURL = null;
try {
serverURL = new URI(callback.nodeWeaveURL());
} catch (URISyntaxException e) {
// Fall through to abort.
}
if (serverURL != null) {
Logger.info(LOG_TAG, "Using serverURL <" + serverURL.toASCIIString() + "> as clusterURL.");
session.config.setClusterURL(serverURL);
@ -224,7 +237,7 @@ public class EnsureClusterURLStage extends AbstractNonRepositorySyncStage {
return;
}
Logger.warn(LOG_TAG, "No serverURL set to use as fallback cluster URL. Aborting sync.");
// Fallthrough to abort.
// Fall through to abort.
} else {
session.interpretHTTPFailure(response);
}
@ -241,7 +254,7 @@ public class EnsureClusterURLStage extends AbstractNonRepositorySyncStage {
@Override
public void run() {
try {
fetchClusterURL(session.config.nodeWeaveURL(), delegate);
fetchClusterURL(callback.nodeWeaveURL(), delegate);
} catch (URISyntaxException e) {
session.abort(e, "Invalid URL for node/weave.");
}

View File

@ -4,27 +4,16 @@
package org.mozilla.gecko.sync.stage;
import org.mozilla.gecko.sync.CryptoRecord;
import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
import org.mozilla.gecko.sync.repositories.RecordFactory;
import org.mozilla.gecko.sync.repositories.Repository;
import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
import org.mozilla.gecko.sync.repositories.domain.Record;
import org.mozilla.gecko.sync.repositories.domain.TabsRecord;
import org.mozilla.gecko.sync.repositories.domain.TabsRecordFactory;
import org.mozilla.gecko.sync.repositories.domain.VersionConstants;
public class FennecTabsServerSyncStage extends ServerSyncStage {
private static final String COLLECTION = "tabs";
public class FennecTabsRecordFactory extends RecordFactory {
@Override
public Record createRecord(Record record) {
TabsRecord r = new TabsRecord();
r.initFromEnvelope((CryptoRecord) record);
return r;
}
}
@Override
protected String getCollection() {
return COLLECTION;
@ -48,6 +37,6 @@ public class FennecTabsServerSyncStage extends ServerSyncStage {
@Override
protected RecordFactory getRecordFactory() {
return new FennecTabsRecordFactory();
return new TabsRecordFactory();
}
}

View File

@ -4,12 +4,10 @@
package org.mozilla.gecko.sync.stage;
import org.mozilla.gecko.sync.CryptoRecord;
import org.mozilla.gecko.sync.repositories.RecordFactory;
import org.mozilla.gecko.sync.repositories.Repository;
import org.mozilla.gecko.sync.repositories.android.PasswordsRepositorySession;
import org.mozilla.gecko.sync.repositories.domain.PasswordRecord;
import org.mozilla.gecko.sync.repositories.domain.Record;
import org.mozilla.gecko.sync.repositories.domain.PasswordRecordFactory;
import org.mozilla.gecko.sync.repositories.domain.VersionConstants;
public class PasswordsServerSyncStage extends ServerSyncStage {
@ -37,14 +35,4 @@ public class PasswordsServerSyncStage extends ServerSyncStage {
protected RecordFactory getRecordFactory() {
return new PasswordRecordFactory();
}
public class PasswordRecordFactory extends RecordFactory {
@Override
public Record createRecord(Record record) {
PasswordRecord r = new PasswordRecord();
r.initFromEnvelope((CryptoRecord) record);
return r;
}
}
}

View File

@ -17,6 +17,8 @@ import org.mozilla.gecko.sync.AlreadySyncingException;
import org.mozilla.gecko.sync.CredentialException;
import org.mozilla.gecko.sync.GlobalSession;
import org.mozilla.gecko.sync.NonObjectJSONException;
import org.mozilla.gecko.sync.SharedPreferencesClientsDataDelegate;
import org.mozilla.gecko.sync.SharedPreferencesNodeAssignmentCallback;
import org.mozilla.gecko.sync.SyncConfiguration;
import org.mozilla.gecko.sync.SyncConfigurationException;
import org.mozilla.gecko.sync.SyncConstants;
@ -26,8 +28,8 @@ import org.mozilla.gecko.sync.Utils;
import org.mozilla.gecko.sync.config.AccountPickler;
import org.mozilla.gecko.sync.crypto.CryptoException;
import org.mozilla.gecko.sync.crypto.KeyBundle;
import org.mozilla.gecko.sync.delegates.BaseGlobalSessionCallback;
import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
import org.mozilla.gecko.sync.net.AuthHeaderProvider;
import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
import org.mozilla.gecko.sync.net.ConnectionMonitorThread;
@ -51,7 +53,7 @@ import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteException;
import android.os.Bundle;
public class SyncAdapter extends AbstractThreadedSyncAdapter implements GlobalSessionCallback, ClientsDataDelegate {
public class SyncAdapter extends AbstractThreadedSyncAdapter implements BaseGlobalSessionCallback {
private static final String LOG_TAG = "SyncAdapter";
private static final int BACKOFF_PAD_SECONDS = 5;
@ -195,6 +197,8 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter implements GlobalSe
protected Account localAccount;
protected boolean thisSyncIsForced = false;
protected SharedPreferences accountSharedPreferences;
protected SharedPreferencesClientsDataDelegate clientsDataDelegate;
protected SharedPreferencesNodeAssignmentCallback nodeAssignmentDelegate;
/**
* Return the number of milliseconds until we're allowed to sync again,
@ -220,7 +224,7 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter implements GlobalSe
return false;
}
if (wantNodeAssignment()) {
if (nodeAssignmentDelegate.wantNodeAssignment()) {
/*
* We recently had a 401 and we aborted the last sync. We should kick off
* another sync to fetch a new node/weave cluster URL, since ours is
@ -359,11 +363,14 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter implements GlobalSe
final String profile = Constants.DEFAULT_PROFILE;
final long version = SyncConfiguration.CURRENT_PREFS_VERSION;
self.accountSharedPreferences = Utils.getSharedPreferences(mContext, product, username, serverURL, profile, version);
self.clientsDataDelegate = new SharedPreferencesClientsDataDelegate(accountSharedPreferences);
final String nodeWeaveURL = Utils.nodeWeaveURL(serverURL, username);
self.nodeAssignmentDelegate = new SharedPreferencesNodeAssignmentCallback(accountSharedPreferences, nodeWeaveURL);
Logger.info(LOG_TAG,
"Client is named '" + getClientName() + "'" +
", has client guid " + getAccountGUID() +
", and has " + getClientsCount() + " clients.");
"Client is named '" + clientsDataDelegate.getClientName() + "'" +
", has client guid " + clientsDataDelegate.getAccountGUID() +
", and has " + clientsDataDelegate.getClientsCount() + " clients.");
thisSyncIsForced = (extras != null) && (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false));
long delay = delayMilliseconds();
@ -405,7 +412,7 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter implements GlobalSe
syncMonitor.wait();
if (setNextSync.get()) {
long interval = getSyncInterval();
long interval = getSyncInterval(clientsDataDelegate);
long next = System.currentTimeMillis() + interval;
if (thisSyncIsForced) {
@ -426,13 +433,13 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter implements GlobalSe
}
}
public int getSyncInterval() {
public int getSyncInterval(ClientsDataDelegate clientsDataDelegate) {
// Must have been a problem that means we can't access the Account.
if (this.localAccount == null) {
return SINGLE_DEVICE_INTERVAL_MILLISECONDS;
}
int clientsCount = this.getClientsCount();
int clientsCount = clientsDataDelegate.getClientsCount();
if (clientsCount <= 1) {
return SINGLE_DEVICE_INTERVAL_MILLISECONDS;
}
@ -481,8 +488,8 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter implements GlobalSe
password,
serverURL,
null, // We'll re-fetch cluster URL; not great, but not harmful.
getClientName(),
getAccountGUID());
clientsDataDelegate.getClientName(),
clientsDataDelegate.getAccountGUID());
// Bug 772971: pickle Sync account parameters on background thread to
// avoid strict mode warnings.
@ -502,11 +509,10 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter implements GlobalSe
// Do nothing.
}
// TODO: default serverURL.
final KeyBundle keyBundle = new KeyBundle(username, syncKey);
final AuthHeaderProvider authHeaderProvider = new BasicAuthHeaderProvider(username, password);
GlobalSession globalSession = new GlobalSession(serverURL, username, authHeaderProvider, prefsPath,
keyBundle, this, this.mContext, extras, this);
GlobalSession globalSession = new GlobalSession(username, authHeaderProvider, prefsPath,
keyBundle, this, this.mContext, extras, clientsDataDelegate, nodeAssignmentDelegate);
globalSession.start();
}
@ -545,72 +551,9 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter implements GlobalSe
Logger.trace(LOG_TAG, "Stage completed: " + currentState);
}
@Override
public synchronized String getAccountGUID() {
String accountGUID = accountSharedPreferences.getString(SyncConfiguration.PREF_ACCOUNT_GUID, null);
if (accountGUID == null) {
Logger.debug(LOG_TAG, "Account GUID was null. Creating a new one.");
accountGUID = Utils.generateGuid();
accountSharedPreferences.edit().putString(SyncConfiguration.PREF_ACCOUNT_GUID, accountGUID).commit();
}
return accountGUID;
}
@Override
public synchronized String getClientName() {
String clientName = accountSharedPreferences.getString(SyncConfiguration.PREF_CLIENT_NAME, null);
if (clientName == null) {
clientName = GlobalConstants.MOZ_APP_DISPLAYNAME + " on " + android.os.Build.MODEL;
accountSharedPreferences.edit().putString(SyncConfiguration.PREF_CLIENT_NAME, clientName).commit();
}
return clientName;
}
@Override
public synchronized void setClientsCount(int clientsCount) {
accountSharedPreferences.edit().putLong(SyncConfiguration.PREF_NUM_CLIENTS, (long) clientsCount).commit();
}
@Override
public boolean isLocalGUID(String guid) {
return getAccountGUID().equals(guid);
}
@Override
public synchronized int getClientsCount() {
return (int) accountSharedPreferences.getLong(SyncConfiguration.PREF_NUM_CLIENTS, 0);
}
public synchronized boolean getClusterURLIsStale() {
return accountSharedPreferences.getBoolean(SyncConfiguration.PREF_CLUSTER_URL_IS_STALE, false);
}
public synchronized void setClusterURLIsStale(boolean clusterURLIsStale) {
Editor edit = accountSharedPreferences.edit();
edit.putBoolean(SyncConfiguration.PREF_CLUSTER_URL_IS_STALE, clusterURLIsStale);
edit.commit();
}
@Override
public boolean wantNodeAssignment() {
return getClusterURLIsStale();
}
@Override
public void informNodeAuthenticationFailed(GlobalSession session, URI failedClusterURL) {
// TODO: communicate to the user interface that we need a new user password!
// TODO: only freshen the cluster URL (better yet, forget the cluster URL) after the user has provided new credentials.
setClusterURLIsStale(false);
}
@Override
public void informNodeAssigned(GlobalSession session, URI oldClusterURL, URI newClusterURL) {
setClusterURLIsStale(false);
}
@Override
public void informUnauthorizedResponse(GlobalSession session, URI oldClusterURL) {
setClusterURLIsStale(true);
nodeAssignmentDelegate.setClusterURLIsStale(true);
}
@Override

View File

@ -41,10 +41,9 @@ public class TestClientsStage extends AndroidSyncTestCase {
final ClientsDataDelegate delegate = new MockClientsDataDelegate();
final GlobalSession session = new GlobalSession(
null,
TEST_USERNAME, new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD), null,
new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY),
callback, context, null, delegate);
callback, context, null, delegate, callback);
SyncClientsEngineStage stage = new SyncClientsEngineStage() {

View File

@ -153,10 +153,9 @@ public class TestResetting extends AndroidSyncTestCase {
private GlobalSession createDefaultGlobalSession(final GlobalSessionCallback callback) throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException {
return new GlobalSession(
null,
TEST_USERNAME, new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD), null,
new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY),
callback, getApplicationContext(), null, null) {
callback, getApplicationContext(), null, null, callback) {
@Override
public boolean engineIsEnabled(String engineName,

View File

@ -169,7 +169,7 @@ public class TestSyncAccounts extends AndroidSyncTestCase {
assertNotNull(account);
SharedPreferences prefs = Utils.getSharedPreferences(context, TEST_PRODUCT, TEST_USERNAME,
SyncAccounts.DEFAULT_SERVER, TEST_PROFILE, TEST_VERSION);
SyncConstants.DEFAULT_AUTH_SERVER, TEST_PROFILE, TEST_VERSION);
// Verify that client record is set.
assertEquals(TEST_GUID, prefs.getString(SyncConfiguration.PREF_ACCOUNT_GUID, null));

View File

@ -5,10 +5,10 @@ package org.mozilla.gecko.background.sync;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import org.json.simple.parser.ParseException;
import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
import org.mozilla.gecko.background.testhelpers.DefaultGlobalSessionCallback;
import org.mozilla.gecko.background.testhelpers.MockGlobalSession;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.sync.GlobalSession;
@ -21,7 +21,6 @@ import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
import org.mozilla.gecko.sync.setup.Constants;
import org.mozilla.gecko.sync.setup.SyncAccounts;
import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters;
import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
import org.mozilla.gecko.sync.syncadapter.SyncAdapter;
import android.accounts.Account;
@ -163,7 +162,7 @@ public class TestUpgradeRequired extends AndroidSyncTestCase {
*/
public void testUpgradeResponse() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException {
final Result calledUpgradeRequired = new Result();
final GlobalSessionCallback callback = new BlankGlobalSessionCallback() {
final GlobalSessionCallback callback = new DefaultGlobalSessionCallback() {
@Override
public void informUpgradeRequiredResponse(final GlobalSession session) {
calledUpgradeRequired.called = true;
@ -171,7 +170,7 @@ public class TestUpgradeRequired extends AndroidSyncTestCase {
};
final GlobalSession session = new MockGlobalSession(
TEST_SERVER, TEST_USERNAME, TEST_PASSWORD,
TEST_USERNAME, TEST_PASSWORD,
new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY), callback);
session.interpretHTTPFailure(simulate400());
@ -182,55 +181,4 @@ public class TestUpgradeRequired extends AndroidSyncTestCase {
public void tearDown() {
deleteTestAccount();
}
public abstract class BlankGlobalSessionCallback implements GlobalSessionCallback {
public BlankGlobalSessionCallback() {
}
@Override
public void requestBackoff(long backoff) {
}
@Override
public boolean wantNodeAssignment() {
return false;
}
@Override
public void informUnauthorizedResponse(GlobalSession globalSession,
URI oldClusterURL) {
}
@Override
public void informNodeAssigned(GlobalSession globalSession,
URI oldClusterURL, URI newClusterURL) {
}
@Override
public void informNodeAuthenticationFailed(GlobalSession globalSession,
URI failedClusterURL) {
}
@Override
public void handleAborted(GlobalSession globalSession, String reason) {
}
@Override
public void handleError(GlobalSession globalSession, Exception ex) {
}
@Override
public void handleSuccess(GlobalSession globalSession) {
}
@Override
public void handleStageCompleted(Stage currentState,
GlobalSession globalSession) {
}
@Override
public boolean shouldBackOff() {
return false;
}
}
}

View File

@ -60,4 +60,9 @@ public class DefaultGlobalSessionCallback implements GlobalSessionCallback {
public boolean shouldBackOff() {
return false;
}
}
@Override
public String nodeWeaveURL() {
return null;
}
}

View File

@ -19,10 +19,10 @@ import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
public class MockGlobalSession extends MockPrefsGlobalSession {
public MockGlobalSession(String clusterURL, String username, String password,
public MockGlobalSession(String username, String password,
KeyBundle syncKeyBundle, GlobalSessionCallback callback)
throws SyncConfigurationException, IllegalArgumentException, IOException, ParseException, NonObjectJSONException {
super(clusterURL, username, password, null, syncKeyBundle, callback, /* context */ null, null, null);
super(username, password, null, syncKeyBundle, callback, /* context */ null, null, null);
}
@Override

View File

@ -26,23 +26,23 @@ public class MockPrefsGlobalSession extends GlobalSession {
public MockSharedPreferences prefs;
public MockPrefsGlobalSession(String serverURL,
public MockPrefsGlobalSession(
String username, String password, String prefsPath,
KeyBundle syncKeyBundle, GlobalSessionCallback callback, Context context,
Bundle extras, ClientsDataDelegate clientsDelegate)
throws SyncConfigurationException, IllegalArgumentException, IOException,
ParseException, NonObjectJSONException {
this(serverURL, username, new BasicAuthHeaderProvider(username, password), prefsPath, syncKeyBundle, callback, context, extras, clientsDelegate);
this(username, new BasicAuthHeaderProvider(username, password), prefsPath, syncKeyBundle, callback, context, extras, clientsDelegate);
}
public MockPrefsGlobalSession(String serverURL,
public MockPrefsGlobalSession(
String username, AuthHeaderProvider authHeaderProvider, String prefsPath,
KeyBundle syncKeyBundle, GlobalSessionCallback callback, Context context,
Bundle extras, ClientsDataDelegate clientsDelegate)
throws SyncConfigurationException, IllegalArgumentException, IOException,
ParseException, NonObjectJSONException {
super(serverURL, username, authHeaderProvider, prefsPath, syncKeyBundle,
callback, context, extras, clientsDelegate);
super(username, authHeaderProvider, prefsPath, syncKeyBundle,
callback, context, extras, clientsDelegate, callback);
}
@Override