package edu.mit.mobile.android.content;
/*
* Copyright (C) 2011 MIT Mobile Experience Lab
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import java.util.HashMap;
import java.util.Map;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
/**
* A helper class that will do handle standard CRUD queries for URIs that
* represent relationships between a from and to. For example, it expects that
* the URIs passed to it be in the form of <code>/parent/1/child</code> or
* <code>/parent/1/child/2</code> where 1 is the ID of the parent and 2 is the
* ID of the child.
*
* The easiest way to use this is to have it be a static object of the
* {@link ContentProvider} where the provider defaults to calling the CRUD
* methods on the helper if no other matches are found.
*
* @author steve
*
*/
public final class DBHelperMapper {
private final Map<Integer, DBHelperMapItem> mDbhMap = new HashMap<Integer, DBHelperMapItem>();
/**
* Makes a mapping from the code to the given DBHelper. This helper will be
* used to handle any queries for items that match the given code. All other
* items will throw an error. Check {@link #canHandle(int)} and
* {@link #canQuery(int)}, etc. first to ensure that a query will complete.
*
* @param code
* A unique ID representing the given URI; usually a
* {@link UriMatcher} code
* @param helper
* The helper that should be used for this code.
* @param type
* The type of requests that should be handled by the helper. Any
* other requests will throw an error. Types can be joined
* together, eg. <code>TYPE_INSERT | TYPE_QUERY</code>
*/
public void addDirMapping(int code, DBHelper helper, int type){
mDbhMap.put(code, new DBHelperMapItem(type, false, helper));
}
public void addItemMapping(int code, DBHelper helper, int type){
mDbhMap.put(code, new DBHelperMapItem(type, true, helper));
}
public boolean canHandle(int code){
return mDbhMap.containsKey(code);
}
public boolean canInsert(int code){
final DBHelperMapItem item = mDbhMap.get(code);
return item != null && item.allowType(TYPE_INSERT);
}
public boolean canQuery(int code){
final DBHelperMapItem item = mDbhMap.get(code);
return item != null && item.allowType(TYPE_QUERY);
}
public boolean canUpdate(int code){
final DBHelperMapItem item = mDbhMap.get(code);
return item != null && item.allowType(TYPE_UPDATE);
}
public boolean canDelete(int code){
final DBHelperMapItem item = mDbhMap.get(code);
return item != null && item.allowType(TYPE_DELETE);
}
private String getType(int type){
String typeString = null;
if ((type & TYPE_INSERT) != 0){
typeString = "insert";
}else if ((type & TYPE_QUERY) != 0){
typeString = "query";
}else if ((type & TYPE_UPDATE) != 0){
typeString = "update";
}else if ((type & TYPE_DELETE) != 0){
typeString = "delete";
}
return typeString;
}
private DBHelperMapItem getMap(int type, int code){
final DBHelperMapItem dbhmi = mDbhMap.get(code);
if (dbhmi == null){
throw new IllegalArgumentException("No mapping for code "+ code);
}
if ((dbhmi.type & type) == 0){
throw new IllegalArgumentException("Cannot "+getType(type)+" for code " + code);
}
return dbhmi;
}
public Uri insert(int code, ContentProvider provider, SQLiteDatabase db, Uri uri, ContentValues values) throws SQLException {
final DBHelperMapItem dbhmi = getMap(TYPE_INSERT, code);
return dbhmi.dbHelper.insertDir(db, provider, uri, values);
}
public Cursor query(int code, ContentProvider provider, SQLiteDatabase db, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder){
final DBHelperMapItem dbhmi = getMap(TYPE_QUERY, code);
if (dbhmi.isItem){
return dbhmi.dbHelper.queryItem(db, uri, projection, selection, selectionArgs, sortOrder);
}else{
return dbhmi.dbHelper.queryDir(db, uri, projection, selection, selectionArgs, sortOrder);
}
}
public int update(int code, ContentProvider provider, SQLiteDatabase db, Uri uri, ContentValues cv, String selection, String[] selectionArgs){
final DBHelperMapItem dbhmi = getMap(TYPE_QUERY, code);
if (dbhmi.isItem){
return dbhmi.dbHelper.updateItem(db, provider, uri, cv, selection, selectionArgs);
}else{
return dbhmi.dbHelper.updateDir(db, provider, uri, cv, selection, selectionArgs);
}
}
public int delete(int code, ContentProvider provider, SQLiteDatabase db, Uri uri, String selection, String[] selectionArgs){
final DBHelperMapItem dbhmi = getMap(TYPE_QUERY, code);
if (dbhmi.isItem){
return dbhmi.dbHelper.deleteItem(db, provider,uri, selection, selectionArgs);
}else{
return dbhmi.dbHelper.deleteDir(db, provider, uri, selection, selectionArgs);
}
}
private class DBHelperMapItem {
public DBHelperMapItem(int type, boolean isItem, DBHelper dbHelper) {
this.type = type;
this.dbHelper = dbHelper;
this.isItem = isItem;
}
public boolean allowType(int type){
return (this.type & type) != 0;
}
final DBHelper dbHelper;
final int type;
final boolean isItem;
}
public static final int
TYPE_INSERT = 1,
TYPE_QUERY = 2,
TYPE_UPDATE = 4,
TYPE_DELETE = 8,
TYPE_ALL = TYPE_INSERT | TYPE_QUERY | TYPE_UPDATE | TYPE_DELETE;
}