com.money.manager.ex.database.MmxOpenHelper.java Source code

Java tutorial

Introduction

Here is the source code for com.money.manager.ex.database.MmxOpenHelper.java

Source

/*
 * Copyright (C) 2012-2016 The Android Money Manager Ex Project Team
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.money.manager.ex.database;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
//import net.sqlcipher.database.SQLiteDatabase;
//import net.sqlcipher.database.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;

import com.money.manager.ex.Constants;
import com.money.manager.ex.R;
import com.money.manager.ex.core.InfoKeys;
import com.money.manager.ex.core.UIHelper;
import com.money.manager.ex.datalayer.CategoryRepository;
import com.money.manager.ex.datalayer.InfoRepositorySql;
import com.money.manager.ex.datalayer.SubcategoryRepository;
import com.money.manager.ex.domainmodel.Category;
import com.money.manager.ex.domainmodel.Info;
import com.money.manager.ex.domainmodel.Subcategory;
import com.money.manager.ex.servicelayer.InfoService;
import com.money.manager.ex.core.Core;
import com.money.manager.ex.currency.CurrencyService;
import com.money.manager.ex.sync.SyncManager;
import com.money.manager.ex.utils.MmxFileUtils;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;

import java.io.File;
import java.io.IOException;
import java.util.Currency;

import timber.log.Timber;

/**
 * Actual helper class for accessing an SQLite database.
 */
public class MmxOpenHelper extends SQLiteOpenHelper {

    /**
     * Database schema version.
     */
    private static final int databaseVersion = 7;

    // Dynamic

    /**
     * Constructor. This is where the database path gets set.
     * @param context Current context.
     */
    public MmxOpenHelper(Context context, String dbPath) {
        super(context, dbPath, null, databaseVersion);
        this.mContext = context;

    }

    private Context mContext;
    private String mPassword = "";

    public Context getContext() {
        return this.mContext;
    }

    //    @Override
    //    public void onConfigure(SQLiteDatabase db) {
    //        super.onConfigure(db);
    //        db.rawQuery("PRAGMA journal_mode=OFF", null).close();
    //    }

    /**
     * Called when the database is being created.
     * @param db Database instance.
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        Timber.d("OpenHelper onCreate");

        try {
            executeRawSql(db, R.raw.tables_v1);
            initDatabase(db);
        } catch (Exception e) {
            Timber.e(e, "initializing database");
        }
    }

    @Override
    public void onOpen(SQLiteDatabase db) {
        super.onOpen(db);

        //        int version = db.getVersion();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Timber.d("Upgrading from %1$d  to %2$d", oldVersion, newVersion);

        try {
            String currentDbFile = db.getPath();
            createDatabaseBackupOnUpgrade(currentDbFile, oldVersion);
        } catch (Exception ex) {
            Timber.e(ex, "creating database backup, can't continue");

            // don't upgrade
            return;
        }

        // update databases
        updateDatabase(db, oldVersion, newVersion);

        // notify sync about the db update.
        new SyncManager(getContext()).dataChanged();
    }

    @Override
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // nothing to do for now.
        Timber.d("Downgrade attempt from %1$d to %2$d", oldVersion, newVersion);
    }

    //    @Override
    //    public synchronized void close() {
    //        super.close();
    //
    //        mInstance = null;
    //    }

    @Override
    public SQLiteDatabase getReadableDatabase() {
        SQLiteDatabase db = null;
        try {
            db = super.getReadableDatabase();
        } catch (Exception ex) {
            Timber.e(ex, "opening readable database");
        }
        return db;
    }

    //    public SQLiteDatabase getReadableDatabase() {
    //        return this.getReadableDatabase(this.mPassword);
    //    }
    //    @Override
    //    public SQLiteDatabase getReadableDatabase(String password) {
    //        SQLiteDatabase db = null;
    //        try {
    //            db = super.getReadableDatabase(password);
    //        } catch (Exception ex) {
    //            Timber.e(ex, "opening readable database");
    //        }
    //        return db;
    //    }

    @Override
    public SQLiteDatabase getWritableDatabase() {
        try {
            //return getWritableDatabase_Internal();
            return super.getWritableDatabase();
        } catch (Exception ex) {
            Timber.e(ex, "opening writable database");
        }
        return null;
    }

    //    public SQLiteDatabase getWritableDatabase() {
    //        return getWritableDatabase(this.mPassword);
    //    }
    //    @Override
    //    public SQLiteDatabase getWritableDatabase(String password) {
    //        try {
    //            return getWritableDatabase_Internal(password);
    //        } catch (Exception ex) {
    //            Timber.e(ex, "opening writable database");
    //        }
    //        return null;
    //    }

    public void setPassword(String password) {
        this.mPassword = password;
    }

    //    public boolean hasPassword() {
    //        return !TextUtils.isEmpty(this.mPassword);
    //    }

    //    private SQLiteDatabase getWritableDatabase_Internal() {
    //        // String password
    ////
    ////        SQLiteDatabase db = super.getWritableDatabase(password);
    //        SQLiteDatabase db = super.getWritableDatabase();
    //
    //        if (db != null) {
    //            db.rawQuery("PRAGMA journal_mode=OFF", null).close();
    //        }
    //
    //        return db;
    //    }

    /**
     * @param db    SQLite database to execute raw SQL
     * @param rawId id raw resource
     */
    private void executeRawSql(SQLiteDatabase db, int rawId) {
        String sqlRaw = MmxFileUtils.getRawAsString(getContext(), rawId);
        String sqlStatement[] = sqlRaw.split(";");

        // process all statements
        for (String aSqlStatment : sqlStatement) {
            Timber.d(aSqlStatment);

            try {
                db.execSQL(aSqlStatment);
            } catch (Exception e) {
                String errorMessage = e.getMessage();
                if (e instanceof SQLiteException && errorMessage != null
                        && errorMessage.contains("not an error (code 0)")) {
                    Timber.w(errorMessage);
                } else {
                    Timber.e(e, "executing raw sql: %s", aSqlStatment);
                }
            }
        }
    }

    /**
     * Get SQLite Version installed
     * @return version of SQLite
     */
    public String getSQLiteVersion() {
        String sqliteVersion = null;
        Cursor cursor = null;
        try {
            if (getReadableDatabase() != null) {
                cursor = getReadableDatabase().rawQuery("select sqlite_version() AS sqlite_version", null);
                if (cursor != null && cursor.moveToFirst()) {
                    sqliteVersion = cursor.getString(0);
                }
            }
        } catch (Exception e) {
            Timber.e(e, "getting sqlite version");
        } finally {
            if (cursor != null)
                cursor.close();
            //            if (database != null) database.close();
        }
        return sqliteVersion;
    }

    private void updateDatabase(SQLiteDatabase db, int oldVersion, int newVersion) {
        // Execute every script between the old and the new version of the database schema.
        for (int i = oldVersion + 1; i <= newVersion; i++) {
            int resourceId = mContext.getResources().getIdentifier("database_version_" + Integer.toString(i), "raw",
                    mContext.getPackageName());
            if (resourceId > 0) {
                executeRawSql(db, resourceId);
            }
        }
    }

    private boolean initDatabase(SQLiteDatabase database) {
        try {
            initBaseCurrency(database);
        } catch (Exception e) {
            Timber.e(e, "init database, base currency");
        }

        initDateFormat(database);
        initCategories(database);

        return true;
    }

    private void initCategories(SQLiteDatabase database) {
        try {
            Cursor countCategories = database.rawQuery("SELECT * FROM CATEGORY_V1", null);
            if (countCategories == null || countCategories.getCount() > 0)
                return;

            int keyCategory = 0;
            String[] categories = new String[] { "1;1", "2;1", "3;1", "4;1", "5;1", "6;1", "7;1", "8;2", "9;2",
                    "10;3", "11;3", "12;3", "13;4", "14;4", "15;4", "16;4", "17;5", "18;5", "19;5", "20;6", "21;6",
                    "22;6", "23;7", "24;7", "25;7", "26;7", "27;7", "28;8", "29;8", "30;8", "31;8", "32;9", "33;9",
                    "34;9", "35;10", "36;10", "37;10", "38;10", "39;13", "40;13", "41;13" };

            for (String item : categories) {
                int subCategoryId = Integer.parseInt(item.substring(0, item.indexOf(";")));
                int categoryId = Integer.parseInt(item.substring(item.indexOf(";") + 1));

                if (categoryId != keyCategory) {
                    keyCategory = categoryId;
                    int idStringCategory = mContext.getResources().getIdentifier(
                            "category_" + Integer.toString(categoryId), "string", mContext.getPackageName());

                    if (idStringCategory > 0) {
                        ContentValues contentValues = new ContentValues();
                        contentValues.put(Category.CATEGID, categoryId);
                        contentValues.put(Category.CATEGNAME, mContext.getString(idStringCategory));

                        // Update existing records, inserted via the db creation script.
                        int updated = database.update(CategoryRepository.tableName, contentValues,
                                Category.CATEGID + "=?", new String[] { Integer.toString(categoryId) });
                        if (updated <= 0) {
                            Timber.w("updating %s for category %s", contentValues.toString(),
                                    Integer.toString(categoryId));
                        }
                    }
                }

                int idStringSubcategory = mContext.getResources().getIdentifier(
                        "subcategory_" + Integer.toString(subCategoryId), "string", mContext.getPackageName());
                if (idStringSubcategory > 0) {
                    ContentValues contentValues = new ContentValues();
                    contentValues.put(Subcategory.SUBCATEGID, subCategoryId);
                    contentValues.put(Subcategory.CATEGID, categoryId);
                    contentValues.put(Subcategory.SUBCATEGNAME, mContext.getString(idStringSubcategory));

                    int updated = database.update(SubcategoryRepository.tableName, contentValues,
                            Subcategory.SUBCATEGID + "=?", new String[] { Integer.toString(subCategoryId) });
                    if (updated <= 0) {
                        Timber.w("update failed, %s for subcategory %s", contentValues.toString(),
                                Integer.toString(subCategoryId));
                    }
                }
            }

            countCategories.close();
        } catch (Exception e) {
            Timber.e(e, "init database, categories");
        }
    }

    /**
     * The creation of the record is done in tables_v1.sql initialization script.
     * Here we only update the record to the current system's date format.
     * @param database Database being initialized.
     */
    private void initDateFormat(SQLiteDatabase database) {
        try {
            Core core = new Core(getContext());
            String pattern = core.getDefaultSystemDateFormat();
            if (pattern == null)
                return;

            InfoService infoService = new InfoService(getContext());
            infoService.updateRaw(database, InfoKeys.DATEFORMAT, pattern);
        } catch (Exception e) {
            Timber.e(e, "init database, date format");
        }
    }

    private void initBaseCurrency(SQLiteDatabase db) {
        // currencies
        CurrencyService currencyService = new CurrencyService(getContext());
        Currency systemCurrency = currencyService.getSystemDefaultCurrency();
        if (systemCurrency == null)
            return;

        InfoService infoService = new InfoService(getContext());

        // todo: try query generator.
        //        String sql = new Select()
        //                .select()
        //                .from(InfoRepositorySql.TABLE_NAME)
        //                .where(Info.INFONAME + "=?", InfoKeys.BASECURRENCYID)
        //                .toString();

        Cursor currencyCursor = db.rawQuery(
                "SELECT * FROM " + InfoRepositorySql.TABLE_NAME + " WHERE " + Info.INFONAME + "=?",
                new String[] { InfoKeys.BASECURRENCYID });
        if (currencyCursor == null)
            return;

        // Get id of the base currency record.
        int recordId = Constants.NOT_SET;
        boolean recordExists = currencyCursor.moveToFirst();
        if (recordExists) {
            recordId = currencyCursor.getInt(currencyCursor.getColumnIndex(Info.INFOID));
        }
        currencyCursor.close();

        // Use the system default currency.
        int currencyId = currencyService.loadCurrencyIdFromSymbolRaw(db, systemCurrency.getCurrencyCode());
        if (currencyId == Constants.NOT_SET) {
            // Use Euro by default.
            currencyId = 2;
        }

        UIHelper uiHelper = new UIHelper(getContext());

        // Insert/update base currency record into info table.
        if (!recordExists) {
            long newId = infoService.insertRaw(db, InfoKeys.BASECURRENCYID, currencyId);
            if (newId <= 0) {
                uiHelper.showToast("error inserting base currency on init");
            }
        } else {
            // Update the (by default empty) record to the default currency.
            long updatedRecords = infoService.updateRaw(db, recordId, InfoKeys.BASECURRENCYID, currencyId);
            if (updatedRecords <= 0) {
                uiHelper.showToast("error updating base currency on init");
            }
        }

        // Can't use provider here as the database is not ready.
        //            int currencyId = currencyService.loadCurrencyIdFromSymbol(systemCurrency.getCurrencyCode());
        //            String baseCurrencyId = infoService.getInfoValue(InfoService.BASECURRENCYID);
        //            if (!StringUtils.isEmpty(baseCurrencyId)) return;
        //            infoService.setInfoValue(InfoService.BASECURRENCYID, Integer.toString(currencyId));
    }

    @Override
    public void finalize() throws Throwable {
        super.finalize();
    }

    public void createDatabaseBackupOnUpgrade(String currentDbFile, int oldVersion) throws IOException {
        File in = new File(currentDbFile);
        String backupFileNameWithExtension = in.getName();

        String backupName = FilenameUtils.getBaseName(backupFileNameWithExtension);
        String backupExtension = FilenameUtils.getExtension(backupFileNameWithExtension);

        // append last db version
        backupName += "_v" + Integer.toString(oldVersion);

        backupFileNameWithExtension = backupName + "." + backupExtension;

        String outPath = FilenameUtils.getFullPath(currentDbFile) + backupFileNameWithExtension;
        File out = new File(outPath);

        FileUtils.copyFile(in, out);
    }
}