Bug 709402 preparation. r=rnewman

This commit is contained in:
Nick Alexander 2012-03-23 11:03:48 -07:00
parent d6a3d199c3
commit 5d1183b8ef
8 changed files with 125 additions and 154 deletions

View File

@ -211,7 +211,7 @@ public class AndroidBrowserBookmarksDataAccessor extends AndroidBrowserRepositor
// content provider to do that for us.
return cv;
}
/**
* Returns a cursor over non-deleted records that list the given androidID as a parent.
*/

View File

@ -1,54 +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):
* Jason Voll <jvoll@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.repositories.android;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.sync.Logger;
import org.mozilla.gecko.sync.repositories.domain.HistoryRecord;
import org.mozilla.gecko.sync.repositories.domain.Record;
import android.content.ContentValues;
import android.content.Context;
import android.net.Uri;
import android.util.Log;
public class AndroidBrowserHistoryDataAccessor extends AndroidBrowserRepositoryDataAccessor {
public class AndroidBrowserHistoryDataAccessor extends
AndroidBrowserRepositoryDataAccessor {
private AndroidBrowserHistoryDataExtender dataExtender;
@ -56,7 +24,7 @@ public class AndroidBrowserHistoryDataAccessor extends AndroidBrowserRepositoryD
super(context);
dataExtender = new AndroidBrowserHistoryDataExtender(context);
}
public AndroidBrowserHistoryDataExtender getHistoryDataExtender() {
return dataExtender;
}
@ -70,15 +38,16 @@ public class AndroidBrowserHistoryDataAccessor extends AndroidBrowserRepositoryD
protected ContentValues getContentValues(Record record) {
ContentValues cv = new ContentValues();
HistoryRecord rec = (HistoryRecord) record;
cv.put(BrowserContract.History.GUID, rec.guid);
cv.put(BrowserContract.History.TITLE, rec.title);
cv.put(BrowserContract.History.URL, rec.histURI);
cv.put(BrowserContract.History.GUID, rec.guid);
cv.put(BrowserContract.History.TITLE, rec.title);
cv.put(BrowserContract.History.URL, rec.histURI);
if (rec.visits != null) {
JSONArray visits = rec.visits;
long mostRecent = 0;
for (int i = 0; i < visits.size(); i++) {
JSONObject visit = (JSONObject) visits.get(i);
long visitDate = (Long) visit.get(AndroidBrowserHistoryRepositorySession.KEY_DATE);
long visitDate = (Long) visit
.get(AndroidBrowserHistoryRepositorySession.KEY_DATE);
if (visitDate > mostRecent) {
mostRecent = visitDate;
}
@ -94,13 +63,13 @@ public class AndroidBrowserHistoryDataAccessor extends AndroidBrowserRepositoryD
protected String[] getAllColumns() {
return BrowserContractHelpers.HistoryColumns;
}
@Override
public Uri insert(Record record) {
HistoryRecord rec = (HistoryRecord) record;
Log.d(LOG_TAG, "Storing visits for " + record.guid);
Logger.debug(LOG_TAG, "Storing visits for " + record.guid);
dataExtender.store(record.guid, rec.visits);
Log.d(LOG_TAG, "Storing record " + record.guid);
Logger.debug(LOG_TAG, "Storing record " + record.guid);
return super.insert(record);
}
@ -108,17 +77,17 @@ public class AndroidBrowserHistoryDataAccessor extends AndroidBrowserRepositoryD
public void update(String oldGUID, Record newRecord) {
HistoryRecord rec = (HistoryRecord) newRecord;
String newGUID = newRecord.guid;
Log.d(LOG_TAG, "Storing visits for " + newGUID + ", replacing " + oldGUID);
Logger.debug(LOG_TAG, "Storing visits for " + newGUID + ", replacing " + oldGUID);
dataExtender.delete(oldGUID);
dataExtender.store(newGUID, rec.visits);
super.update(oldGUID, newRecord);
}
@Override
protected void delete(String guid) {
Log.d(LOG_TAG, "Deleting record " + guid);
super.delete(guid);
public int purgeGuid(String guid) {
Logger.debug(LOG_TAG, "Purging record with " + guid);
dataExtender.delete(guid);
return super.purgeGuid(guid);
}
public void closeExtender() {

View File

@ -1,42 +1,10 @@
/* ***** 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):
* Jason Voll <jvoll@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.repositories.android;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.sync.repositories.domain.PasswordRecord;
import org.mozilla.gecko.sync.repositories.domain.Record;
@ -55,20 +23,20 @@ public class AndroidBrowserPasswordsDataAccessor extends AndroidBrowserRepositor
PasswordRecord rec = (PasswordRecord) record;
ContentValues cv = new ContentValues();
cv.put(PasswordColumns.GUID, rec.guid);
cv.put(PasswordColumns.HOSTNAME, rec.hostname);
cv.put(PasswordColumns.HTTP_REALM, rec.httpRealm);
cv.put(PasswordColumns.FORM_SUBMIT_URL, rec.formSubmitURL);
cv.put(PasswordColumns.USERNAME_FIELD, rec.usernameField);
cv.put(PasswordColumns.PASSWORD_FIELD, rec.passwordField);
cv.put(BrowserContract.Passwords.GUID, rec.guid);
cv.put(BrowserContract.Passwords.HOSTNAME, rec.hostname);
cv.put(BrowserContract.Passwords.HTTP_REALM, rec.httpRealm);
cv.put(BrowserContract.Passwords.FORM_SUBMIT_URL, rec.formSubmitURL);
cv.put(BrowserContract.Passwords.USERNAME_FIELD, rec.usernameField);
cv.put(BrowserContract.Passwords.PASSWORD_FIELD, rec.passwordField);
// TODO Do encryption of username/password here. Bug 711636
cv.put(PasswordColumns.ENC_TYPE, rec.encType);
cv.put(PasswordColumns.ENCRYPTED_USERNAME, rec.username);
cv.put(PasswordColumns.ENCRYPTED_PASSWORD, rec.password);
cv.put(BrowserContract.Passwords.ENC_TYPE, rec.encType);
cv.put(BrowserContract.Passwords.ENCRYPTED_USERNAME, rec.username);
cv.put(BrowserContract.Passwords.ENCRYPTED_PASSWORD, rec.password);
cv.put(PasswordColumns.TIMES_USED, rec.timesUsed);
cv.put(PasswordColumns.TIME_LAST_USED, rec.timeLastUsed);
cv.put(BrowserContract.Passwords.TIMES_USED, rec.timesUsed);
cv.put(BrowserContract.Passwords.TIME_LAST_USED, rec.timeLastUsed);
return cv;
}

View File

@ -61,9 +61,20 @@ public abstract class AndroidBrowserRepositoryDataAccessor {
}
protected abstract String[] getAllColumns();
/**
* Produce a <code>ContentValues</code> instance that represents the provided <code>Record</code>.
*
* @param record The <code>Record</code> to be converted.
* @return The <code>ContentValues</code> corresponding to <code>record</code>.
*/
protected abstract ContentValues getContentValues(Record record);
protected abstract Uri getUri();
/**
* Dump all the records in raw format.
*/
public void dumpDB() {
Cursor cur = null;
try {
@ -83,36 +94,34 @@ public abstract class AndroidBrowserRepositoryDataAccessor {
public void wipe() {
Uri uri = getUri();
Logger.info(LOG_TAG, "wiping: " + uri);
Logger.debug(LOG_TAG, "Wiping: " + uri);
context.getContentResolver().delete(uri, null, null);
}
public void purgeDeleted() throws NullCursorException {
String where = BrowserContract.SyncColumns.IS_DELETED + "= 1";
Cursor cur = queryHelper.safeQuery(".purgeDeleted", GUID_COLUMNS, where, null, null);
try {
if (!cur.moveToFirst()) {
return;
}
while (!cur.isAfterLast()) {
delete(RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID));
cur.moveToNext();
}
} finally {
cur.close();
}
Uri uri = getUri();
Logger.info(LOG_TAG, "Purging deleted from: " + uri);
context.getContentResolver().delete(uri, where, null);
}
protected void delete(String guid) {
/**
* Remove matching records from the database entirely, i.e., do not set a
* deleted flag, delete entirely.
*
* @param guid
* The GUID of the record to be deleted.
* @return The number of records deleted.
*/
public int purgeGuid(String guid) {
String where = BrowserContract.SyncColumns.GUID + " = ?";
String[] args = new String[] { guid };
int deleted = context.getContentResolver().delete(getUri(), where, args);
if (deleted == 1) {
return;
if (deleted != 1) {
Logger.warn(LOG_TAG, "Unexpectedly deleted " + deleted + " records for guid " + guid);
}
Logger.warn(LOG_TAG, "Unexpectedly deleted " + deleted + " rows for guid " + guid);
return deleted;
}
public void update(String guid, Record newRecord) {
@ -132,21 +141,23 @@ public abstract class AndroidBrowserRepositoryDataAccessor {
/**
* Fetch all records.
* <p>
* The caller is responsible for closing the cursor.
*
* @return A cursor. You *must* close this when you're done with it.
* @return A cursor. You </b>must</b> close this when you're done with it.
* @throws NullCursorException
*/
public Cursor fetchAll() throws NullCursorException {
return queryHelper.safeQuery(".fetchAll", getAllColumns(), null, null, null);
}
/**
* Fetch GUIDs for records modified since the provided timestamp.
* <p>
* The caller is responsible for closing the cursor.
*
* @param timestamp
* @return A cursor. You *must* close this when you're done with it.
* @param timestamp A timestamp in milliseconds.
* @return A cursor. You <b>must</b> close this when you're done with it.
* @throws NullCursorException
*/
public Cursor getGUIDsSince(long timestamp) throws NullCursorException {
@ -158,10 +169,11 @@ public abstract class AndroidBrowserRepositoryDataAccessor {
/**
* Fetch records modified since the provided timestamp.
* <p>
* The caller is responsible for closing the cursor.
*
* @param timestamp
* @return A cursor. You *must* close this when you're done with it.
* @param timestamp A timestamp in milliseconds.
* @return A cursor. You <b>must</b> close this when you're done with it.
* @throws NullCursorException
*/
public Cursor fetchSince(long timestamp) throws NullCursorException {
@ -173,10 +185,11 @@ public abstract class AndroidBrowserRepositoryDataAccessor {
/**
* Fetch records for the provided GUIDs.
* <p>
* The caller is responsible for closing the cursor.
*
* @param guids
* @return A cursor. You *must* close this when you're done with it.
* @param guids The GUIDs of the records to fetch.
* @return A cursor. You <b>must</b> close this when you're done with it.
* @throws NullCursorException
*/
public Cursor fetch(String guids[]) throws NullCursorException {
@ -198,17 +211,6 @@ public abstract class AndroidBrowserRepositoryDataAccessor {
return builder.toString();
}
public void delete(Record record) {
String where = BrowserContract.SyncColumns.GUID + " = ?";
String[] args = new String[] { record.guid };
int deleted = context.getContentResolver().delete(getUri(), where, args);
if (deleted == 1) {
return;
}
Logger.warn(LOG_TAG, "Unexpectedly deleted " + deleted + " rows for guid " + record.guid);
}
public void updateByGuid(String guid, ContentValues cv) {
String where = BrowserContract.SyncColumns.GUID + " = ?";
String[] args = new String[] { guid };

View File

@ -489,9 +489,9 @@ public abstract class AndroidBrowserRepositorySession extends StoreTrackingRepos
}
protected void storeRecordDeletion(final Record record) {
// TODO: we ought to mark the record as deleted rather than deleting it,
// TODO: we ought to mark the record as deleted rather than purging it,
// in order to support syncing to multiple destinations. Bug 722607.
dbHelper.delete(record); // TODO: mm?
dbHelper.purgeGuid(record.guid);
delegate.onRecordStoreSucceeded(record);
}

View File

@ -13,6 +13,12 @@ import org.mozilla.gecko.db.BrowserContract;
import android.net.Uri;
public class BrowserContractHelpers extends BrowserContract {
protected static Uri withSync(Uri u) {
return u.buildUpon()
.appendQueryParameter(PARAM_IS_SYNC, "true")
.build();
}
protected static Uri withSyncAndDeleted(Uri u) {
return u.buildUpon()
.appendQueryParameter(PARAM_IS_SYNC, "true")
@ -30,9 +36,9 @@ public class BrowserContractHelpers extends BrowserContract {
public static final Uri PASSWORDS_CONTENT_URI = null;
/*
public static final Uri PASSWORDS_CONTENT_URI = withSyncAndDeleted(Passwords.CONTENT_URI);
public static final Uri FORM_HISTORY_CONTENT_URI = withSyncAndDeleted(FormHistory.CONTENT_URI);
public static final Uri DELETED_FORM_HISTORY_CONTENT_URI = withSyncAndDeleted(DeletedFormHistory.CONTENT_URI);
*/
public static final Uri FORM_HISTORY_CONTENT_URI = withSync(FormHistory.CONTENT_URI);
public static final Uri DELETED_FORM_HISTORY_CONTENT_URI = withSync(DeletedFormHistory.CONTENT_URI);
public static final String[] PasswordColumns = new String[] {
CommonColumns._ID,
@ -80,6 +86,23 @@ public class BrowserContractHelpers extends BrowserContract {
Bookmarks.KEYWORD
};
public static final String[] FormHistoryColumns = new String[] {
FormHistory.ID,
FormHistory.GUID,
FormHistory.FIELD_NAME,
FormHistory.VALUE,
FormHistory.TIMES_USED,
FormHistory.FIRST_USED,
FormHistory.LAST_USED
};
public static final String[] DeletedColumns = new String[] {
DeletedFormHistory.ID,
DeletedFormHistory.GUID,
DeletedFormHistory.TIME_DELETED
};
// Mapping from Sync types to Fennec types.
public static final String[] BOOKMARK_TYPE_CODE_TO_STRING = {
// Observe omissions: "microsummary", "item".

View File

@ -146,7 +146,7 @@ public class RepoUtils {
Logger.pii(LOG_TAG, "> URI: " + rec.histURI);
}
} catch (Exception e) {
Logger.debug(LOG_TAG, "Exception logging bookmark record " + rec, e);
Logger.debug(LOG_TAG, "Exception logging history record " + rec, e);
}
return rec;
}
@ -154,10 +154,10 @@ public class RepoUtils {
public static void logClient(ClientRecord rec) {
if (Logger.logVerbose(LOG_TAG)) {
Logger.trace(LOG_TAG, "Returning client record " + rec.guid + " (" + rec.androidID + ")");
Logger.trace(LOG_TAG, "Client Name: " + rec.name);
Logger.trace(LOG_TAG, "Client Type: " + rec.type);
Logger.trace(LOG_TAG, "Client Name: " + rec.name);
Logger.trace(LOG_TAG, "Client Type: " + rec.type);
Logger.trace(LOG_TAG, "Last Modified: " + rec.lastModified);
Logger.trace(LOG_TAG, "Deleted: " + rec.deleted);
Logger.trace(LOG_TAG, "Deleted: " + rec.deleted);
}
}
@ -217,19 +217,26 @@ public class RepoUtils {
return " ".substring(0, i);
}
private static String dashes(int i) {
return "-------------------------------------".substring(0, i);
}
public static void dumpCursor(Cursor cur) {
dumpCursor(cur, 18, "records");
}
public static void dumpCursor(Cursor cur, int columnWidth, String tag) {
int originalPosition = cur.getPosition();
try {
String[] columnNames = cur.getColumnNames();
int columnCount = cur.getColumnCount();
// 12 chars each column.
for (int i = 0; i < columnCount; ++i) {
System.out.print(fixedWidth(12, columnNames[i]) + " | ");
System.out.print(fixedWidth(columnWidth, columnNames[i]) + " | ");
}
System.out.println("");
System.out.println("(" + cur.getCount() + " " + tag + ")");
for (int i = 0; i < columnCount; ++i) {
System.out.print("------------" + " | ");
System.out.print(dashes(columnWidth) + " | ");
}
System.out.println("");
if (!cur.moveToFirst()) {
@ -238,15 +245,17 @@ public class RepoUtils {
}
cur.moveToFirst();
while (cur.moveToNext()) {
while (!cur.isAfterLast()) {
for (int i = 0; i < columnCount; ++i) {
System.out.print(fixedWidth(12, cur.getString(i)) + " | ");
System.out.print(fixedWidth(columnWidth, cur.getString(i)) + " | ");
}
System.out.println("");
cur.moveToNext();
}
for (int i = 0; i < columnCount; ++i) {
System.out.print("---------------");
for (int i = 0; i < columnCount-1; ++i) {
System.out.print(dashes(columnWidth + 3));
}
System.out.print(dashes(columnWidth + 3 - 1));
System.out.println("");
} finally {
cur.moveToPosition(originalPosition);

File diff suppressed because one or more lines are too long