
org.droitateddb.BaseContentProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of api Show documentation
Show all versions of api Show documentation
droitatedDB is a lightweight framework, which frees you from the burden of dealing with Androids SQLite
database directly if you don't want to
and let's you access it directly if you have to.
/*
* Copyright (C) 2014 The droitated DB Authors
*
* 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 org.droitateddb;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import org.droitateddb.cursor.CombinedCursor;
import org.droitateddb.cursor.CombinedCursorImpl;
import org.droitateddb.entity.Entity;
import org.droitateddb.schema.AbstractAttribute;
import org.droitateddb.schema.EntityInfo;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* The {@link BaseContentProvider} is the base class of all generated {@link ContentProvider} for {@link Entity} classes.
*
* For each {@link Entity} which allows {@link ContentProvider} generation a separate {@link ContentProvider} will be generated. The generated
* {@link ContentProvider} is also referenced in the AndroidManifest.xml to use an own Implementation remove the attribute
* droitateddb:generated="true"
in the provider
element of the AndroidManifest.xml
* The authority of the {@link ContentProvider} is therefore defined within the {@link Entity} annotation.
*
* The base {@link Uri} for calling the {@link ContentProvider} is build following this schema: content://[authority]/[
* {@link BaseContentProvider#getEntityURIPart}].
* If not overridden {@link BaseContentProvider#getEntityURIPart} returns entity
*
* For easier use the {@link BaseContentProvider} provides the methods {@link BaseContentProvider#uri(String)} and
* {@link BaseContentProvider#uriForItem(String, long)}. These methods allow getting the {@link Uri} referencing the Provider with the table name of the
* {@link Entity} and the primary key.
*
* {@link BaseContentProvider#uri(String)}: Returns a {@link Uri} for accessing multiple {@link Entity} elements.
*
* {@link BaseContentProvider#uriForItem(String, long)}: Returns a {@link Uri} for accessing a specific {@link Entity} element
*
* @author Falk Appel
* @author Alexander Frank
*/
public abstract class BaseContentProvider extends ContentProvider {
private static final int MATCH_DIR = 0;
private static final int MATCH_ITEM = 1;
private static final String PROTOCOL = "content://";
private static final UriRegistry REGISTRY = new UriRegistry();
private final String contentUri;
private final String dirContentType;
private final String itemContentType;
private DbCreator dbCreator;
private final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
protected BaseContentProvider() {
String authority = getAuthority();
String base = getEntityURIPart();
String typeDescription = "/vnd." + authority + "." + base;
contentUri = PROTOCOL + authority + "/" + base;
dirContentType = ContentResolver.CURSOR_DIR_BASE_TYPE + typeDescription;
itemContentType = ContentResolver.CURSOR_ITEM_BASE_TYPE + typeDescription;
uriMatcher.addURI(authority, base, MATCH_DIR);
uriMatcher.addURI(authority, base + "/#", MATCH_ITEM);
REGISTRY.add(getTableName(), contentUri);
}
/**
* Returns a {@link Uri} for the using it with a {@link ContentResolver} to access this {@link ContentProvider}. The {@link Uri} allows CRUD operations on
* multiple {@link Entity} elements.
*
* @param tableName Name of the Table (simple {@link Entity} name) the data should be retrieved from.
* @return Uri to access the tables data
*/
public static Uri uri(final String tableName) {
return REGISTRY.getDictionaryUri(tableName);
}
/**
* Returns a {@link Uri} for the using it with a {@link ContentResolver} to access this {@link ContentProvider}. The {@link Uri} allows CRUD operations
* on a
* single {@link Entity} element, qualified by its primary key.
*
* @param tableName Name of the Table (simple {@link Entity} name) the data should be retrieved from.
* @param id Primary key of the {@link Entity} to be accessed
* @return Uri to access the specific item in the table
*/
public static Uri uriForItem(final String tableName, final long id) {
return REGISTRY.getItemUri(tableName, Long.toString(id));
}
/**
* Has to return the authority to be used for this {@link ContentProvider}.
* If generated this is the authority defined in the {@link Entity} class
*
* @return The authority used for the ContentProvider
*/
protected abstract String getAuthority();
/**
* Has to return the attribute describing the primary key of the {@link Entity}.
* Id generated this is the {@link org.droitateddb.entity.PrimaryKey} annotated {@link org.droitateddb.entity.Column}.
*
* @return The description of the primary key of the table access by this ContentProvider
*/
protected abstract AbstractAttribute getIdAttribute();
/**
* Has to return metadata of the {@link Entity} this {@link ContentProvider} is for.
*
* @return Metadata to the {@link Entity} being accessed
*/
protected abstract EntityInfo getEntityInfo();
protected String getEntityURIPart() {
return "entity";
}
private String getTableName() {
return getEntityInfo().table();
}
private String getIdName() {
return getIdAttribute().fieldName();
}
@Override
public boolean onCreate() {
dbCreator = DbCreator.getInstance(getContext());
return true;
}
@Override
public String getType(final Uri uri) {
switch (uriMatcher.match(uri)) {
case MATCH_DIR:
return dirContentType;
case MATCH_ITEM:
return itemContentType;
default:
throw new UnsupportedOperationException("No type for Uri " + uri + " present");
}
}
@Override
public Uri insert(final Uri uri, final ContentValues values) {
return dbCreator.functionOnDatabase(new DbFunction() {
@Override
public Uri apply(SQLiteDatabase db) {
switch (uriMatcher.match(uri)) {
case MATCH_DIR:
long id = db.insertWithOnConflict(getTableName(), null, values, SQLiteDatabase.CONFLICT_REPLACE);
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(contentUri + "/" + id);
default:
throw new UnsupportedOperationException("Insert not allowed with specific note uri");
}
}
});
}
@Override
public Cursor query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder) {
SQLiteDatabase db = dbCreator.getDatabaseConnection();
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
builder.setTables(getTableName());
switch (uriMatcher.match(uri)) {
case MATCH_DIR:
return wrap(builder.query(db, projection, selection, selectionArgs, null, null, sortOrder), uri);
case MATCH_ITEM:
int id = Integer.parseInt(uri.getLastPathSegment());
builder.appendWhere(getIdName() + " = " + id);
return wrap(builder.query(db, projection, selection, selectionArgs, null, null, sortOrder), uri);
default:
throw new UnsupportedOperationException("Unsupported query Uri " + uri);
}
}
@Override
public int update(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs) {
return dbCreator.functionOnDatabase(new DbFunction() {
@Override
public Integer apply(SQLiteDatabase db) {
switch (uriMatcher.match(uri)) {
case MATCH_DIR:
return db.update(getTableName(), values, selection, selectionArgs);
case MATCH_ITEM:
String selectId = getIdName() + " = " + Integer.parseInt(uri.getLastPathSegment());
return db.update(getTableName(), values, getEffectivSelection(selection, selectId), selectionArgs);
default:
throw new UnsupportedOperationException(
"Update not supported for the given Uri + " + uri + ". Only single item updates are allowed right " +
"now");
}
}
});
}
@Override
public int delete(final Uri uri, final String selection, final String[] selectionArgs) {
return dbCreator.functionOnDatabase(new DbFunction() {
@Override
public Integer apply(SQLiteDatabase db) {
switch (uriMatcher.match(uri)) {
case MATCH_DIR:
return db.delete(getTableName(), selection, selectionArgs);
case MATCH_ITEM:
String selectId = getIdName() + " = " + Integer.parseInt(uri.getLastPathSegment());
return db.delete(getTableName(), getEffectivSelection(selection, selectId), selectionArgs);
default:
throw new UnsupportedOperationException(
"Delete not supported for the given Uri + " + uri + ". Only single item deletes are allowed right now");
}
}
});
}
private Cursor wrap(final Cursor cursor, final Uri uri) {
try {
EntityInfo entityInfo = getEntityInfo();
CombinedCursor> magicCursor = CombinedCursorImpl.create(getContext(), cursor, entityInfo, Class.forName(entityInfo.className()));
magicCursor.setNotificationUri(getContext().getContentResolver(), uri);
return magicCursor;
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
private String getEffectivSelection(final String submitedSelection, final String idSelection) {
String effectivSelection;
if (submitedSelection == null || submitedSelection.equals("")) {
effectivSelection = idSelection;
} else {
effectivSelection = submitedSelection + " AND " + idSelection;
}
return effectivSelection;
}
private static class UriRegistry {
private final Map registry = new ConcurrentHashMap();
public void add(final String tableName, final String uri) {
registry.put(tableName, uri);
}
public Uri getDictionaryUri(final String tableName) {
return Uri.parse(getRegisteredUri(tableName));
}
public Uri getItemUri(final String tableName, final String id) {
return Uri.parse(getRegisteredUri(tableName) + "/" + id);
}
private String getRegisteredUri(final String tableName) {
String uri = registry.get(tableName);
if (uri == null) {
throw new IllegalStateException("No ContentProvider Uri was registered for table " + tableName +
". Did you forget to set \"contentProvider=true\" on the corresponding @Entity annotation?");
}
return uri;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy