/*
* Copyright 2010 Christian Matzat and others
*
* 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 net.matzat.android.hiberdroid;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import net.matzat.android.hiberdroid.exception.MappingNotFoundException;
import net.matzat.android.hiberdroid.exception.PropertyAccessException;
import net.matzat.android.hiberdroid.mapping.ColumnMapping;
import net.matzat.android.hiberdroid.mapping.EntityMapping;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* HiberDroidManager class manages the database connection to the SQLite database.
*/
public class HiberDroidManager {
private final static String TAG = HiberDroidManager.class.getSimpleName();
private final static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
private HiberDroidOpenHelper dbo = null;
private static HiberDroidManager instance = null;
private HiberDroidManager() {
// do not allow direct instantiation
}
/**
* returns a SQLiteDatabase instance to perform read/write operations on the database.
*
* @return SQLiteDatabase instance
*/
private SQLiteDatabase getWritableDatabaseConnection() {
if (!isInitialized()) {
throw new IllegalStateException("Database ist not initialized.");
}
return dbo.getWritableDatabase();
}
/**
* returns a SQLiteDatabase instance to perform only read operations on the database.
*
* @return SQLiteDatabase instance
*/
private SQLiteDatabase getDatabaseConnection() {
if (!isInitialized()) {
throw new IllegalStateException("Database ist not initialized.");
}
return dbo.getReadableDatabase();
}
/**
* get an instance of the HiberDroidManager. This instance is created only once and then shared.
*
* @return DBManager instance
*/
public static synchronized HiberDroidManager getInstance() {
if (instance == null) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Creating new HiberDroidManager.");
}
instance = new HiberDroidManager();
}
return instance;
}
/**
* Initializes the database mapping.
*
* @param context the Android context of the app
* @param dbName the database name
* @param dbVersion the database version
* @param mappingClasses full qualified class names of the mapping classes as Strings (vararg)
*/
public void initialize(Context context, String dbName, int dbVersion, String... mappingClasses) {
if (dbo == null) {
try {
Configuration.createInstance(mappingClasses);
dbo = new HiberDroidOpenHelper(context, dbName, dbVersion);
} catch (ClassNotFoundException e) {
Log.e(TAG, "Mapping Class not found", e);
throw new MappingNotFoundException("Mapping class not found.");
} catch (InstantiationException e) {
Log.e(TAG, "Configuration was already configured", e);
throw new MappingNotFoundException("Duplicate initialization call.");
}
}
}
/**
* destroys the database connection and the mapping configuration
*/
public void destroy() {
dbo.close();
dbo = null;
Configuration.destroy();
}
/**
* check if database mapping in initialized and a database connection object is available.
*
* @return true if successfully initialized
*/
public boolean isInitialized() {
return dbo != null;
}
/**
* gets a Cursor for a database query.
*
* @param table the database table
* @param columns an array of column names
* @param selection the where clause
* @param selectionArgs the parameters for the selection arguments
* @param group the group clause
* @param having the having clause
* @param order the order clause
* @return Cursor
*/
public Cursor getCursor(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String group, String having, String order, String limit) {
return getDatabaseConnection().query(distinct, table, columns, selection, selectionArgs, group, having, order, limit);
}
/**
* saves a mapped entity object to the database. checks if the entity is new and performs an insert or update if
* object is updated. requires an id column set for the entity to delete.
*
* @param entity
*/
public void save(Object entity) {
try {
EntityMapping entityMapping = Configuration.findEntityMappingByClass(entity.getClass());
if (entityMapping.getIdProperty() == null) {
throw new MappingNotFoundException("cannot save without id column.");
}
boolean insert = true;
String idValue = "";
ContentValues contentValues = new ContentValues(entityMapping.getColumns().size());
for (String property : entityMapping.getColumns().keySet()) {
Field field = entity.getClass().getDeclaredField(property);
field.setAccessible(true);
ColumnMapping columnMapping = entityMapping.getColumns().get(property);
Object value = null;
if (field.get(entity) != null) {
value = field.get(entity);
}
if (columnMapping.isId()) {
idValue = value.toString();
if (idValue != null && !idValue.equals("0")) {
insert = false;
}
} else {
switch (columnMapping.getColumnType()) {
case DATE:
value = value != null && value instanceof Date ? DATE_FORMAT.format(value) : null;
contentValues.put(columnMapping.getColumn(), value != null && value instanceof String ? (String) value : null);
break;
case STRING:
contentValues.put(columnMapping.getColumn(), value != null && value instanceof String ? (String) value : null);
break;
case BYTE:
contentValues.put(columnMapping.getColumn(), value != null && value instanceof Byte ? (Byte) value : null);
break;
case SHORT:
contentValues.put(columnMapping.getColumn(), value != null && value instanceof Short ? (Short) value : null);
break;
case INTEGER:
contentValues.put(columnMapping.getColumn(), value != null && value instanceof Integer ? (Integer) value : null);
break;
case LONG:
contentValues.put(columnMapping.getColumn(), value != null && value instanceof Long ? (Long) value : null);
break;
case DOUBLE:
contentValues.put(columnMapping.getColumn(), value != null && value instanceof Double ? (Double) value : null);
break;
case FLOAT:
contentValues.put(columnMapping.getColumn(), value != null && value instanceof Float ? (Float) value : null);
break;
case BLOB:
contentValues.put(columnMapping.getColumn(), value != null && value instanceof byte[] ? (byte[]) value : null);
break;
case BOOLEAN:
if (value != null && value instanceof Boolean) {
value = (Boolean) value ? new Integer(1) : new Integer(0);
}
contentValues.put(columnMapping.getColumn(), value != null && value instanceof Integer ? (Integer) value : null);
break;
}
}
}
if (insert) {
Long newIdValue = getWritableDatabaseConnection().insert(entityMapping.getTable(), null, contentValues);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, String.format("entity with id %s was inserted", newIdValue.toString()));
}
} else {
getWritableDatabaseConnection().update(entityMapping.getTable(), contentValues, entityMapping.getIdColumn() + "=?", new String[]{idValue});
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, String.format("entity with id %s was updated", idValue));
}
}
} catch (NoSuchFieldException e) {
throw new PropertyAccessException("property access failed.");
} catch (IllegalAccessException e) {
throw new PropertyAccessException("property access failed.");
}
}
/**
* deletes a mapped entity from the database. requires an id column set for the entity to delete.
*
* @param entity the entity object to delete
*/
public void delete(Object entity) {
EntityMapping entityMapping = Configuration.findEntityMappingByClass(entity.getClass());
if (entityMapping.getIdProperty() == null) {
throw new MappingNotFoundException("cannot delete without id column.");
}
try {
Field field = entity.getClass().getDeclaredField(entityMapping.getIdProperty());
field.setAccessible(true);
Long value = null;
if (field.get(entity) != null) {
value = (Long) field.get(entity);
}
delete(entity.getClass(), value);
} catch (NoSuchFieldException e) {
throw new PropertyAccessException("property access failed.");
} catch (IllegalAccessException e) {
throw new PropertyAccessException("property access failed.");
}
}
/**
* deletes a mapped entity with the given id from the database. requires an id column set for the entity to delete.
*
* @param entityClass the entity class
* @param entityId the entity id to delete
*/
public void delete(Class entityClass, Long entityId) {
EntityMapping entityMapping = Configuration.findEntityMappingByClass(entityClass);
if (entityMapping.getIdProperty() == null) {
throw new MappingNotFoundException("cannot delete without id column.");
}
if (entityId != null) {
getWritableDatabaseConnection().delete(entityMapping.getTable(), entityMapping.getIdColumn() + "=?", new String[]{entityId.toString()});
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, String.format("entity with id %s was deleted", entityId.toString()));
}
}
}
}
|