Bug 731491 - Rework GeckoProvider. r=rnewman

--HG--
rename : mobile/android/base/db/GeckoProvider.java => mobile/android/base/db/PerProfileContentProvider.java
This commit is contained in:
Federico Paolinelli 2013-04-30 08:52:42 -04:00
parent 074c62ae8d
commit 37c3facdcc
4 changed files with 169 additions and 110 deletions

View File

@ -172,7 +172,7 @@ FENNEC_JAVA_FILES = \
db/BrowserContract.java \
db/BrowserProvider.java \
db/FormHistoryProvider.java \
db/GeckoProvider.java \
db/PerProfileContentProvider.java \
db/PasswordsProvider.java \
db/TabsProvider.java \
gfx/Axis.java \

View File

@ -20,7 +20,7 @@ import android.database.Cursor;
import android.net.Uri;
import android.text.TextUtils;
public class FormHistoryProvider extends GeckoProvider {
public class FormHistoryProvider extends PerProfileContentProvider {
static final String TABLE_FORM_HISTORY = "moz_formhistory";
static final String TABLE_DELETED_FORM_HISTORY = "moz_deleted_formhistory";
@ -29,8 +29,6 @@ public class FormHistoryProvider extends GeckoProvider {
private static final UriMatcher URI_MATCHER;
private static HashMap<String, String> FORM_HISTORY_PROJECTION_MAP;
private static HashMap<String, String> DELETED_FORM_HISTORY_PROJECTION_MAP;
// This should be kept in sync with the db version in toolkit/components/satchel/nsFormHistory.js
private static int DB_VERSION = 4;
@ -39,23 +37,19 @@ public class FormHistoryProvider extends GeckoProvider {
private static final String WHERE_GUID_IS_NULL = BrowserContract.DeletedFormHistory.GUID + " IS NULL";
private static final String WHERE_GUID_IS_VALUE = BrowserContract.DeletedFormHistory.GUID + " = ?";
private static final String LOG_TAG = "FormHistoryProvider";
static {
URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
URI_MATCHER.addURI(BrowserContract.FORM_HISTORY_AUTHORITY, "formhistory", FORM_HISTORY);
URI_MATCHER.addURI(BrowserContract.FORM_HISTORY_AUTHORITY, "deleted-formhistory", DELETED_FORM_HISTORY);
FORM_HISTORY_PROJECTION_MAP = new HashMap<String, String>();
DELETED_FORM_HISTORY_PROJECTION_MAP = new HashMap<String, String>();
}
@Override
public boolean onCreate() {
setLogTag("FormHistoryProvider");
setDBName(DB_FILENAME);
setDBVersion(DB_VERSION);
return super.onCreate();
public FormHistoryProvider() {
super(LOG_TAG);
}
@Override
public String getType(Uri uri) {
final int match = URI_MATCHER.match(uri);
@ -93,8 +87,9 @@ public class FormHistoryProvider extends GeckoProvider {
@Override
public String getSortOrder(Uri uri, String aRequested) {
if (!TextUtils.isEmpty(aRequested))
if (!TextUtils.isEmpty(aRequested)) {
return aRequested;
}
return null;
}
@ -152,4 +147,14 @@ public class FormHistoryProvider extends GeckoProvider {
@Override
public void onPostQuery(Cursor cursor, Uri uri, SQLiteBridge db) { }
@Override
protected String getDBName(){
return DB_FILENAME;
}
@Override
protected int getDBVersion(){
return DB_VERSION;
}
}

View File

@ -25,7 +25,7 @@ import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
public class PasswordsProvider extends GeckoProvider {
public class PasswordsProvider extends PerProfileContentProvider {
static final String TABLE_PASSWORDS = "moz_logins";
static final String TABLE_DELETED_PASSWORDS = "moz_deleted_logins";
@ -43,10 +43,11 @@ public class PasswordsProvider extends GeckoProvider {
// this should be kept in sync with the version in toolkit/components/passwordmgr/storage-mozStorage.js
private static final int DB_VERSION = 5;
private static final String DB_FILENAME = "signons.sqlite";
private static final String WHERE_GUID_IS_NULL = BrowserContract.DeletedPasswords.GUID + " IS NULL";
private static final String WHERE_GUID_IS_VALUE = BrowserContract.DeletedPasswords.GUID + " = ?";
private static final String LOG_TAG = "GeckPasswordsProvider";
static {
URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
@ -78,12 +79,18 @@ public class PasswordsProvider extends GeckoProvider {
System.loadLibrary("mozglue");
}
public PasswordsProvider() {
super(LOG_TAG);
}
@Override
public boolean onCreate() {
setLogTag("GeckoPasswordsProvider");
setDBName(DB_FILENAME);
setDBVersion(DB_VERSION);
return super.onCreate();
protected String getDBName(){
return DB_FILENAME;
}
@Override
protected int getDBVersion(){
return DB_VERSION;
}
@Override
@ -119,8 +126,9 @@ public class PasswordsProvider extends GeckoProvider {
@Override
public String getSortOrder(Uri uri, String aRequested) {
if (!TextUtils.isEmpty(aRequested))
if (!TextUtils.isEmpty(aRequested)) {
return aRequested;
}
final int match = URI_MATCHER.match(uri);
switch (match) {
@ -206,7 +214,7 @@ public class PasswordsProvider extends GeckoProvider {
}
}
} catch (Exception ex) {
Log.e(getLogTag(), "Error in NSSBridge");
Log.e(LOG_TAG, "Error in NSSBridge");
throw new RuntimeException(ex);
}
return result;

View File

@ -34,31 +34,31 @@ import android.util.Log;
* public abstract void initGecko();
*/
public abstract class GeckoProvider extends ContentProvider {
private String mLogTag = "GeckoPasswordsProvider";
private String mDBName = "";
private int mDBVersion = 0;
public abstract class PerProfileContentProvider extends ContentProvider {
private HashMap<String, SQLiteBridge> mDatabasePerProfile;
protected Context mContext = null;
private final String mLogTag;
protected PerProfileContentProvider(String logTag) {
mLogTag = logTag;
}
@Override
public void shutdown() {
if (mDatabasePerProfile == null)
return;
Collection<SQLiteBridge> bridges = mDatabasePerProfile.values();
Iterator<SQLiteBridge> it = bridges.iterator();
while (it.hasNext()) {
SQLiteBridge bridge = it.next();
if (bridge != null) {
try {
bridge.close();
} catch (Exception ex) { }
}
if (mDatabasePerProfile == null) {
return;
}
mDatabasePerProfile = null;
synchronized (this) {
for (SQLiteBridge bridge : mDatabasePerProfile.values()){
if (bridge != null) {
try {
bridge.close();
} catch (Exception ex) { }
}
}
mDatabasePerProfile = null;
}
}
@Override
@ -66,29 +66,6 @@ public abstract class GeckoProvider extends ContentProvider {
shutdown();
}
protected void setLogTag(String aLogTag) {
mLogTag = aLogTag;
}
protected String getLogTag() {
return mLogTag;
}
protected void setDBName(String aDBName) {
mDBName = aDBName;
}
protected String getDBName() {
return mDBName;
}
protected void setDBVersion(int aVersion) {
mDBVersion = aVersion;
}
protected int getDBVersion() {
return mDBVersion;
}
private SQLiteBridge getDB(Context context, final String databasePath) {
SQLiteBridge bridge = null;
@ -100,11 +77,12 @@ public abstract class GeckoProvider extends ContentProvider {
GeckoLoader.loadNSSLibs(context, resourcePath);
bridge = SQLiteBridge.openDatabase(databasePath, null, 0);
int version = bridge.getVersion();
dbNeedsSetup = version != mDBVersion;
dbNeedsSetup = version != getDBVersion();
} catch (SQLiteBridgeException ex) {
// close the database
if (bridge != null)
if (bridge != null) {
bridge.close();
}
// this will throw if the database can't be found
// we should attempt to set it up if Gecko is running
@ -126,53 +104,110 @@ public abstract class GeckoProvider extends ContentProvider {
bridge = null;
initGecko();
}
if (bridge != null)
mDatabasePerProfile.put(databasePath, bridge);
return bridge;
}
/**
* Returns the absolute path of a database file depending on the specified profile and dbName.
* @param profile
* the profile whose dbPath must be returned
* @param dbName
* the name of the db file whose absolute path must be returned
* @return the absolute path of the db file or <code>null</code> if it was not possible to retrieve a valid path
*
*/
private String getDatabasePathForProfile(String profile, String dbName) {
// Depends on the vagaries of GeckoProfile.get, so null check for safety.
File profileDir = GeckoProfile.get(mContext, profile).getDir();
if (profileDir == null) {
return null;
}
String databasePath = new File(profileDir, dbName).getAbsolutePath();
return databasePath;
}
/**
* Returns a SQLiteBridge object according to the specified profile id and to the name of db related to the
* current provider instance.
* @param profile
* the id of the profile to be used to retrieve the related SQLiteBridge
* @return the <code>SQLiteBridge</code> related to the specified profile id or <code>null</code> if it was
* not possible to retrieve a valid SQLiteBridge
*/
private SQLiteBridge getDatabaseForProfile(String profile) {
if (TextUtils.isEmpty(profile)) {
profile = GeckoProfile.get(mContext).getName();
Log.d(mLogTag, "No profile provided, using '" + profile + "'");
}
final String dbName = getDBName();
String mapKey = profile + "/" + dbName;
SQLiteBridge db = null;
synchronized (this) {
String dbPath = getDatabasePathForProfile(profile);
db = mDatabasePerProfile.get(dbPath);
if (db == null) {
db = getDB(mContext, dbPath);
}
}
return db;
}
private SQLiteBridge getDatabaseForPath(String profilePath) {
SQLiteBridge db = null;
synchronized (this) {
db = mDatabasePerProfile.get(profilePath);
if (db == null) {
File profileDir = new File(profilePath, mDBName);
db = getDB(mContext, profileDir.getPath());
db = mDatabasePerProfile.get(mapKey);
if (db != null) {
return db;
}
final String dbPath = getDatabasePathForProfile(profile, dbName);
if (dbPath == null) {
Log.e(mLogTag, "Failed to get a valid db path for profile '" + profile + "'' dbName '" + dbName + "'");
return null;
}
db = getDB(mContext, dbPath);
if (db != null) {
mDatabasePerProfile.put(mapKey, db);
}
}
return db;
}
private String getDatabasePathForProfile(String profile) {
File profileDir = GeckoProfile.get(mContext, profile).getDir();
if (profileDir == null) {
return null;
}
String databasePath = new File(profileDir, mDBName).getAbsolutePath();
return databasePath;
/**
* Returns a SQLiteBridge object according to the specified profile path and to the name of db related to the
* current provider instance.
* @param profilePath
* the profilePath to be used to retrieve the related SQLiteBridge
* @return the <code>SQLiteBridge</code> related to the specified profile path or <code>null</code> if it was
* not possible to retrieve a valid <code>SQLiteBridge</code>
*/
private SQLiteBridge getDatabaseForProfilePath(String profilePath) {
File profileDir = new File(profilePath, getDBName());
final String dbPath = profileDir.getPath();
return getDatabaseForDBPath(dbPath);
}
/**
* Returns a SQLiteBridge object according to the specified file path.
* @param dbPath
* the path of the file to be used to retrieve the related SQLiteBridge
* @return the <code>SQLiteBridge</code> related to the specified file path or <code>null</code> if it was
* not possible to retrieve a valid <code>SQLiteBridge</code>
*
*/
private SQLiteBridge getDatabaseForDBPath(String dbPath) {
SQLiteBridge db = null;
synchronized (this) {
db = mDatabasePerProfile.get(dbPath);
if (db != null) {
return db;
}
db = getDB(mContext, dbPath);
if (db != null) {
mDatabasePerProfile.put(dbPath, db);
}
}
return db;
}
/**
* Returns a SQLiteBridge object to be used to perform operations on the given <code>Uri</code>.
* @param uri
* the <code>Uri</code> to be used to retrieve the related SQLiteBridge
* @return a <code>SQLiteBridge</code> object to be used on the given uri or <code>null</code> if it was
* not possible to retrieve a valid <code>SQLiteBridge</code>
*
*/
private SQLiteBridge getDatabase(Uri uri) {
String profile = null;
String profilePath = null;
@ -181,8 +216,9 @@ public abstract class GeckoProvider extends ContentProvider {
profilePath = uri.getQueryParameter(BrowserContract.PARAM_PROFILE_PATH);
// Testing will specify the absolute profile path
if (profilePath != null)
return getDatabaseForPath(profilePath);
if (profilePath != null) {
return getDatabaseForProfilePath(profilePath);
}
return getDatabaseForProfile(profile);
}
@ -204,8 +240,9 @@ public abstract class GeckoProvider extends ContentProvider {
public int delete(Uri uri, String selection, String[] selectionArgs) {
int deleted = 0;
final SQLiteBridge db = getDatabase(uri);
if (db == null)
if (db == null) {
return deleted;
}
try {
deleted = db.delete(getTable(uri), selection, selectionArgs);
@ -225,8 +262,9 @@ public abstract class GeckoProvider extends ContentProvider {
// If we can not get a SQLiteBridge instance, its likely that the database
// has not been set up and Gecko is not running. We return null and expect
// callers to try again later
if (db == null)
if (db == null) {
return null;
}
setupDefaults(uri, values);
@ -262,8 +300,9 @@ public abstract class GeckoProvider extends ContentProvider {
// If we can not get a SQLiteBridge instance, its likely that the database
// has not been set up and Gecko is not running. We return 0 and expect
// callers to try again later
if (db == null)
if (db == null) {
return 0;
}
long id = -1;
int rowsAdded = 0;
@ -287,8 +326,9 @@ public abstract class GeckoProvider extends ContentProvider {
db.endTransaction();
}
if (rowsAdded > 0)
if (rowsAdded > 0) {
mContext.getContentResolver().notifyChange(uri, null);
}
return rowsAdded;
}
@ -302,8 +342,9 @@ public abstract class GeckoProvider extends ContentProvider {
// If we can not get a SQLiteBridge instance, its likely that the database
// has not been set up and Gecko is not running. We return null and expect
// callers to try again later
if (db == null)
if (db == null) {
return updated;
}
onPreUpdate(values, uri, db);
@ -326,8 +367,9 @@ public abstract class GeckoProvider extends ContentProvider {
// If we can not get a SQLiteBridge instance, its likely that the database
// has not been set up and Gecko is not running. We return null and expect
// callers to try again later
if (db == null)
if (db == null) {
return cursor;
}
sortOrder = getSortOrder(uri, sortOrder);
@ -342,17 +384,21 @@ public abstract class GeckoProvider extends ContentProvider {
return cursor;
}
public abstract String getTable(Uri uri);
protected abstract String getDBName();
public abstract String getSortOrder(Uri uri, String aRequested);
protected abstract int getDBVersion();
public abstract void setupDefaults(Uri uri, ContentValues values);
protected abstract String getTable(Uri uri);
public abstract void initGecko();
protected abstract String getSortOrder(Uri uri, String aRequested);
public abstract void onPreInsert(ContentValues values, Uri uri, SQLiteBridge db);
protected abstract void setupDefaults(Uri uri, ContentValues values);
public abstract void onPreUpdate(ContentValues values, Uri uri, SQLiteBridge db);
protected abstract void initGecko();
public abstract void onPostQuery(Cursor cursor, Uri uri, SQLiteBridge db);
protected abstract void onPreInsert(ContentValues values, Uri uri, SQLiteBridge db);
protected abstract void onPreUpdate(ContentValues values, Uri uri, SQLiteBridge db);
protected abstract void onPostQuery(Cursor cursor, Uri uri, SQLiteBridge db);
}