xiaofei.library.datastorage.database.DbService.java Source code

Java tutorial

Introduction

Here is the source code for xiaofei.library.datastorage.database.DbService.java

Source

/**
 *
 * Copyright 2015-2016 Xiaofei
 *
 * 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 xiaofei.library.datastorage.database;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.v4.util.Pair;

import java.util.LinkedList;
import java.util.List;

import xiaofei.library.datastorage.annotation.AnnotationProcessor;
import xiaofei.library.datastorage.util.Condition;

/**
 * Created by Xiaofei on 15/11/12.
 *
 * DbService performs database operations. It is not thread-safe.
 *
 */
public class DbService implements IDbOperation {

    private Coder mCoder = null;

    private static final String EQUAL = "` = '";

    private static DbService sInstance;

    private DbOpenHelper mDatabaseHelper;

    private AnnotationProcessor mAnnotationProcessor;

    private SQLiteDatabase mDb = null;

    private DbService(Context context) {
        mDatabaseHelper = new DbOpenHelper(context);
        //The following statement may throw an exception.
        mDb = mDatabaseHelper.getWritableDatabase();
        mCoder = new GsonObjectCoder();
        mAnnotationProcessor = AnnotationProcessor.getInstance();
    }

    static synchronized DbService getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new DbService(context);
        }
        return sInstance;
    }

    void setCoder(Coder coder) {
        mCoder = coder;
    }

    private static String generateEquation(String leftValue, String rightValue) {
        return "`" + leftValue + EQUAL + rightValue + "'";
    }

    private <T> String generateReplaceValue(T object, String id) {
        return "('" + mAnnotationProcessor.getClassId(object.getClass()) + "', '" + id + "', '"
                + mCoder.encode(object) + "')";
    }

    /**
     * ??
     */
    public void close() {
        mDb.close();
    }

    @Override
    public <T> boolean containsObject(Class<T> clazz, String objectId) {
        Cursor c = mDb.query(DbConst.TABLE_NAME, null,
                generateEquation(DbConst.CLASS_ID, mAnnotationProcessor.getClassId(clazz)) + " and "
                        + generateEquation(DbConst.OBJECT_ID, objectId),
                null, null, null, null, null);
        boolean result = c.getCount() != 0;
        c.close();
        return result;
    }

    @Override
    public <T> void insertObject(T object, String objectId) {
        String command = DbConst.REPLACE_COMMAND + generateReplaceValue(object, objectId) + ";";
        mDb.execSQL(command);
    }

    @Override
    public <T> void insertObjects(final List<T> objects, final List<String> objectIds) {
        if (objects.isEmpty()) {
            return;
        }
        executeInTransaction(new Runnable() {
            @Override
            public void run() {
                // To avoid the extremely long sql command, we insert objects one by one, instead of
                // insert all of them by a long sql command.
                // This is not the best practice. Future work should make this better.
                int size = objects.size();
                for (int i = 0; i < size; ++i) {
                    T object = objects.get(i);
                    String id = objectIds.get(i);
                    insertObject(object, id);
                }
            }
        });
    }

    @Override
    public <T> List<Pair<String, T>> getAllObjects(Class<T> clazz) {
        List<Pair<String, T>> list = new LinkedList<Pair<String, T>>();
        Cursor cursor = mDb.query(DbConst.TABLE_NAME, null,
                generateEquation(DbConst.CLASS_ID, mAnnotationProcessor.getClassId(clazz)), null, null, null, null);
        while (cursor.moveToNext()) {
            String data = cursor.getString(cursor.getColumnIndex(DbConst.OBJECT_DATA));
            String id = cursor.getString(cursor.getColumnIndex(DbConst.OBJECT_ID));
            T object = null;
            try {
                object = mCoder.decode(data, clazz);
            } catch (RuntimeException e) {
                e.printStackTrace();
            }
            if (object != null) {
                list.add(new Pair<String, T>(id, object));
            }
        }
        cursor.close();
        return list;
    }

    @Override
    public <T> T getObject(Class<T> clazz, String objectIds) {
        T result = null;
        Cursor cursor = mDb.query(DbConst.TABLE_NAME, null,
                generateEquation(DbConst.CLASS_ID, mAnnotationProcessor.getClassId(clazz)) + " and "
                        + generateEquation(DbConst.OBJECT_ID, objectIds),
                null, null, null, null);
        if (cursor.moveToNext()) {
            String data = cursor.getString(cursor.getColumnIndex(DbConst.OBJECT_DATA));
            try {
                result = mCoder.decode(data, clazz);
            } catch (RuntimeException e) {
                e.printStackTrace();
            }
        }
        cursor.close();
        return result;
    }

    @Override
    public <T> List<Pair<String, T>> getObjects(Class<T> clazz, Condition<T> condition) {
        List<Pair<String, T>> result = new LinkedList<Pair<String, T>>();
        Cursor cursor = mDb.query(DbConst.TABLE_NAME, null,
                generateEquation(DbConst.CLASS_ID, mAnnotationProcessor.getClassId(clazz)), null, null, null, null);
        while (cursor.moveToNext()) {
            String data = cursor.getString(cursor.getColumnIndex(DbConst.OBJECT_DATA));
            T object = null;
            try {
                object = mCoder.decode(data, clazz);
            } catch (RuntimeException e) {
                e.printStackTrace();
            }
            if (object == null) {
                continue;
            }
            if (condition == null || condition != null && condition.satisfy(object)) {
                String id = cursor.getString(cursor.getColumnIndex(DbConst.OBJECT_ID));
                result.add(new Pair<String, T>(id, object));
            }
        }
        return result;
    }

    @Override
    public <T> void replaceObjects(final Class<T> clazz, final List<String> oldObjectIds, final List<T> newObjects,
            final List<String> newObjectIds) {
        executeInTransaction(new Runnable() {
            @Override
            public void run() {
                deleteObjects(clazz, oldObjectIds);
                insertObjects(newObjects, newObjectIds);
            }
        });
    }

    @Override
    public void clearTable() {
        mDb.delete(DbConst.TABLE_NAME, null, null);
    }

    @Override
    public <T> void deleteObject(Class<T> clazz, String objectId) {
        String whereClause = generateEquation(DbConst.CLASS_ID, mAnnotationProcessor.getClassId(clazz)) + " and "
                + generateEquation(DbConst.OBJECT_ID, objectId);
        mDb.delete(DbConst.TABLE_NAME, whereClause, null);
    }

    @Override
    public <T> void deleteObjects(Class<T> clazz, List<String> objectIds) {
        if (objectIds.isEmpty()) {
            return;
        }
        StringBuilder whereClause = new StringBuilder(
                generateEquation(DbConst.CLASS_ID, mAnnotationProcessor.getClassId(clazz)) + " and `"
                        + DbConst.OBJECT_ID + "` in ('" + objectIds.get(0) + "'");
        int size = objectIds.size();
        for (int i = 1; i < size; ++i) {
            whereClause.append(" ,'").append(objectIds.get(i)).append("'");
        }
        whereClause.append(")");
        mDb.delete(DbConst.TABLE_NAME, whereClause.toString(), null);
    }

    @Override
    public <T> void deleteAllObjects(Class<T> clazz) {
        String whereClause = generateEquation(DbConst.CLASS_ID, mAnnotationProcessor.getClassId(clazz));
        mDb.delete(DbConst.TABLE_NAME, whereClause, null);
    }

    public void executeInTransaction(Runnable runnable) {
        if (runnable == null) {
            throw new IllegalArgumentException();
        }
        try {
            mDb.beginTransaction();
            try {
                runnable.run();
                mDb.setTransactionSuccessful();
            } finally {
                mDb.endTransaction();
            }
        } catch (RuntimeException e) {
            e.printStackTrace();
        }
    }

    public interface Coder {
        String encode(Object object);

        <T> T decode(String string, Class<T> clazz);
    }
}