/* * Copyright (C) 2012 Eyal LEZMY (http://www.eyal.fr) * * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package fr.eyal.lib.data.model.provider; import java.util.ArrayList; import android.content.ContentProvider; import android.content.ContentProviderOperation; import android.content.ContentProviderResult; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.OperationApplicationException; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; import fr.eyal.lib.data.model.BusinessObjectDAO; import fr.eyal.lib.util.Out; /** * @author Eyal LEZMY */ public abstract class BusinessObjectProvider extends ContentProvider { private static final String TAG = BusinessObjectProvider.class.getSimpleName(); public static String DATABASE_NAME = null; public static int DATABASE_VERSION = -1; /** * Tables' names list */ public static String[] DATABASE_TABLES_NAMES = null; /** * Tables' fields' names list */ public static String[][] DATABASE_TABLES_FIELDS_NAMES = null; /** * Tables' fields' names list */ public static String[] CREATE_TABLES = null; /** * Context of execution */ private static Context sContext; /** * SQLite Open Helper */ private static DatabaseHelper sDbHelper; /** * Uri matcher */ protected static UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); public static final String PROVIDER_PREFIX = "content://"; /** * Codes returned by the URIMatcher corresponding to the URI analyzed */ @Override public boolean onCreate() { Out.d(TAG, "On Create BusinessObjectProvider"); initialize(getContext()); return true; } /** * Initialize provider context * * @param context is the context of execution. If possible give the Application's context */ public static void initialize(final Context context) { if (sContext == null) { Out.d(TAG, "initialize!!"); sContext = context.getApplicationContext(); sDbHelper = new DatabaseHelper(sContext); } } /***************************** * * ContentProvider's Functions * *****************************/ @Override public int delete(final Uri uri, final String where, final String[] whereArgs) { final int match = sUriMatcher.match(uri); Out.d(TAG, TAG + ".delete: uri=" + uri + ", match is " + match); //We get the database access SQLiteDatabase db = sDbHelper.getWritableDatabase(); int count; //we get the table and then we delete the field into the database String table = getTableName(match); count = db.delete(table, where, whereArgs); sContext.getContentResolver().notifyChange(uri, null); return count; } @Override public Uri insert(final Uri uri, ContentValues values) { //we get the type of the URI received final int match = sUriMatcher.match(uri); //log message Out.d(TAG, "BusinessObjectProvider.insert: uri=" + uri + ", match is " + match); //we manage the null ContentValues if (values == null) values = new ContentValues(); //we prepare the database access SQLiteDatabase db = sDbHelper.getWritableDatabase(); //we create the result values long id = BusinessObjectDAO.ID_INVALID; Uri resultUri; //we get the table name and then insert into the database String table = getTableName(match); id = db.insert(table, "foo", values); //we add the id received at the end of the URI resultUri = ContentUris.withAppendedId(uri, id); //we return the URI with the id of the entry at the end return resultUri; } @Override public Cursor query(final Uri uri, final String[] columns, final String where, final String[] whereArgs, final String order) { Cursor c = null; final int match = sUriMatcher.match(uri); //get a readable database access SQLiteDatabase db = sDbHelper.getReadableDatabase(); //log message Out.d(TAG, "BusinessObjectProvider.query: uri=" + uri + ", match is " + match); //we get the table and then query to the database String table = getTableName(match); c = db.query(table, columns, where, whereArgs, null, null, order); //we notify that a change happened if it actually occurred if ((c != null) && !isTemporary()) { c.setNotificationUri(sContext.getContentResolver(), uri); } return c; } @Override public int update(final Uri uri, final ContentValues values, final String where, final String[] whereArgs) { final int match = sUriMatcher.match(uri); //get a readable database access SQLiteDatabase db = sDbHelper.getWritableDatabase(); //log message Out.d(TAG, "BusinessObjectProvider.query: uri=" + uri + ", match is " + match); //we initialize the update counter int count = 0; String table = getTableName(match); //throws an exception if there is no table name if (table == null) throw new IllegalArgumentException("Unknown URI " + uri); //update the database count = db.update(table, values, where, whereArgs); //we notify that a change happened sContext.getContentResolver().notifyChange(uri, null); return count; } /** * Get the ContentResolver of the application Context * * @return the ContentResolver of the context * @throws InstantiationException */ public static ContentResolver getContentResolver() throws InstantiationException { if(sContext == null) throw new InstantiationException("The ContentProvider does not exits. Did you declare it on the Android Manifest?"); return sContext.getContentResolver(); } /** * Get the table name corresponding to the matched URI * This used to implement a switch/case algorithm like this : * * <code> * switch (match) { * case CODE_PREVISION_METEO: * return PrevisionMeteo.DATABASE_TABLE_NAME; * break; * case CODE_METEO_WEATHER: * return MeteoWeather.DATABASE_TABLE_NAME; * break; * default: * throw new IllegalArgumentException("Unknown URI " + uri); * } * </code> * * * @param match result of the {@link UriMatcher} match method * * @return the name of the corresponding table */ protected abstract String getTableName(int match); /**************** Subclass for the database automatic generation ******************/ private static class DatabaseHelper extends SQLiteOpenHelper { private static final String TAG = "DatabaseHelper"; DatabaseHelper(final Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(final SQLiteDatabase db) { Out.d(TAG, "Creation de la BDD"); //we go through the tables creation scripts for (int i = 0; i < CREATE_TABLES.length; i++) { Out.d(TAG, CREATE_TABLES[i]); //we create each table into the database db.execSQL(CREATE_TABLES[i]); } } @Override public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { Out.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data"); //we go through the tables names array for (int i = 0; i < DATABASE_TABLES_NAMES.length; i++) { //we DROP each table db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLES_NAMES[i]); } //we recreate the table onCreate(db); } } /** * Apply the given set of {@link ContentProviderOperation}, executing inside * a {@link SQLiteDatabase} transaction. All changes will be rolled back if * any single one fails. */ @Override public ContentProviderResult[] applyBatch(final ArrayList<ContentProviderOperation> operations) throws OperationApplicationException { final SQLiteDatabase db = sDbHelper.getWritableDatabase(); db.beginTransaction(); try { final int numOperations = operations.size(); final ContentProviderResult[] results = new ContentProviderResult[numOperations]; for (int i = 0; i < numOperations; i++) { results[i] = operations.get(i).apply(this, results, i); } db.setTransactionSuccessful(); return results; } finally { db.endTransaction(); } } }