package org.ebookdroid.common.settings.books; import org.ebookdroid.common.settings.BackupSettings; import org.ebookdroid.common.settings.SettingsManager; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import org.emdev.common.backup.BackupManager; import org.emdev.common.backup.IBackupAgent; import org.emdev.common.log.LogContext; import org.emdev.common.log.LogManager; import org.emdev.utils.LengthUtils; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; public class DBSettingsManager extends SQLiteOpenHelper implements IBackupAgent { private static final LogContext LCTX = LogManager.root().lctx("DBSettingsManager"); public static final String BACKUP_KEY = "recent-books"; public static final int DB_VERSION = DBAdapterV9.VERSION; private final IDBAdapter adapter; private SQLiteDatabase upgragingInstance; private SQLiteDatabase m_db; public DBSettingsManager(final Context context) { this(context, context.getPackageName() + ".settings"); } DBSettingsManager(final Context context, String fileName) { this(context, fileName, DB_VERSION); } /** * Used in DBSettingsManagerTest * * @param context * @param fileName */ DBSettingsManager(final Context context, String fileName, int version) { super(context, fileName, null, version); adapter = createAdapter(version); try { m_db = getWritableDatabase(); } catch (final Exception ex) { LCTX.e("Unexpected DB error: ", ex); } BackupManager.addAgent(this); } public void close() { if (m_db != null) { try { m_db.close(); } catch (Exception ex) { } m_db = null; } } @Override public void onCreate(final SQLiteDatabase db) { adapter.onCreate(db); } protected IDBAdapter createAdapter(final int version) { switch (version) { case DBAdapterV1.VERSION: return new DBAdapterV1(this); case DBAdapterV2.VERSION: return new DBAdapterV2(this); case DBAdapterV3.VERSION: return new DBAdapterV3(this); case DBAdapterV4.VERSION: return new DBAdapterV4(this); case DBAdapterV5.VERSION: return new DBAdapterV5(this); case DBAdapterV6.VERSION: return new DBAdapterV6(this); case DBAdapterV7.VERSION: return new DBAdapterV7(this); case DBAdapterV8.VERSION: return new DBAdapterV8(this); case DBAdapterV9.VERSION: default: return new DBAdapterV9(this); } } @Override public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { upgragingInstance = db; LCTX.i("Upgrading from version " + oldVersion + " to version " + newVersion); try { final IDBAdapter oldAdapter = createAdapter(oldVersion); final IDBAdapter newAdapter = createAdapter(newVersion); switchAdapter(db, oldAdapter, newAdapter); } finally { upgragingInstance = null; LCTX.i("Upgrade finished"); } } @Override public void onDowngrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { upgragingInstance = db; LCTX.i("Downgrading from version " + oldVersion + " to version " + newVersion); try { final IDBAdapter oldAdapter = createAdapter(oldVersion); final IDBAdapter newAdapter = createAdapter(newVersion); switchAdapter(db, newAdapter, oldAdapter); } finally { upgragingInstance = null; LCTX.i("Downgrade finished"); } } public void switchAdapter(final SQLiteDatabase db, final IDBAdapter oldAdapter, final IDBAdapter newAdapter) { final Map<String, BookSettings> bookSettings = oldAdapter.getAllBooks(); oldAdapter.deleteAll(); oldAdapter.onDestroy(db); newAdapter.onCreate(db); newAdapter.restoreBookSettings(bookSettings.values()); } /** * {@inheritDoc} * * @see android.database.sqlite.SQLiteOpenHelper#getWritableDatabase() */ @Override public synchronized SQLiteDatabase getWritableDatabase() { if (upgragingInstance != null) { return upgragingInstance; } if (m_db != null && m_db.isOpen()) { return m_db; } LCTX.d("New DB connection created: " + m_db); m_db = super.getWritableDatabase(); return m_db; } /** * {@inheritDoc} * * @see android.database.sqlite.SQLiteOpenHelper#getReadableDatabase() */ @Override public synchronized SQLiteDatabase getReadableDatabase() { if (upgragingInstance != null) { return upgragingInstance; } if (m_db != null && m_db.isOpen()) { return m_db; } return super.getReadableDatabase(); } synchronized void closeDatabase(final SQLiteDatabase db) { if (db != upgragingInstance && db != m_db) { try { db.close(); } catch (final Exception ex) { } LCTX.d("DB connection closed: " + m_db); } } public Map<String, BookSettings> getAllBooks() { return adapter.getAllBooks(); } public Map<String, BookSettings> getRecentBooks(final boolean all) { return adapter.getRecentBooks(all); } public BookSettings getBookSettings(final String fileName) { return adapter.getBookSettings(fileName); } public boolean storeBookSettings(final BookSettings bs) { return bs.persistent ? adapter.storeBookSettings(Collections.singletonList(bs)) : false; } public boolean storeBookSettings(final List<BookSettings> list) { return adapter.storeBookSettings(list); } public boolean restoreBookSettings(Collection<BookSettings> c) { return adapter.restoreBookSettings(c); } public boolean clearRecent() { return adapter.clearRecent(); } public boolean removeBookFromRecents(final BookSettings bs) { return adapter.removeBookFromRecents(bs); } public void delete(final BookSettings current) { adapter.delete(current); } public boolean deleteAll() { return adapter.deleteAll(); } public boolean deleteAllBookmarks() { return adapter.deleteAllBookmarks(); } @Override public String key() { return BACKUP_KEY; } @Override public JSONObject backup() { final BookBackupType backupType = BackupSettings.current().bookBackup; final JSONObject root = new JSONObject(); if (backupType == BookBackupType.NONE) { return root; } try { final JSONArray books = new JSONArray(); root.put("books", books); final Map<String, BookSettings> m = backupType == BookBackupType.RECENT ? getRecentBooks(true) : getAllBooks(); for (final BookSettings bs : m.values()) { final JSONObject obj = bs.toJSON(); books.put(obj); } } catch (final JSONException ex) { SettingsManager.LCTX.e("Error on recent book backup: " + ex.getMessage()); } return root; } @Override public void restore(final JSONObject backup) { try { final List<BookSettings> list = new ArrayList<BookSettings>(); final JSONArray books = backup.getJSONArray("books"); if (LengthUtils.isNotEmpty(books)) { for (int i = 0, n = books.length(); i < n; i++) { final JSONObject obj = books.getJSONObject(i); list.add(new BookSettings(obj)); } } if (deleteAll()) { restoreBookSettings(list); } SettingsManager.onRecentBooksChanged(); } catch (final JSONException ex) { SettingsManager.LCTX.e("Error on recent book restoring: " + ex.getMessage()); } } }