package by.istin.android.xcore.provider.impl; import android.content.ContentProviderOperation; import android.content.ContentProviderResult; 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.net.Uri; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import by.istin.android.xcore.db.IDBSupport; import by.istin.android.xcore.db.operation.IDBBatchOperationSupport; import by.istin.android.xcore.db.operation.IDBDeleteOperationSupport; import by.istin.android.xcore.db.operation.IDBInsertOrUpdateOperationSupport; import by.istin.android.xcore.provider.IDBContentProviderSupport; import by.istin.android.xcore.provider.ModelContract; import by.istin.android.xcore.source.DataSourceRequest; import by.istin.android.xcore.utils.StringUtil; /** * Created with IntelliJ IDEA. * User: Uladzimir_Klyshevich * Date: 10/15/13 */ public class DBContentProviderSupport implements IDBContentProviderSupport { private static UriMatcher sUriMatcher; private static final int MODELS = 1; private static final int MODELS_ID = 2; private static final int MODELS_ID_NEGOTIVE = 3; private final Context mContext; private final Class<?>[] mEntities; private final IDBSupport mDbSupport; public DBContentProviderSupport(Context context, IDBSupport dbSupport, Class<?> ... entities) { mContext = context; mEntities = entities; mDbSupport = dbSupport; mDbSupport.create(context, entities); initUriMatcher(); } private void initUriMatcher() { if (sUriMatcher == null) { sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); String authority = ModelContract.getAuthority(getContext()); sUriMatcher.addURI(authority, "*", MODELS); sUriMatcher.addURI(authority, "*/#", MODELS_ID); //for negotive number sUriMatcher.addURI(authority, "*/*", MODELS_ID_NEGOTIVE); } } @Override public Class<?>[] getEntities() { return mEntities; } @Override public String getType(Uri uri) { switch (sUriMatcher.match(uri)) { case MODELS: return ModelContract.getContentType(uri.getLastPathSegment()); default: throw new IllegalArgumentException("Unknown URI " + uri); } } @Override public int delete(Uri uri, String where, String[] whereArgs) { return internalDelete(mDbSupport, uri, where, whereArgs); } private int internalDelete(IDBDeleteOperationSupport writeOperationSupport, Uri uri, String where, String[] whereArgs) { List<String> pathSegments = uri.getPathSegments(); String className; switch (sUriMatcher.match(uri)) { case MODELS: className = pathSegments.get(pathSegments.size()-1); break; case MODELS_ID: className = pathSegments.get(pathSegments.size()-2); if (where == null) { where = StringUtil.EMPTY; } where = where + ModelContract.ModelColumns._ID + " = " + uri.getLastPathSegment(); break; case MODELS_ID_NEGOTIVE: className = pathSegments.get(pathSegments.size()-2); if (where == null) { where = StringUtil.EMPTY; } where = where + ModelContract.ModelColumns._ID + " = " + uri.getLastPathSegment(); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } int count = writeOperationSupport.delete(className, where, whereArgs); if (ModelContract.isNotify(uri)) { getContext().getContentResolver().notifyChange(uri, null); } return count; } @Override public Uri insertOrUpdate(Uri uri, ContentValues initialValues) { return internalInsertOrUpdate(mDbSupport, uri, initialValues); } private Uri internalInsertOrUpdate(IDBInsertOrUpdateOperationSupport writeOperationSupport, Uri uri, ContentValues initialValues) { if (sUriMatcher.match(uri) != MODELS) { throw new IllegalArgumentException("Unknown URI " + uri); } String className = uri.getLastPathSegment(); DataSourceRequest dataSourceRequest = ModelContract.getDataSourceRequestFromUri(uri); long rowId = writeOperationSupport.updateOrInsert(dataSourceRequest, className, initialValues); if (rowId != -1l) { Uri serializableModelUri = ContentUris.withAppendedId(uri, rowId); if (ModelContract.isNotify(uri)) { getContext().getContentResolver().notifyChange( serializableModelUri, null); } return serializableModelUri; } else { throw new IllegalArgumentException(uri + ": " + initialValues.toString()); } } @Override public int bulkInsertOrUpdate(Uri uri, ContentValues[] values) { String className = uri.getLastPathSegment(); int count = mDbSupport.updateOrInsert(ModelContract.getDataSourceRequestFromUri(uri), className, values); if (count > 0) { if (ModelContract.isNotify(uri)) { getContext().getContentResolver().notifyChange(uri, null); } } return count; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { String className; List<String> pathSegments; switch (sUriMatcher.match(uri)) { case MODELS: className = uri.getLastPathSegment(); break; case MODELS_ID: pathSegments = uri.getPathSegments(); className = pathSegments.get(pathSegments.size()-2); if (StringUtil.isEmpty(selection)) { selection = ModelContract.ModelColumns._ID + " = " + uri.getLastPathSegment(); } else { selection = selection + ModelContract.ModelColumns._ID + " = " + uri.getLastPathSegment(); } break; case MODELS_ID_NEGOTIVE: pathSegments = uri.getPathSegments(); className = pathSegments.get(pathSegments.size()-2); if (StringUtil.isEmpty(selection)) { selection = ModelContract.ModelColumns._ID + " = " + uri.getLastPathSegment(); } else { selection = selection + ModelContract.ModelColumns._ID + " = " + uri.getLastPathSegment(); } break; default: throw new IllegalArgumentException("Unknown URI " + uri); } if (ModelContract.isSqlUri(className)) { Cursor c = mDbSupport.rawQuery(ModelContract.getSqlParam(uri), selectionArgs); if (c != null) { c.getCount(); c.moveToFirst(); Uri observerUri = ModelContract.getObserverUri(uri); if (observerUri != null) { c.setNotificationUri(getContext().getContentResolver(), observerUri); } } return c; } else { String limitParam = ModelContract.getLimitParam(uri); Cursor c = mDbSupport.query(className, projection, selection, selectionArgs, null, null, sortOrder, limitParam); if (c != null) { c.setNotificationUri(getContext().getContentResolver(), uri); c.getCount(); c.moveToFirst(); } return c; } } @Override public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) throws OperationApplicationException { ContentProviderResult[] result = new ContentProviderResult[operations.size()]; Set<Uri> set = new HashSet<Uri>(); IDBBatchOperationSupport batchOperationConnection = mDbSupport.getConnectionForBatchOperation(); try { batchOperationConnection.beginTransaction(); for(int i = 0; i < operations.size(); i++) { ContentProviderOperation contentProviderOperation = operations.get(i); Uri uri = contentProviderOperation.getUri(); if (ModelContract.isNotify(uri)) { set.add(uri); } result[i] = apply(batchOperationConnection, contentProviderOperation, result, i); } batchOperationConnection.setTransactionSuccessful(); } finally { batchOperationConnection.endTransaction(); } for (Uri uri : set) { getContext().getContentResolver().notifyChange(Uri.parse(uri.toString().split("\\?")[0]), null); } return result; } public ContentProviderResult apply(IDBBatchOperationSupport batchOperationConnection, ContentProviderOperation contentProviderOperation, ContentProviderResult[] backRefs, int numBackRefs) throws OperationApplicationException { ContentValues values = contentProviderOperation.resolveValueBackReferences(backRefs, numBackRefs); String[] selectionArgs = contentProviderOperation.resolveSelectionArgsBackReferences(backRefs, numBackRefs); Uri uri = contentProviderOperation.getUri(); if (values != null) { Uri newUri = internalInsertOrUpdate(batchOperationConnection, uri, values); if (newUri == null) { throw new OperationApplicationException("insert failed"); } return new ContentProviderResult(newUri); } int numRows = internalDelete(batchOperationConnection, uri, selectionArgs == null ? null : "?", selectionArgs); return new ContentProviderResult(numRows); } @Override public Context getContext() { return mContext; } @Override public IDBSupport getDbSupport() { return mDbSupport; } //helper's methods for batch operations public static ContentProviderOperation getDeleteOperation(DataSourceRequest dataSourceRequest, Class<?> clazz) { return getDeleteOperation(dataSourceRequest, clazz, null); } public static ContentProviderOperation getDeleteOperation(DataSourceRequest dataSourceRequest, Class<?> clazz, String selection) { return ContentProviderOperation. newDelete(ModelContract.getUri(dataSourceRequest, clazz)). withSelection("?", selection == null ? null : new String[]{selection}). build(); } public static ArrayList<ContentProviderOperation> getContentProviderOperations(DataSourceRequest dataSourceRequest, Class<?> clazz, ContentValues[] array) { List<ContentValues> list = new ArrayList<ContentValues>(); Collections.addAll(list, array); return getContentProviderOperations(dataSourceRequest, clazz, list); } public static ArrayList<ContentProviderOperation> getContentProviderOperations(DataSourceRequest dataSourceRequest, Class<?> clazz, List<ContentValues> array) { ArrayList<ContentProviderOperation> list = new ArrayList<ContentProviderOperation>(); if (array != null) { for (ContentValues contentValues : array) { Uri uri = ModelContract.getUri(dataSourceRequest, clazz); list.add(ContentProviderOperation.newInsert(uri).withValues(contentValues).build()); } } return list; } }