/* * 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 gnu.trove.list.linked.TLongLinkedList; import mobisocial.musubi.model.MEncodedMessage; import mobisocial.musubi.model.MObject; import mobisocial.musubi.model.MPendingUpload; import mobisocial.musubi.util.Util; 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 EncodedMessageManager extends ManagerBase { SQLiteStatement sqlInsertEncoded_; SQLiteStatement sqlUpdateEncoded_; SQLiteStatement mSqlGetEncodedIdByHash; SQLiteStatement mSqlGetFeedIdForEncoded; String mSqlGetMetadataById; String mSqlObjectsToDecode; String mSqlGetEncodedDataById; public EncodedMessageManager(SQLiteOpenHelper databaseSource) { super(databaseSource); } public EncodedMessageManager(SQLiteDatabase db) { super(db); } public void insertEncoded(MEncodedMessage encoded) { SQLiteDatabase db = initializeDatabase(); if(sqlInsertEncoded_ == null) { synchronized (this) { if(sqlInsertEncoded_ == null) { sqlInsertEncoded_ = db.compileStatement( "INSERT INTO " + MEncodedMessage.TABLE + " (" + MEncodedMessage.COL_DEVICE_ID + "," + MEncodedMessage.COL_HASH + "," + MEncodedMessage.COL_OUTBOUND + "," + MEncodedMessage.COL_PROCESSED + "," + MEncodedMessage.COL_SENDER + "," + MEncodedMessage.COL_ENCODED + "," + MEncodedMessage.COL_SHORT_HASH + "," + MEncodedMessage.COL_PROCESSED_TIME + ") " + "VALUES (?,?,?,?,?,?,?,?)" ); } } } synchronized (sqlInsertEncoded_) { if(encoded.fromDevice_ == null) { sqlInsertEncoded_.bindNull(1); } else { sqlInsertEncoded_.bindLong(1, encoded.fromDevice_); } if(encoded.hash_ == null) { sqlInsertEncoded_.bindNull(2); } else { sqlInsertEncoded_.bindBlob(2, encoded.hash_); } sqlInsertEncoded_.bindLong(3, encoded.outbound_ ? 1 : 0); sqlInsertEncoded_.bindLong(4, encoded.processed_ ? 1 : 0); if(encoded.fromIdentityId_ == null) { sqlInsertEncoded_.bindNull(5); } else { sqlInsertEncoded_.bindLong(5, encoded.fromIdentityId_); } sqlInsertEncoded_.bindBlob(6, encoded.encoded_); if(encoded.shortHash_ == null) { sqlInsertEncoded_.bindNull(7); } else { sqlInsertEncoded_.bindLong(7, encoded.shortHash_); } sqlInsertEncoded_.bindLong(8, encoded.processedTime_); encoded.id_ = sqlInsertEncoded_.executeInsert(); } } public void updateEncodedMetadata(MEncodedMessage encoded) { SQLiteDatabase db = initializeDatabase(); if(sqlUpdateEncoded_ == null) { synchronized (this) { if(sqlUpdateEncoded_ == null) { sqlUpdateEncoded_ = db.compileStatement( "UPDATE " + MEncodedMessage.TABLE + " SET " + MEncodedMessage.COL_DEVICE_ID + "=?," + MEncodedMessage.COL_HASH + "=?," + MEncodedMessage.COL_OUTBOUND + "=?," + MEncodedMessage.COL_PROCESSED + "=?," + MEncodedMessage.COL_SENDER + "=?," + MEncodedMessage.COL_SHORT_HASH + "=?, " + MEncodedMessage.COL_PROCESSED_TIME + "=? " + " WHERE " + MEncodedMessage.COL_ID + "=? " ); } } } synchronized (sqlUpdateEncoded_) { if(encoded.fromDevice_ == null) { sqlUpdateEncoded_.bindNull(1); } else { sqlUpdateEncoded_.bindLong(1, encoded.fromDevice_); } if(encoded.hash_ == null) { sqlUpdateEncoded_.bindNull(2); } else { sqlUpdateEncoded_.bindBlob(2, encoded.hash_); } sqlUpdateEncoded_.bindLong(3, encoded.outbound_ ? 1 : 0); sqlUpdateEncoded_.bindLong(4, encoded.processed_ ? 1 : 0); if(encoded.fromIdentityId_ == null) { sqlUpdateEncoded_.bindNull(5); } else { sqlUpdateEncoded_.bindLong(5, encoded.fromIdentityId_); } if(encoded.shortHash_ == null) { sqlUpdateEncoded_.bindNull(6); } else { sqlUpdateEncoded_.bindLong(6, encoded.shortHash_); } sqlUpdateEncoded_.bindLong(7, encoded.processedTime_); sqlUpdateEncoded_.bindLong(8, encoded.id_); sqlUpdateEncoded_.execute(); } } public byte[] lookupEncodedDataById(long id) { if (mSqlGetEncodedDataById == null) { StringBuilder sql = new StringBuilder(80); sql.append("SELECT ").append(MEncodedMessage.COL_ENCODED) .append(" FROM ").append(MEncodedMessage.TABLE) .append(" WHERE ").append(MEncodedMessage.COL_ID).append("=?"); mSqlGetEncodedDataById = sql.toString(); } SQLiteDatabase db = initializeDatabase(); Cursor c = db.rawQuery(mSqlGetEncodedDataById, new String[] { Long.toString(id) }); try { if (c.moveToFirst()) { return c.getBlob(0); } return null; } finally { c.close(); } } public MEncodedMessage lookupById(long id) { SQLiteDatabase db = initializeDatabase(); String table = MEncodedMessage.TABLE; String[] columns = new String[] { MEncodedMessage.COL_SENDER, MEncodedMessage.COL_ENCODED, MEncodedMessage.COL_DEVICE_ID, MEncodedMessage.COL_SHORT_HASH, MEncodedMessage.COL_HASH, MEncodedMessage.COL_OUTBOUND, MEncodedMessage.COL_PROCESSED, MEncodedMessage.COL_PROCESSED_TIME, }; String selection = MEncodedMessage.COL_ID + " = ?"; String[] selectionArgs = new String[] { Long.toString(id) }; String groupBy = null, having = null, orderBy = null; Cursor c = db.query(table, columns, selection, selectionArgs, groupBy, having, orderBy); if (!c.moveToFirst()) { return null; } MEncodedMessage encoded = new MEncodedMessage(); encoded.id_ = id; encoded.fromIdentityId_ = c.isNull(0) ? null : c.getLong(0); encoded.encoded_ = c.getBlob(1); encoded.fromDevice_ = c.isNull(2) ? null : c.getLong(2); encoded.shortHash_ = c.isNull(3) ? null : c.getLong(3); encoded.hash_ = c.getBlob(4); encoded.outbound_ = c.getInt(5) != 0; encoded.processed_ = c.getInt(6) != 0; encoded.processedTime_ = c.getLong(7); try { return encoded; } finally { c.close(); } } public MEncodedMessage lookupMetadataById(long id) { SQLiteDatabase db = initializeDatabase(); if (mSqlGetMetadataById == null) { StringBuilder sql = new StringBuilder(100) .append("SELECT ") .append(MEncodedMessage.COL_SENDER).append(",") .append(MEncodedMessage.COL_DEVICE_ID).append(",") .append(MEncodedMessage.COL_SHORT_HASH).append(",") .append(MEncodedMessage.COL_HASH).append(",") .append(MEncodedMessage.COL_OUTBOUND).append(",") .append(MEncodedMessage.COL_PROCESSED).append(",") .append(MEncodedMessage.COL_PROCESSED_TIME); sql.append(" FROM ").append(MEncodedMessage.TABLE) .append(" WHERE ").append(MEncodedMessage.COL_ID).append("=?"); mSqlGetMetadataById = sql.toString(); } String[] selectionArgs = new String[] { Long.toString(id) }; Cursor c = db.rawQuery(mSqlGetMetadataById, selectionArgs); if (!c.moveToFirst()) { return null; } MEncodedMessage encoded = new MEncodedMessage(); encoded.id_ = id; encoded.fromIdentityId_ = c.isNull(0) ? null : c.getLong(0); encoded.fromDevice_ = c.isNull(1) ? null : c.getLong(1); encoded.shortHash_ = c.isNull(2) ? null : c.getLong(2); encoded.hash_ = c.getBlob(3); encoded.outbound_ = c.getInt(4) != 0; encoded.processed_ = c.getInt(5) != 0; encoded.processedTime_ = c.getLong(6); try { return encoded; } finally { c.close(); } } public boolean delete(long id) { SQLiteDatabase db = initializeDatabase(); String whereClause = MEncodedMessage.COL_ID + " = ?"; String[] whereArgs = new String[] { Long.toString(id) }; return db.delete(MEncodedMessage.TABLE, whereClause, whereArgs) > 0; } /** * Returns the encoded message ids that are ready to be sent-- * they are outbound, have been encoded, and are not pending uploads. */ public TLongLinkedList getUnsentOutboundIdsNotPending() { SQLiteDatabase db = initializeDatabase(); StringBuilder pendingUploads = new StringBuilder(50) .append("SELECT ").append(MObject.COL_ENCODED_ID) .append(" FROM ").append(MObject.TABLE).append(",").append(MPendingUpload.TABLE) .append(" WHERE ").append(MObject.TABLE).append(".").append(MObject.COL_ID) .append("=").append(MPendingUpload.TABLE).append(".").append(MPendingUpload.COL_OBJECT_ID); StringBuilder selection = new StringBuilder(100) .append(MEncodedMessage.COL_PROCESSED).append("=0 AND ") .append(MEncodedMessage.COL_OUTBOUND + "=1 AND ") .append(MEncodedMessage.COL_ID).append(" NOT IN ") .append("(").append(pendingUploads).append(")"); Cursor c = db.query(MEncodedMessage.TABLE, new String[] { MEncodedMessage.COL_ID }, selection.toString(), null, null, null, MEncodedMessage.COL_ID + " ASC"); TLongLinkedList ids = new TLongLinkedList(); try { while(c.moveToNext()) { ids.add(c.getLong(0)); } return ids; } finally { c.close(); } } public int deleteProcessedOldItems(int daysOld) { SQLiteDatabase db = initializeDatabase(); StringBuilder whereClause = new StringBuilder() .append(MEncodedMessage.COL_PROCESSED).append("=1 AND ") .append(MEncodedMessage.COL_PROCESSED_TIME).append("<?"); long since = System.currentTimeMillis() - (daysOld * 24 * 60 * 60 * 1000); String[] whereArgs = new String[] { String.valueOf(since) }; return db.delete(MEncodedMessage.TABLE, whereClause.toString(), whereArgs); } public long[] getNonDecodedInboundIds() { if (mSqlObjectsToDecode == null) { StringBuilder sql = new StringBuilder(80); sql.append("SELECT ").append(MEncodedMessage.COL_ID) .append(" FROM ").append(MEncodedMessage.TABLE) .append(" WHERE ").append(MEncodedMessage.COL_PROCESSED).append("=0") .append(" AND ").append(MEncodedMessage.COL_OUTBOUND).append("=0") .append(" ORDER BY ").append(MEncodedMessage.COL_ID).append(" ASC"); mSqlObjectsToDecode = sql.toString(); } SQLiteDatabase db = initializeDatabase(); Cursor c = db.rawQuery(mSqlObjectsToDecode, null); long[] ids = new long[c.getCount()]; int i = 0; try { while (c.moveToNext()) { ids[i++] = c.getLong(0); } return ids; } finally { c.close(); } } public long getEncodedIdForHash(byte[] hash) { SQLiteDatabase db = initializeDatabase(); if (mSqlGetEncodedIdByHash == null) { synchronized (this) { if(mSqlGetEncodedIdByHash == null) { String sql = new StringBuilder() .append("SELECT ").append(MEncodedMessage.COL_ID).append(" FROM ").append(MEncodedMessage.TABLE).append(" WHERE ") .append(MEncodedMessage.COL_SHORT_HASH).append("=?").append(" AND ") .append(MEncodedMessage.COL_HASH).append("=?").toString(); mSqlGetEncodedIdByHash = db.compileStatement(sql); } } } synchronized (mSqlGetEncodedIdByHash) { mSqlGetEncodedIdByHash.bindLong(1, Util.shortHash(hash)); mSqlGetEncodedIdByHash.bindBlob(2, hash); try { return mSqlGetEncodedIdByHash.simpleQueryForLong(); } catch(SQLiteDoneException e) { return -1; } } } public long getFeedIdForEncoded(long encodedId) { SQLiteDatabase db = initializeDatabase(); if (mSqlGetFeedIdForEncoded == null) { synchronized (this) { if (mSqlGetFeedIdForEncoded == null) { StringBuilder sql = new StringBuilder(50); sql.append(" SELECT ").append(MObject.COL_FEED_ID) .append(" FROM ").append(MObject.TABLE) .append(" WHERE ").append(MObject.COL_ENCODED_ID).append("=?") .append(" LIMIT 1"); mSqlGetFeedIdForEncoded = db.compileStatement(sql.toString()); } } } synchronized(mSqlGetFeedIdForEncoded) { mSqlGetFeedIdForEncoded.bindLong(1, encodedId); try { return mSqlGetFeedIdForEncoded.simpleQueryForLong(); } catch (SQLiteDoneException e) { return -1; } } } @Override public synchronized void close() { if (sqlInsertEncoded_ != null) { sqlInsertEncoded_.close(); sqlInsertEncoded_ = null; } if (sqlUpdateEncoded_ != null) { sqlUpdateEncoded_.close(); sqlUpdateEncoded_ = null; } if (mSqlGetEncodedIdByHash != null) { mSqlGetEncodedIdByHash.close(); mSqlGetEncodedIdByHash = null; } if (mSqlGetFeedIdForEncoded != null) { mSqlGetFeedIdForEncoded.close(); mSqlGetFeedIdForEncoded = null; } } }