/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the Common Development
* and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at
* src/com/vodafone360/people/VODAFONE.LICENSE.txt or
* http://github.com/360/360-Engine-for-Android
* See the License for the specific language governing permissions and
* limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each file and
* include the License file at src/com/vodafone360/people/VODAFONE.LICENSE.txt.
* If applicable, add the following below this CDDL HEADER, with the fields
* enclosed by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright 2010 Vodafone Sales & Services Ltd. All rights reserved.
* Use is subject to license terms.
*/
package com.vodafone360.people.database.tables;
import java.util.ArrayList;
import java.util.Iterator;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import com.vodafone360.people.database.DatabaseHelper;
import com.vodafone360.people.database.SQLKeys;
import com.vodafone360.people.database.utils.SqlUtils;
import com.vodafone360.people.datatypes.ContactSummary.OnlineStatus;
import com.vodafone360.people.engine.presence.NetworkPresence;
import com.vodafone360.people.engine.presence.User;
import com.vodafone360.people.utils.CloseUtils;
import com.vodafone360.people.utils.LogUtils;
import com.vodafone360.people.utils.StringBufferPool;
/**
* PresenceTable... The table for storing the presence states of contacts.
*
* @throws SQLException is thrown when request to create a table fails with an
* SQLException
* @throws NullPointerException if the passed in database instance is null
*/
public abstract class PresenceTable {
/***
* The name of the table as it appears in the database.
*/
public static final String TABLE_NAME = "Presence"; // it is used in the
// tests
/**
* The return types for the add/update method: if a new record was added.
*/
public static final int USER_ADDED = 0;
/**
* The return types for the add/update method: if an existing record was
* updated.
*/
public static final int USER_UPDATED = 1;
/**
* The return types for the add/update method: if an error happened and
* prevented the record from being added or updated.
*/
public static final int USER_NOTADDED = 2;
/**
* An enumeration of all the field names in the database, containing ID,
* LOCAL_CONTACT_ID, USER_ID, NETWORK_ID, NETWORK_STATUS.
*/
private static enum Field {
/**
* The primary key.
*/
ID("id"),
/**
* The internal representation of the serverId for this account.
*/
LOCAL_CONTACT_ID("LocalContactId"),
/**
* This is contact list id: gmail, facebook, nowplus or other account,
* STRING.
*/
USER_ID("ImAddress"),
/**
* The SocialNetwork id, INT.
*/
NETWORK_ID("NetworkId"),
/**
* The presence status id, INT.
*/
NETWORK_STATUS("Status");
/**
* The name of the field as it appears in the database.
*/
private String mField;
/**
* Constructor.
*
* @param field - Field name
*/
private Field(String field) {
mField = field;
}
/*
* This implementation returns the field name. (non-Javadoc)
* @see java.lang.Enum#toString()
*/
public String toString() {
return mField;
}
}
/**
* The constants for column indexes in the table: LocalContactId
*/
private static final int LOCAL_CONTACT_ID = 1;
/**
* The constants for column indexes in the table: ImAddress
*/
private static final int USER_ID = 2;
/**
* The constants for column indexes in the table: NetworkId
*/
private static final int NETWORK_ID = 3;
/**
* The constants for column indexes in the table: Status
*/
private static final int NETWORK_STATUS = 4;
/**
* The default message for the NullPointerException caused by the null
* instance of database passed into PresenceTable methods.
*/
private static final String DEFAULT_ERROR_MESSAGE = "PresenceTable: the passed in database is null!";
/**
* This method creates the PresenceTable.
*
* @param writableDb - the writable database
* @throws SQLException is thrown when request to create a table fails with
* an SQLException
* @throws NullPointerException if the passed in database instance is null
*/
public static void create(SQLiteDatabase writableDb) throws SQLException, NullPointerException {
DatabaseHelper.trace(true, "PresenceTable.create()");
if (writableDb == null) {
throw new NullPointerException(DEFAULT_ERROR_MESSAGE);
}
String createSql = "CREATE TABLE IF NOT EXISTS " + DatabaseHelper.DATABASE_PRESENCE
+ "." + TABLE_NAME + " (" + Field.ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + Field.LOCAL_CONTACT_ID + " LONG, "
+ Field.USER_ID + " STRING, " + Field.NETWORK_ID + " INT, " + Field.NETWORK_STATUS
+ " INT);";
writableDb.execSQL(createSql);
}
/**
* This method updates the user with the information from the User wrapper.
*
* @param user2Update - User info to update
* @param ignoredNetworkIds - ArrayList of integer network ids presence state for which must be ignored.
* @param writableDatabase - writable database
* @return USER_ADDED if no user with user id like the one in user2Update
* payload "status.getUserId()" ever existed in this table,
* USER_UPDATED if the user already existed in the table and has
* been successfully added, USER_NOT_ADDED - if user was not added.
* @throws SQLException if the database layer throws this exception.
* @throws NullPointerException if the passed in database instance is null.
*/
public static int updateUser(User user2Update, ArrayList<Integer> ignoredNetworkIds, SQLiteDatabase writableDatabase)
throws SQLException, NullPointerException {
int ret = USER_NOTADDED;
if (writableDatabase == null) {
throw new NullPointerException(DEFAULT_ERROR_MESSAGE);
}
if (user2Update != null) {
ArrayList<NetworkPresence> statusesOnNetworks = user2Update.getPayload();
if (!statusesOnNetworks.isEmpty()) {
ContentValues values = new ContentValues();
StringBuffer where = null;
Iterator<NetworkPresence> itr = statusesOnNetworks.iterator();
NetworkPresence status = null;
long localContactId = user2Update.getLocalContactId();
int networkId = 0;
while (itr.hasNext()) {
status = itr.next();
networkId = status.getNetworkId();
if (ignoredNetworkIds == null || !ignoredNetworkIds.contains(networkId)) {
values.put(Field.LOCAL_CONTACT_ID.toString(), localContactId);
values.put(Field.USER_ID.toString(), status.getUserId());
values.put(Field.NETWORK_ID.toString(), networkId);
values.put(Field.NETWORK_STATUS.toString(), status.getOnlineStatusId());
where = StringBufferPool.getStringBuffer(Field.LOCAL_CONTACT_ID.toString());
where.append(SQLKeys.EQUALS).append(localContactId).
append(SQLKeys.AND).append(Field.NETWORK_ID).append(SQLKeys.EQUALS).append(networkId);
int numberOfAffectedRows = writableDatabase.update(TABLE_NAME, values, StringBufferPool.toStringThenRelease(where),
null);
if (numberOfAffectedRows == 0) {
if (writableDatabase.insert(TABLE_NAME, null, values) != -1) {
ret = USER_ADDED;
} else {
LogUtils.logE("PresenceTable updateUser(): could not add new user!");
}
} else if (ret == USER_NOTADDED) {
ret = USER_UPDATED;
}
values.clear();
} else if (ignoredNetworkIds != null) { // presence information from this network needs to be ignored
itr.remove();
}
}
}
}
return ret;
}
/**
* This method fills the provided user object with presence information.
*
* @param user User - the user with a localContactId != -1
* @param readableDatabase - the database to read from
* @return user/me profile presence state wrapped in "User" wrapper class,
* or NULL if the specified localContactId doesn't exist
* @throws SQLException if the database layer throws this exception.
* @throws NullPointerException if the passed in database instance is null.
*/
public static void getUserPresence(User user,
SQLiteDatabase readableDatabase) throws SQLException, NullPointerException {
if (readableDatabase == null) {
throw new NullPointerException(DEFAULT_ERROR_MESSAGE);
}
if (user.getLocalContactId() < 0) {
LogUtils.logE("PresenceTable.getUserPresenceByLocalContactId(): "
+ "#localContactId# parameter is -1 ");
return;
}
Cursor c = null;
try {
c = readableDatabase.rawQuery("SELECT * FROM " + TABLE_NAME + " WHERE "
+ Field.LOCAL_CONTACT_ID + "=" + user.getLocalContactId(), null);
if (c != null) {
int onlineStatus = OnlineStatus.OFFLINE.ordinal(); // i.e. 0
ArrayList<NetworkPresence> payload = user.getPayload();
payload.clear();
while (c.moveToNext()) {
String userId = c.getString(USER_ID);
int networkId = c.getInt(NETWORK_ID);
int statusId = c.getInt(NETWORK_STATUS);
if (statusId > onlineStatus) {
onlineStatus = statusId;
}
payload.add(new NetworkPresence(userId, networkId, statusId));
}
user.setOverallOnline(onlineStatus);
}
} finally {
CloseUtils.close(c);
c = null;
}
}
/**
* This method returns user/me profile presence state.
*
* @param localContactId - me profile localContactId
* @param readableDatabase - the database to read from
* @return user/me profile presence state wrapped in "User" wrapper class,
* or NULL if the specified localContactId doesn't exist
* @throws SQLException if the database layer throws this exception.
* @throws NullPointerException if the passed in database instance is null.
* @return user - User object filled with presence information.
*/
public static User getUserPresenceByLocalContactId(long localContactId,
SQLiteDatabase readableDatabase) throws SQLException, NullPointerException {
if (readableDatabase == null) {
throw new NullPointerException(DEFAULT_ERROR_MESSAGE);
}
User user = null;
if (localContactId < 0) {
LogUtils.logE("PresenceTable.getUserPresenceByLocalContactId(): "
+ "#localContactId# parameter is -1 ");
return user;
}
Cursor c = null;
try {
c = readableDatabase.rawQuery("SELECT * FROM " + TABLE_NAME + " WHERE "
+ Field.LOCAL_CONTACT_ID + "=" + localContactId, null);
ArrayList<NetworkPresence> networkPresence = new ArrayList<NetworkPresence>();
user = new User();
int onlineStatus = OnlineStatus.OFFLINE.ordinal(); // i.e. 0
while (c.moveToNext()) {
user.setLocalContactId(c.getLong(LOCAL_CONTACT_ID));
String userId = c.getString(USER_ID);
int networkId = c.getInt(NETWORK_ID);
int statusId = c.getInt(NETWORK_STATUS);
if (statusId > onlineStatus) {
onlineStatus = statusId;
}
networkPresence.add(new NetworkPresence(userId, networkId, statusId));
}
if (!networkPresence.isEmpty()) {
user.setOverallOnline(onlineStatus);
user.setPayload(networkPresence);
}
} finally {
CloseUtils.close(c);
c = null;
}
return user;
}
/**
* The method cleans the presence table: deletes all the rows.
*
* @param writableDatabase - database to write to.
* @return the number of rows affected if a whereClause is passed in, 0
* otherwise.
* @throws NullPointerException if the passed in database instance is null.
*/
public static int setAllUsersOffline(SQLiteDatabase writableDatabase)
throws NullPointerException {
if (writableDatabase == null) {
throw new NullPointerException(DEFAULT_ERROR_MESSAGE);
}
// To remove all rows and get a count pass null as the whereClause
return writableDatabase.delete(TABLE_NAME, null, null);
}
/**
* The method cleans the presence table: deletes all the rows, except for
* the given user localContactId ("Me Profile" localContactId)
*
* @param localContactIdOfMe - the localContactId of the user (long), whose
* info should not be deleted
* @param writableDatabase - database to write to.
* @return the number of rows affected if a whereClause is passed in, 0
* otherwise.
* @throws NullPointerException if the passed in database instance is null.
*/
public static int setAllUsersOfflineExceptForMe(long localContactIdOfMe,
SQLiteDatabase writableDatabase) throws NullPointerException {
if (writableDatabase == null) {
throw new NullPointerException(DEFAULT_ERROR_MESSAGE);
}
return writableDatabase.delete(TABLE_NAME, Field.LOCAL_CONTACT_ID + " != "
+ localContactIdOfMe, null);
}
/**
* This method returns the array of distinct user local contact ids in this table.
* @param readableDatabase - database.
* @return ArrayList of Long distinct local contact ids from this table.
*/
public static ArrayList<Long> getLocalContactIds(SQLiteDatabase readableDatabase) {
Cursor c = null;
ArrayList<Long> ids = new ArrayList<Long>();
try {
c = readableDatabase.rawQuery("SELECT DISTINCT " +Field.LOCAL_CONTACT_ID+ " FROM " + TABLE_NAME, null);
if (c != null) {
while (c.moveToNext()) {
ids.add(c.getLong(0));
}
}
} finally {
CloseUtils.close(c);
c = null;
}
return ids;
}
/**
* This method deletes information about the user presence states on the provided networks.
* @param networksToDelete - ArrayList of integer network ids.
* @param writableDatabase - writable database.
* @throws NullPointerException is thrown when the provided database is null.
*/
public static void setTPCNetworksOffline(ArrayList<Integer> networksToDelete,
SQLiteDatabase writableDatabase) throws NullPointerException {
if (writableDatabase == null) {
throw new NullPointerException(DEFAULT_ERROR_MESSAGE);
}
StringBuffer networks = StringBufferPool.getStringBuffer();
for (Integer network : networksToDelete) {
networks.append(network).append(SqlUtils.COMMA);
}
if (networks.length() > 0) {
networks.deleteCharAt(networks.lastIndexOf(SqlUtils.COMMA));
}
final StringBuilder where = new StringBuilder(Field.NETWORK_ID.toString());
where.append(" IN (").append(StringBufferPool.toStringThenRelease(networks)).append(")");
writableDatabase.delete(TABLE_NAME, where.toString(), null);
}
}