Android Open Source - NexusData Android Sql Persistent Store






From Project

Back to project page NexusData.

License

The source code is released under:

Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCT...

If you think the Android project NexusData listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.github.dkharrat.nexusdata.store;
/*from   w w w.j  a  v  a2  s . c o m*/
import java.io.File;
import java.net.URL;
import java.text.ParseException;
import java.util.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.github.dkharrat.nexusdata.core.*;
import com.github.dkharrat.nexusdata.metamodel.*;
import com.github.dkharrat.nexusdata.utils.android.CursorUtil;
import com.github.dkharrat.nexusdata.utils.DateUtil;

/* TODO: AndroidSqlPersistentStore changes
 *  - improve memory-management
 *  - code clean-up (see todo's in code below)
 */

public class AndroidSqlPersistentStore extends IncrementalStore {

    private static final Logger LOG = LoggerFactory.getLogger(AndroidSqlPersistentStore.class);

    static final String COLUMN_ID_NAME = "_ID";

    private DatabaseHelper databaseHelper;
    private Map<String,Long> lastRowIDs = new HashMap<String,Long>();
    private Context context;

    private SQLiteDatabase db;

    // TODO: use a MRU cache and also remove objects if they are unregistered from all contexts
    private Map<Class<?>, Map<Long,StoreCacheNode>> cache = new HashMap<Class<?>, Map<Long,StoreCacheNode>>();

    public AndroidSqlPersistentStore(Context context, URL path) {
        super(path);
        this.context = context;
    }

    public AndroidSqlPersistentStore(Context context, File location) {
        super(location);
        this.context = context;
    }

    @Override
    protected void loadMetadata() {
        ObjectModel model = getCoordinator().getModel();
        databaseHelper = new DatabaseHelper(context, new File(getLocation().getPath()), model);

        // TODO: does the DB need to be closed at some point?
        db = databaseHelper.getWritableDatabase();

        setUuid(DatabaseHelper.getDatabaseUuid(db, model.getVersion()));
    }

    static protected String getColumnName(Property property) {
        return "`" + property.getName() + "`";
    }

    private ManagedObject createObjectFromCursor(ObjectContext context, Entity<?> entity, Cursor cursor) {

        long id = CursorUtil.getLong(cursor, COLUMN_ID_NAME);
        ObjectID objectID = this.createObjectID(entity, id);
        ManagedObject object = context.objectWithID(objectID);

        StoreCacheNode cacheNode = getStoreNodeFromCursor(objectID, cursor, context);
        Map<Long,StoreCacheNode> entityCache = cache.get(entity.getType());
        if (entityCache == null) {
            entityCache = new HashMap<Long,StoreCacheNode>();
            cache.put(entity.getType(), entityCache);
        }
        entityCache.put(id, cacheNode);

        return object;
    }

    @Override
    protected <T extends ManagedObject> List<T> executeFetchRequest(FetchRequest<T> request, ObjectContext context) {
        Cursor cursor = DatabaseQueryService.query(db, this, DatabaseHelper.getTableName(request.getEntity()), request);

        List<T> results = new ArrayList<T>();
        while(cursor.moveToNext()) {
            @SuppressWarnings("unchecked")
            T object = (T)createObjectFromCursor(context, request.getEntity(), cursor);
            results.add(object);
        }

        cursor.close();

        return results;
    }

    private ContentValues getContentValues(ManagedObject object) throws IllegalArgumentException, IllegalAccessException {
        ContentValues values = new ContentValues();

        values.put(COLUMN_ID_NAME, getReferenceObjectForObjectID(object.getID()).toString());
        for (Property property : object.getEntity().getProperties()) {
            Class<?> propertyType = property.getType();
            Object value = object.getValue(property.getName());

            if (property.isRelationship()) {
                Relationship relationship = (Relationship)property;
                if (relationship.isToOne()) {
                    ManagedObject toOneObject = (ManagedObject) value;
                    if (toOneObject != null) {
                        values.put(getColumnName(relationship), getReferenceObjectForObjectID(toOneObject.getID()).toString());
                    } else {
                        values.putNull(getColumnName(relationship));
                    }
                }
            } else {
                if (value != null) {
                    if (Date.class.isAssignableFrom(propertyType)) {
                        values.put(getColumnName(property), DateUtil.format(DateUtil.ISO8601_NO_TIMEZONE, (Date)value));
                    } else if (Boolean.class.isAssignableFrom(propertyType)) {
                        values.put(getColumnName(property), ((Boolean)value) ? "1" : "0" );
                    } else {
                        values.put(getColumnName(property), value.toString());
                    }
                } else {
                    values.putNull(getColumnName(property));
                }
            }
        }

        return values;
    }

    @Override
    protected void executeSaveRequest(SaveChangesRequest request, ObjectContext context) {
        db.beginTransaction();
        try {
            for (ManagedObject object : request.getChanges().getInsertedObjects()) {
                ContentValues values = getContentValues(object);
                //TODO: log inserts, updates & deletes
                db.insertOrThrow(DatabaseHelper.getTableName(object.getEntity()), null, values);
            }

            for (ManagedObject object : request.getChanges().getUpdatedObjects()) {
                ContentValues values = getContentValues(object);
                long id = (Long)getReferenceObjectForObjectID(object.getID());
                db.update(DatabaseHelper.getTableName(object.getEntity()), values, "_ID = " + id, null);

                Map<Long, StoreCacheNode> entityCache = cache.get(object.getEntity().getType());
                if (entityCache != null) {
                    //TODO: update cache entry instead of deleting it
                    entityCache.remove(id);
                }
            }

            for (ManagedObject object : request.getChanges().getDeletedObjects()) {
                long id = (Long)getReferenceObjectForObjectID(object.getID());
                db.delete(DatabaseHelper.getTableName(object.getEntity()), "_ID = " + id, null);

                Map<Long, StoreCacheNode> entityCache = cache.get(object.getEntity().getType());
                if (entityCache != null) {
                    entityCache.remove(id);
                }
            }

            db.setTransactionSuccessful();
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } finally {
            db.endTransaction();
        }
    }

    private StoreCacheNode getStoreNodeFromCursor(ObjectID objectID, Cursor cursor, ObjectContext context) {
        StoreCacheNode node = new StoreCacheNode(objectID);

        try {
            for (Property property : objectID.getEntity().getProperties()) {
                Object value;
                @SuppressWarnings("unchecked")
                Class<?> propType = property.getType();

                if (property.isRelationship()) {
                    Relationship relationship = (Relationship)property;
                    if (relationship.isToOne()) {
                        @SuppressWarnings("unchecked")
                        Entity<?> assocEntity = getCoordinator().getModel().getEntity((Class<ManagedObject>)relationship.getType());
                        long relatedID = CursorUtil.getLong(cursor, relationship.getName());
                        if (relatedID != 0) {
                            value = this.createObjectID(assocEntity, relatedID);
                        } else {
                            continue;
                        }
                    } else {
                        continue;
                    }
                } else if (CursorUtil.isNull(cursor, property.getName())) {
                    value = null;
                } else if (propType.isAssignableFrom(Integer.class) || propType.isAssignableFrom(int.class)) {
                    value = CursorUtil.getInt(cursor, property.getName());
                } else if (propType.isAssignableFrom(Long.class) || propType.isAssignableFrom(long.class)) {
                    value = CursorUtil.getLong(cursor, property.getName());
                } else if (propType.isAssignableFrom(String.class)) {
                    value = CursorUtil.getString(cursor, property.getName());
                } else if (propType.isAssignableFrom(Boolean.class) || propType.isAssignableFrom(boolean.class)) {
                    value = CursorUtil.getBoolean(cursor, property.getName());
                } else if (propType.isAssignableFrom(Float.class) || propType.isAssignableFrom(float.class)) {
                    value = CursorUtil.getFloat(cursor, property.getName());
                } else if (propType.isAssignableFrom(Double.class) || propType.isAssignableFrom(double.class)) {
                    value = CursorUtil.getDouble(cursor, property.getName());
                } else if (Enum.class.isAssignableFrom(propType)) {
                    String enumName = CursorUtil.getString(cursor, property.getName());
                    if (enumName != null) {
                        value = Enum.valueOf((Class<? extends Enum>)propType, enumName);
                    } else {
                        value = null;
                    }
                } else if (propType.isAssignableFrom(Date.class)) {
                    String dateStr = CursorUtil.getString(cursor, property.getName());
                    if (dateStr != null) {
                        value = DateUtil.parse(DateUtil.ISO8601_NO_TIMEZONE, dateStr);
                    } else {
                        value = null;
                    }
                } else {
                    throw new UnsupportedOperationException("Unsupported property type " + property.getType());
                }

                node.setProperty(property.getName(), value);
            }
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

        return node;
    }

    @Override
    protected StoreCacheNode getObjectValues(ObjectID objectID, ObjectContext context) {

        long id = Long.valueOf(getReferenceObjectForObjectID(objectID).toString());

        Map<Long,StoreCacheNode> entityCache = cache.get(objectID.getEntity().getType());
        if (entityCache != null) {
            StoreCacheNode node = entityCache.get(id);
            if (node != null) {
                return node;
            }
        }

        Cursor cursor = db.query(
                false,          // not distinct
                DatabaseHelper.getTableName(objectID.getEntity()),
                null,           // columns
                COLUMN_ID_NAME + "=?",           // selection
                new String[]{String.valueOf(id)},           // selectionArgs
                null,           // groupBy
                null,           // having
                null,           // orderBy
                null);          // limit

        StoreCacheNode node = null;
        if (cursor.moveToNext()) {
            node = getStoreNodeFromCursor(objectID, cursor, context);
        }
        cursor.close();

        if (entityCache == null) {
            entityCache = new HashMap<Long,StoreCacheNode>();
            cache.put(objectID.getEntity().getType(), entityCache);
        }
        entityCache.put(id, node);

        return node;
    }

    @Override
    protected Set<ObjectID> getToManyRelationshipValue(
            ObjectID objectID,
            Relationship relationship,
            ObjectContext context) {

        String[] columns = new String[]{COLUMN_ID_NAME};
        String table = DatabaseHelper.getTableName(relationship.getDestinationEntity());
        String selection = relationship.getInverse().getName()+"=?";
        String[] selectionArgs = new String[]{getReferenceObjectForObjectID(objectID).toString()};

        Cursor cursor = db.query(
                false,          // not distinct
                table,
                columns,        // columns
                selection,      // selection
                selectionArgs,  // selectionArgs
                null,           // groupBy
                null,           // having
                null,           // orderBy
                null);          // limit


        Set<ObjectID> results = new HashSet<ObjectID>();
        while(cursor.moveToNext()) {
            long id = CursorUtil.getLong(cursor, COLUMN_ID_NAME);
            ObjectID relatedObject = this.createObjectID(relationship.getDestinationEntity(), id);
            results.add(relatedObject);
        }
        cursor.close();

        return results;
    }

    @Override
    protected ObjectID getToOneRelationshipValue(
            ObjectID objectID,
            Relationship relationship,
            ObjectContext context) {

        String fromTable = DatabaseHelper.getTableName(objectID.getEntity());
        String toTable = DatabaseHelper.getTableName(relationship.getDestinationEntity());

        String table = fromTable + " t1," + toTable + " t2";
        String[] columns = new String[]{"t1" + "." + COLUMN_ID_NAME};
        String selection = "t1"+"."+COLUMN_ID_NAME+"="+getReferenceObjectForObjectID(objectID) + " AND " +
                           "t1"+"."+getColumnName(relationship)+"=t2."+COLUMN_ID_NAME;

        Cursor cursor = db.query(
                false,          // not distinct
                table,
                columns,           // columns
                selection,     // selection
                null,           // selectionArgs
                null,           // groupBy
                null,           // having
                null,           // orderBy
                null);          // limit


        ObjectID relatedObjectID = null;
        if(cursor.moveToNext()) {
            long id = CursorUtil.getLong(cursor, COLUMN_ID_NAME);
            relatedObjectID = this.createObjectID(relationship.getDestinationEntity(), id);
        }
        cursor.close();

        return relatedObjectID;
    }

    private long getLastRowIDFromDatabase(SQLiteDatabase db, String tableName) {
        long lastRow = 1;
        Cursor cursor = db.query(
                false,          // not distinct
                "sqlite_sequence",
                null,           // columns
                "name='" + tableName + "'",           // selection
                null,           // selectionArgs
                null,           // groupBy
                null,           // having
                null,           // orderBy
                "1");           // limit

        if (cursor.moveToNext()) {
            lastRow = CursorUtil.getLong(cursor, "seq")+1;
        }
        cursor.close();

        return lastRow;
    }

    @Override
    protected List<ObjectID> getPermanentIDsForObjects(List<ManagedObject> objects) {

        List<ObjectID> objectIDs = new ArrayList<ObjectID>();
        for (ManagedObject object : objects) {
            ObjectID id;

            String tableName = DatabaseHelper.getTableName(object.getEntity());
            Long lastRowID = lastRowIDs.get(tableName);
            if (lastRowID == null) {
                lastRowID = getLastRowIDFromDatabase(db, tableName);
            }
            id = createObjectID(object.getEntity(), lastRowID++);
            lastRowIDs.put(DatabaseHelper.getTableName(object.getEntity()), lastRowID);

            objectIDs.add(id);
        }

        return objectIDs;
    }
}




Java Source Code List

com.github.dkharrat.nexusdata.core.AtomicStore.java
com.github.dkharrat.nexusdata.core.ChangedObjectsSet.java
com.github.dkharrat.nexusdata.core.FaultingSet.java
com.github.dkharrat.nexusdata.core.FetchRequest.java
com.github.dkharrat.nexusdata.core.IncrementalStore.java
com.github.dkharrat.nexusdata.core.ManagedObject.java
com.github.dkharrat.nexusdata.core.NoSuchPropertyException.java
com.github.dkharrat.nexusdata.core.ObjectContextNotifier.java
com.github.dkharrat.nexusdata.core.ObjectContext.java
com.github.dkharrat.nexusdata.core.ObjectID.java
com.github.dkharrat.nexusdata.core.ObjectsChangedNotification.java
com.github.dkharrat.nexusdata.core.PersistentStoreCoordinator.java
com.github.dkharrat.nexusdata.core.PersistentStoreRequest.java
com.github.dkharrat.nexusdata.core.PersistentStore.java
com.github.dkharrat.nexusdata.core.SaveChangesRequest.java
com.github.dkharrat.nexusdata.core.SortDescriptor.java
com.github.dkharrat.nexusdata.core.StoreCacheNode.java
com.github.dkharrat.nexusdata.metamodel.Attribute.java
com.github.dkharrat.nexusdata.metamodel.Entity.java
com.github.dkharrat.nexusdata.metamodel.ObjectModelJsonParser.java
com.github.dkharrat.nexusdata.metamodel.ObjectModel.java
com.github.dkharrat.nexusdata.metamodel.Property.java
com.github.dkharrat.nexusdata.metamodel.Relationship.java
com.github.dkharrat.nexusdata.modelgen.ModelGenerator.java
com.github.dkharrat.nexusdata.modelgen.Startup.java
com.github.dkharrat.nexusdata.modelgen.metamodel.Attribute.java
com.github.dkharrat.nexusdata.modelgen.metamodel.Entity.java
com.github.dkharrat.nexusdata.modelgen.metamodel.EnumProperty.java
com.github.dkharrat.nexusdata.modelgen.metamodel.ModelWrapper.java
com.github.dkharrat.nexusdata.modelgen.metamodel.Model.java
com.github.dkharrat.nexusdata.modelgen.metamodel.Property.java
com.github.dkharrat.nexusdata.modelgen.metamodel.Relationship.java
com.github.dkharrat.nexusdata.predicate.ComparisonPredicate.java
com.github.dkharrat.nexusdata.predicate.CompoundPredicate.java
com.github.dkharrat.nexusdata.predicate.ConstantExpression.java
com.github.dkharrat.nexusdata.predicate.ExpressionBuilder.java
com.github.dkharrat.nexusdata.predicate.ExpressionVisitor.java
com.github.dkharrat.nexusdata.predicate.Expression.java
com.github.dkharrat.nexusdata.predicate.FieldPathExpression.java
com.github.dkharrat.nexusdata.predicate.NotPredicate.java
com.github.dkharrat.nexusdata.predicate.PredicateBuilder.java
com.github.dkharrat.nexusdata.predicate.Predicate.java
com.github.dkharrat.nexusdata.predicate.ThisExpression.java
com.github.dkharrat.nexusdata.predicate.parser.ComparisonParselet.java
com.github.dkharrat.nexusdata.predicate.parser.ConstantParselet.java
com.github.dkharrat.nexusdata.predicate.parser.ExpressionNode.java
com.github.dkharrat.nexusdata.predicate.parser.GroupParselet.java
com.github.dkharrat.nexusdata.predicate.parser.InfixParselet.java
com.github.dkharrat.nexusdata.predicate.parser.LexerGrammar.java
com.github.dkharrat.nexusdata.predicate.parser.Lexer.java
com.github.dkharrat.nexusdata.predicate.parser.LogicalParselet.java
com.github.dkharrat.nexusdata.predicate.parser.NameParselet.java
com.github.dkharrat.nexusdata.predicate.parser.ParseException.java
com.github.dkharrat.nexusdata.predicate.parser.Parser.java
com.github.dkharrat.nexusdata.predicate.parser.PredicateParser.java
com.github.dkharrat.nexusdata.predicate.parser.PrefixParselet.java
com.github.dkharrat.nexusdata.predicate.parser.Token.java
com.github.dkharrat.nexusdata.store.AndroidSqlPersistentStore.java
com.github.dkharrat.nexusdata.store.DatabaseHelper.java
com.github.dkharrat.nexusdata.store.InMemoryPersistentStore.java
com.github.dkharrat.nexusdata.store.PredicateToSQL.java
com.github.dkharrat.nexusdata.utils.DateUtil.java
com.github.dkharrat.nexusdata.utils.ObjectUtil.java
com.github.dkharrat.nexusdata.utils.SqlTableBuilder.java
com.github.dkharrat.nexusdata.utils.StreamUtil.java
com.github.dkharrat.nexusdata.utils.StringUtil.java
com.github.dkharrat.nexusdata.utils.android.CursorUtil.java
com.github.dkharrat.nexusdata.utils.android.SQLiteDatabaseHelper.java
org.example.todo.MainActivity.java
org.example.todo.NewTaskActivity.java
org.example.todo.Task.java
org.example.todo.TodoApp.java
org.example.todo.User.java
org.example.todo._Task.java
org.example.todo._User.java