/* DBCacheController.java Copyright (c) 2014 NTT DOCOMO,INC. Released under the MIT license http://opensource.org/licenses/mit-license.php */ package org.deviceconnect.android.event.cache.db; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteOpenHelper; import org.deviceconnect.android.event.Event; import org.deviceconnect.android.event.EventError; import org.deviceconnect.android.event.cache.BaseCacheController; import org.deviceconnect.android.event.cache.db.ClientDao.Client; import org.deviceconnect.android.event.cache.db.EventSessionDao.EventSession; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; /** * イベントデータをデータベースに保存し、キャッシュの操作機能を提供する. * * * @author NTT DOCOMO, INC. */ public final class DBCacheController extends BaseCacheController { /** * コンテキストオブジェクト. */ private Context mContext; /** * ロガー. */ private Logger mLogger = Logger.getLogger("org.deviceconnect.dplugin"); /** * DBヘルパー. */ private EventDBOpenHelper mHelper; /** * 指定されたコンテキストでDBCacheControllerのインスタンスを生成する. * * @param context コンテキストオブジェクト */ public DBCacheController(final Context context) { if (context == null) { throw new IllegalArgumentException("Context is null."); } mContext = context; mHelper = new EventDBOpenHelper(mContext); } /** * dbをオープンする. * * @return データベースオブジェクト */ private SQLiteDatabase openDB() { // 安全性と利便性を取り、毎回open、closeすることとする。 SQLiteDatabase db; try { db = mHelper.getWritableDatabase(); } catch (SQLiteException e) { db = null; } return db; } @Override public synchronized EventError addEvent(final Event event) { if (!checkParameter(event)) { return EventError.INVALID_PARAMETER; } EventError result = EventError.FAILED; SQLiteDatabase db = openDB(); if (db == null) { return EventError.FAILED; } do { db.beginTransaction(); long pId = ProfileDao.insert(db, event.getProfile()); if (pId < 0) { break; } long iId = InterfaceDao.insert(db, event.getInterface(), pId); if (iId < 0) { break; } long aId = AttributeDao.insert(db, event.getAttribute(), iId); if (aId < 0) { break; } long dId = DeviceDao.insert(db, event.getServiceId()); if (dId < 0) { break; } long edId = EventDeviceDao.insert(db, aId, dId); if (edId < 0) { break; } long cId = ClientDao.insert(db, event); if (cId < 0) { break; } long esId = EventSessionDao.insert(db, edId, cId); if (esId < 0) { break; } result = EventError.NONE; db.setTransactionSuccessful(); } while (false); db.endTransaction(); db.close(); return result; } @Override public synchronized EventError removeEvent(final Event event) { if (!checkParameter(event)) { return EventError.INVALID_PARAMETER; } SQLiteDatabase db = openDB(); if (db == null) { return EventError.FAILED; } db.beginTransaction(); EventError error = EventSessionDao.delete(db, event); if (error == EventError.NONE || error == EventError.NOT_FOUND) { db.setTransactionSuccessful(); } db.endTransaction(); db.close(); return error; } @Override public synchronized boolean removeAll() { SQLiteDatabase db = openDB(); if (db == null) { return false; } boolean result; db.beginTransaction(); try { db.delete(EventDeviceSchema.TABLE_NAME, null, null); db.delete(AttributeSchema.TABLE_NAME, null, null); db.delete(InterfaceSchema.TABLE_NAME, null, null); db.delete(ProfileSchema.TABLE_NAME, null, null); db.delete(ClientSchema.TABLE_NAME, null, null); db.delete(DeviceSchema.TABLE_NAME, null, null); db.setTransactionSuccessful(); result = true; } catch (SQLiteException e) { // 失敗したらロールバックで巻き返す。 mLogger.severe("DBCacheController#removeAll(). Failed to remove all. " + e.getMessage()); result = false; } db.endTransaction(); db.close(); return result; } @Override public synchronized Event getEvent(final String serviceId, final String profile, final String inter, final String attribute, final String origin, final String receiver) { Event result = null; SQLiteDatabase db = null; do { db = openDB(); if (db == null) { break; } Event search = new Event(); search.setServiceId(serviceId); search.setProfile(profile); search.setInterface(inter); search.setAttribute(attribute); search.setOrigin(origin); search.setReceiverName(receiver); // checkParameterエラー回避用データの設定 search.setAccessToken("dummy"); if (!checkParameter(search)) { break; } EventSession data = EventSessionDao.get(db, search); if (data == null) { break; } Client client = ClientDao.getById(db, data.mCId); if (client == null) { break; } search.setAccessToken(client.mAccessToken); search.setCreateDate(data.mCreateDate); search.setUpdateDate(data.mUpdateDate); result = search; } while (false); if (db != null) { db.close(); } return result; } @Override public synchronized List<Event> getEvents(final String serviceId, final String profile, final String inter, final String attribute) { List<Event> result = new ArrayList<Event>(); SQLiteDatabase db = null; do { db = openDB(); if (db == null) { break; } Event search = new Event(); search.setServiceId(serviceId); search.setProfile(profile); search.setInterface(inter); search.setAttribute(attribute); // checkParameterエラー回避用データの設定 search.setOrigin("dummy"); search.setAccessToken("dummy"); search.setReceiverName("dummy"); if (!checkParameter(search)) { break; } Client[] clients = ClientDao.getByAPIAndServiceId(db, search); if (clients == null) { break; } for (Client client : clients) { Event event = new Event(); event.setServiceId(serviceId); event.setProfile(profile); event.setInterface(inter); event.setAttribute(attribute); event.setOrigin(client.mOrigin); event.setAccessToken(client.mAccessToken); event.setReceiverName(client.mReceiver); event.setCreateDate(client.mESCreateDate); event.setUpdateDate(client.mESUpdateDate); result.add(event); } } while (false); if (db != null) { db.close(); } return result; } @Override public List<Event> getEvents(final String origin) { if (origin == null) { throw new IllegalArgumentException("origin key is null."); } List<Event> result = new ArrayList<Event>(); SQLiteDatabase db; do { db = openDB(); if (db == null) { break; } Client[] clients = ClientDao.getByOrigin(db, origin); if (clients == null) { break; } for (Client client : clients) { List<Event> events = EventSessionDao.getEventsByCid(db, client.mId); for (Event event : events) { event.setOrigin(client.mOrigin); event.setAccessToken(client.mAccessToken); event.setReceiverName(client.mReceiver); event.setCreateDate(client.mESCreateDate); event.setUpdateDate(client.mESUpdateDate); result.add(event); } } } while (false); if (db != null) { db.close(); } return result; } @Override public void flush() { // do-nothing. } @Override public synchronized boolean removeEvents(final String origin) { if (origin == null) { throw new IllegalArgumentException("origin key is null."); } boolean result = false; SQLiteDatabase db = null; do { db = openDB(); if (db == null) { break; } db.beginTransaction(); Client[] clients = ClientDao.getByOrigin(db, origin); if (clients == null) { break; } else if (clients.length == 0) { result = true; break; } String[] ids = new String[clients.length]; int i = 0; for (Client client : clients) { ids[i++] = "" + client.mId; } EventError error = EventSessionDao.delete(db, ids); if (error == EventError.FAILED || error == EventError.INVALID_PARAMETER) { break; } db.setTransactionSuccessful(); result = true; } while (false); if (db != null) { db.endTransaction(); db.close(); } return result; } /** * DBオープンヘルパー. * * @author NTT DOCOMO, INC. * */ private class EventDBOpenHelper extends SQLiteOpenHelper { /** * DBファイル名. */ private static final String DB_NAME = "__device_connect_event.db"; /** * バージョン番号. */ private static final int DB_VERSION = 3; /** * DBオープンヘルパーを生成する. * * @param context コンテキストオブジェクト */ public EventDBOpenHelper(final Context context) { super(context, DB_NAME, null, DB_VERSION); } @Override public void onCreate(final SQLiteDatabase db) { createAllTables(db); } @Override public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { // バージョンが上がった場合はDBを初期化する。 db.execSQL(ProfileSchema.DROP); db.execSQL(InterfaceSchema.DROP); db.execSQL(AttributeSchema.DROP); db.execSQL(ClientSchema.DROP); db.execSQL(DeviceSchema.DROP); db.execSQL(EventDeviceSchema.DROP); db.execSQL(EventSessionSchema.DROP); createAllTables(db); } /** * 必要なテーブルをすべて作成する. * @param db データベース */ private void createAllTables(final SQLiteDatabase db) { // 外部キーの設定は設けていないので、リレーションは手動でしっかり管理すること。 // DBが作れないと使えないので、例外は処理しない db.execSQL(ProfileSchema.CREATE); db.execSQL(InterfaceSchema.CREATE); db.execSQL(AttributeSchema.CREATE); db.execSQL(ClientSchema.CREATE); db.execSQL(DeviceSchema.CREATE); db.execSQL(EventDeviceSchema.CREATE); db.execSQL(EventSessionSchema.CREATE); } } }