/* * Copyright 2012 The Stanford MobiSocial Laboratory * * 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 mobisocial.musubi.model.helpers; import mobisocial.musubi.model.MApp; import mobisocial.musubi.model.MFact; import mobisocial.musubi.model.MFactType; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDoneException; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteStatement; public class FactManager extends ManagerBase { final static int MAX_NUM_FIELDS = 4; SQLiteStatement mSqlInsertFT; SQLiteStatement mSqlInsertFact; SQLiteStatement mSqlSelectFact; SQLiteStatement mSqlGetFactType; final int _id = 0; final int appId = 1; final int factTypeId = 2; final int V = 3; final int A = 4; final int B = 5; final int C = 6; final int D = 7; public FactManager(SQLiteOpenHelper databaseSource) { super(databaseSource); } /** * Example usage: * <code> * ensureFact(musubi_id, TYPE_MIME_TYPE, "image/jpeg", "842") * ensureFact(musubi_id, TYPE_EDIT, null, "842", "981") * ensureFact(game_id, TYPE_SCORE, "1199", "intermediate", idFor("bjdodson@mail.com")) * </code> */ public MFact ensureFact(MApp app, MFactType factType, Object value, Object... fields) { if (fields.length > MAX_NUM_FIELDS) { throw new IllegalArgumentException("Too many fields (max=" + MAX_NUM_FIELDS + ")"); } SQLiteDatabase db = initializeDatabase(); // Check existing if (mSqlSelectFact == null) { synchronized(this) { StringBuilder sql = new StringBuilder(100); sql.append("SELECT ").append(MFact.COL_ID).append(" FROM ").append(MFact.TABLE) .append(" WHERE ").append(MFact.COL_APP_ID).append("=?") .append(" AND ").append(MFact.COL_FACT_TYPE_ID).append("=?") .append(" AND ").append(MFact.COL_V).append(" IS ?") .append(" AND ").append(MFact.COL_A).append(" IS ?") .append(" AND ").append(MFact.COL_B).append(" IS ?") .append(" AND ").append(MFact.COL_C).append(" IS ?") .append(" AND ").append(MFact.COL_D).append(" IS ?"); mSqlSelectFact = db.compileStatement(sql.toString()); } } long id; synchronized(mSqlSelectFact) { bindField(mSqlSelectFact, appId, app.id_); bindField(mSqlSelectFact, factTypeId, factType.id_); bindField(mSqlSelectFact, V, value); int i = A; for (Object f : fields) { bindField(mSqlSelectFact, i++, f); } while (i <= D) { bindField(mSqlSelectFact, i++, null); } try { id = mSqlSelectFact.simpleQueryForLong(); } catch (SQLiteDoneException e) { id = -1; } } // Insert new fact MFact fact = new MFact(); fact.id_ = id; fact.appId_ = app.id_; fact.fact_type_id = factType.id_; fact.V_ = value; if (fields.length > 0) { fact.A_ = fields[0]; if (fields.length > 1) { fact.B_ = fields[1]; if (fields.length > 2) { fact.C_ = fields[2]; if (fields.length > 3) { fact.D_ = fields[3]; } } } } if (id == -1) { insertFact(fact); } return fact; } public MFactType ensureFactType(String factType) { SQLiteDatabase db = initializeDatabase(); if(mSqlGetFactType == null) { synchronized(this) { if(mSqlGetFactType == null) { mSqlGetFactType = db.compileStatement( "SELECT " + MFactType.COL_ID + " FROM " + MFactType.TABLE + " WHERE " + MFactType.COL_FACT_TYPE + "=?" ); } } } synchronized (mSqlGetFactType) { try { mSqlGetFactType.bindString(1, factType); long id = mSqlGetFactType.simpleQueryForLong(); MFactType ft = new MFactType(); ft.id_ = id; ft.factType_ = factType; return ft; } catch(SQLiteDoneException e) { //must insert } } MFactType ft = new MFactType(); ft.factType_ = factType; insertFactType(ft); return ft; } void insertFact(MFact fact) { SQLiteDatabase db = initializeDatabase(); if (mSqlInsertFact == null) { synchronized (this) { if(mSqlInsertFact == null) { String sql = new StringBuilder() .append("INSERT INTO ").append(MFact.TABLE).append("(") .append(MFact.COL_APP_ID).append(",") .append(MFact.COL_FACT_TYPE_ID).append(",") .append(MFact.COL_V).append(",") .append(MFact.COL_A).append(",") .append(MFact.COL_B).append(",") .append(MFact.COL_C).append(",") .append(MFact.COL_D) .append(") VALUES (?,?,?,?,?,?,?)").toString(); mSqlInsertFact = db.compileStatement(sql); } } } synchronized (mSqlInsertFact) { mSqlInsertFact.bindLong(appId, fact.appId_); mSqlInsertFact.bindLong(factTypeId, fact.fact_type_id); bindField(mSqlInsertFact, V, fact.V_); bindField(mSqlInsertFact, A, fact.A_); bindField(mSqlInsertFact, B, fact.B_); bindField(mSqlInsertFact, C, fact.C_); bindField(mSqlInsertFact, D, fact.D_); fact.id_ = mSqlInsertFact.executeInsert(); } } void insertFactType(MFactType type) { SQLiteDatabase db = initializeDatabase(); if (mSqlInsertFT == null) { synchronized (this) { if(mSqlInsertFT == null) { String sql = new StringBuilder() .append("INSERT INTO ").append(MFactType.TABLE).append("(") .append(MFactType.COL_FACT_TYPE) .append(") VALUES (?)").toString(); mSqlInsertFT = db.compileStatement(sql); } } } synchronized (mSqlInsertFT) { mSqlInsertFT.bindString(1, type.factType_); type.id_ = mSqlInsertFT.executeInsert(); } } public MFact getFact(long factId) { SQLiteDatabase db = initializeDatabase(); String table = MFact.TABLE; String[] columns = new String[] { MFact.COL_ID, MFact.COL_APP_ID, MFact.COL_FACT_TYPE_ID, MFact.COL_A, typeOf(MFact.COL_A), MFact.COL_B, typeOf(MFact.COL_B), MFact.COL_C, typeOf(MFact.COL_C), MFact.COL_D, typeOf(MFact.COL_D), MFact.COL_V, typeOf(MFact.COL_V)}; String selection = MFact.COL_ID + " = ?"; String[] selectionArgs = new String[] { Long.toString(factId) }; String groupBy = null, having = null, orderBy = null; Cursor c = db.query(table, columns, selection, selectionArgs, groupBy, having, orderBy); try { if (c.moveToFirst()) { MFact fact = new MFact(); fact.id_ = c.getLong(0); fact.appId_ = c.getLong(1); fact.fact_type_id = c.getLong(2); fact.A_ = getFactField(c, 3, 4); fact.B_ = getFactField(c, 5, 6); fact.C_ = getFactField(c, 7, 8); fact.D_ = getFactField(c, 9, 10); fact.V_ = getFactField(c, 11, 12); return fact; } return null; } finally { c.close(); } } public boolean delete(long factId) { SQLiteDatabase db = initializeDatabase(); String table = MFact.TABLE; String whereClause = MFact.COL_ID + " = ?"; String[] whereArgs = new String[] { Long.toString(factId) }; return db.delete(table, whereClause, whereArgs) > 0; } private String typeOf(String col) { return new StringBuilder(col.length() + 8) .append("typeof(").append(col).append(")").toString(); } private Object getFactField(Cursor c, int col, int type) { String typeStr = c.getString(type); if (typeStr.equals("text")) { return c.getString(col); } if (typeStr.equals("integer")) { return c.getInt(col); } if (typeStr.equals("blob")) { return c.getBlob(col); } if (typeStr.equals("real")) { return c.getDouble(col); } return null; } @Override public synchronized void close() { if (mSqlInsertFT != null) { mSqlInsertFT.close(); mSqlInsertFT = null; } if (mSqlInsertFact != null) { mSqlInsertFact.close(); mSqlInsertFact = null; } if (mSqlSelectFact != null) { mSqlSelectFact.close(); mSqlSelectFact = null; } if (mSqlGetFactType != null) { mSqlGetFactType.close(); mSqlGetFactType = null; } } }