CacheManager.java
/*
* Copyright (c) 2014-present, salesforce.com, inc.
* All rights reserved.
* Redistribution and use of this software in source and binary forms, with or
* without modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of salesforce.com, inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission of salesforce.com, inc.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package com.salesforce.androidsdk.smartsync.manager;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.text.TextUtils;
import android.util.Log;
import com.salesforce.androidsdk.accounts.UserAccount;
import com.salesforce.androidsdk.smartstore.app.SmartStoreSDKManager;
import com.salesforce.androidsdk.smartstore.store.IndexSpec;
import com.salesforce.androidsdk.smartstore.store.QuerySpec;
import com.salesforce.androidsdk.smartstore.store.SmartStore;
import com.salesforce.androidsdk.smartstore.store.SmartStore.SmartStoreException;
import com.salesforce.androidsdk.smartstore.store.SmartStore.Type;
import com.salesforce.androidsdk.smartsync.app.SmartSyncSDKManager;
import com.salesforce.androidsdk.smartsync.model.SalesforceObject;
import com.salesforce.androidsdk.smartsync.model.SalesforceObjectType;
import com.salesforce.androidsdk.smartsync.model.SalesforceObjectTypeLayout;
import com.salesforce.androidsdk.smartsync.util.Constants;
/**
* This class provides APIs to store and retrieve Salesforce object
* metadata, object layouts and MRU objects from a simple cache.
*
* @author bhariharan
*/
public class CacheManager {
private static final String TAG = "SmartSync: CacheManager";
private static final String CACHE_KEY = "cache_key";
private static final String CACHE_DATA = "cache_data";
private static final String SOUP_OF_SOUPS = "master_soup";
private static final String SOUP_NAMES_KEY = "soup_names";
private static Map<String, CacheManager> INSTANCES;
private final SmartStore smartStore;
private Map<String, List<SalesforceObjectType>> objectTypeCacheMap;
private Map<String, List<SalesforceObject>> objectCacheMap;
private Map<String, List<SalesforceObjectTypeLayout>> objectTypeLayoutCacheMap;
/**
* This enum defines different possible cache policies.
*
* @author bhariharan
*/
public enum CachePolicy {
IGNORE_CACHE_DATA, // Ignores cache data and always loads from server.
RELOAD_AND_RETURN_CACHE_ON_FAILURE, // Always reloads data and returns cache data only on failure.
RETURN_CACHE_DATA_DONT_RELOAD, // Returns cache data and does not refresh cache if cache exists.
RELOAD_AND_RETURN_CACHE_DATA, // Reloads and returns cache data.
RELOAD_IF_EXPIRED_AND_RETURN_CACHE_DATA, // Refreshes cache if the refresh time interval is up and returns cache data.
INVALIDATE_CACHE_DONT_RELOAD, // Invalidates the cache and does not refresh the cache.
INVALIDATE_CACHE_AND_RELOAD; // Invalidates the cache and refreshes the cache.
}
/**
* Returns the instance of this class associated with this user account.
*
* @param account User account.
* @return Instance of this class.
*/
public static synchronized CacheManager getInstance(UserAccount account) {
return getInstance(account, null);
}
/**
* Returns the instance of this class associated with this user and community.
*
* @param account User account.
* @param communityId Community ID.
* @return Instance of this class.
*/
public static synchronized CacheManager getInstance(UserAccount account, String communityId) {
if (account == null) {
account = SmartStoreSDKManager.getInstance().getUserAccountManager().getCurrentUser();
}
if (account == null) {
return null;
}
String uniqueId = account.getUserId();
if (UserAccount.INTERNAL_COMMUNITY_ID.equals(communityId)) {
communityId = null;
}
if (!TextUtils.isEmpty(communityId)) {
uniqueId = uniqueId + communityId;
}
CacheManager instance = null;
if (INSTANCES == null) {
INSTANCES = new HashMap<String, CacheManager>();
instance = new CacheManager(account, communityId);
INSTANCES.put(uniqueId, instance);
} else {
instance = INSTANCES.get(uniqueId);
}
if (instance == null) {
instance = new CacheManager(account, communityId);
INSTANCES.put(uniqueId, instance);
}
instance.resetInMemoryCache();
return instance;
}
/**
* Resets the cache manager for this user account. This method clears
* only the in memory cache.
*
* @param account User account.
*/
public static synchronized void softReset(UserAccount account) {
softReset(account, null);
}
/**
* Resets the cache manager for this user account. This method clears
* only the in memory cache.
*
* @param account User account.
* @param communityId Community ID.
*/
public static synchronized void softReset(UserAccount account, String communityId) {
if (account == null) {
account = SmartStoreSDKManager.getInstance().getUserAccountManager().getCurrentUser();
}
if (account != null) {
String uniqueId = account.getUserId();
if (UserAccount.INTERNAL_COMMUNITY_ID.equals(communityId)) {
communityId = null;
}
if (!TextUtils.isEmpty(communityId)) {
uniqueId = uniqueId + communityId;
}
if (getInstance(account, communityId) != null) {
getInstance(account, communityId).resetInMemoryCache();
if (INSTANCES != null) {
INSTANCES.remove(uniqueId);
}
}
}
}
/**
* Resets the cache manager for this user account. This method clears
* the in memory cache and the underlying cache in the database.
*
* @param account User account.
*/
public static synchronized void hardReset(UserAccount account) {
hardReset(account, null);
}
/**
* Resets the cache manager for this user account. This method clears
* the in memory cache and the underlying cache in the database.
*
* @param account User account.
* @param communityId Community ID.
*/
public static synchronized void hardReset(UserAccount account, String communityId) {
if (account == null) {
account = SmartStoreSDKManager.getInstance().getUserAccountManager().getCurrentUser();
}
if (account != null) {
String uniqueId = account.getUserId();
if (UserAccount.INTERNAL_COMMUNITY_ID.equals(communityId)) {
communityId = null;
}
if (!TextUtils.isEmpty(communityId)) {
uniqueId = uniqueId + communityId;
}
if (getInstance(account, communityId) != null) {
getInstance(account, communityId).cleanCache();
if (INSTANCES != null) {
INSTANCES.remove(uniqueId);
}
}
}
}
/**
* Private parameterized constructor.
*
* @param account User account.
* @param communityId Community ID.
*/
private CacheManager(UserAccount account, String communityId) {
smartStore = SmartSyncSDKManager.getInstance().getSmartStore(account, communityId);
resetInMemoryCache();
}
/**
* Returns whether the specified cache exists.
*
* @param soupName Soup name.
* @return True - if the cache exists, False - otherwise.
*/
public boolean doesCacheExist(String soupName) {
if (soupName == null || Constants.EMPTY_STRING.equals(soupName)
|| !smartStore.hasSoup(soupName)) {
return false;
}
return true;
}
/**
* Removes existing data from the specified cache.
*
* @param cacheType Cache type.
* @param cacheKey Cache key.
*/
public void removeCache(String cacheType, String cacheKey) {
if (cacheType == null || cacheKey == null ||
Constants.EMPTY_STRING.equals(cacheType) ||
Constants.EMPTY_STRING.equals(cacheKey)) {
return;
}
if (doesCacheExist(cacheType)) {
smartStore.dropSoup(cacheType);
removeSoupNameFromMasterSoup(cacheType);
resetInMemoryCache();
}
}
/**
* Returns whether the cache needs to be refreshed. Before this method is
* called, either 'doesCacheExist', or 'lastCacheUpdateTime' should be
* called to determine whether the cache already exists and the
* last update time of the cache.
*
* @param cacheExists True - if the cache exists, False - otherwise.
* @param cachePolicy Cache policy being used.
* @param lastCachedTime Last time the cache was updated.
* @param refreshIfOlderThan Refresh time interval. A negative value will
* result in the cache not being refreshed.
* @return True - if cache needs to be refreshed, False - otherwise.
*/
public boolean needToReloadCache(boolean cacheExists, CachePolicy cachePolicy,
long lastCachedTime, long refreshIfOlderThan) {
if (cachePolicy == CachePolicy.IGNORE_CACHE_DATA ||
cachePolicy == CachePolicy.RETURN_CACHE_DATA_DONT_RELOAD ||
cachePolicy == CachePolicy.INVALIDATE_CACHE_DONT_RELOAD) {
return false;
}
if (cachePolicy == CachePolicy.RELOAD_AND_RETURN_CACHE_DATA ||
cachePolicy == CachePolicy.RELOAD_AND_RETURN_CACHE_ON_FAILURE ||
cachePolicy == CachePolicy.INVALIDATE_CACHE_AND_RELOAD) {
return true;
}
if (!cacheExists || refreshIfOlderThan <= 0 || lastCachedTime <= 0) {
return true;
}
long timeDiff = System.currentTimeMillis() - lastCachedTime;
return (timeDiff > refreshIfOlderThan);
}
/**
* Returns the last time the cache was refreshed.
*
* @param cacheType Cache type.
* @param cacheKey Cache key.
* @return Last update time of the cache.
*/
public long getLastCacheUpdateTime(String cacheType, String cacheKey) {
try {
if (cacheType == null || cacheKey == null ||
Constants.EMPTY_STRING.equals(cacheType) ||
Constants.EMPTY_STRING.equals(cacheKey)) {
return 0;
}
if (!doesCacheExist(cacheType)) {
return 0;
}
final QuerySpec querySpec = QuerySpec.buildExactQuerySpec(cacheType,
CACHE_KEY, cacheKey, null, null, 1);
final JSONArray results = smartStore.query(querySpec, 0);
if (results != null && results.length() > 0) {
final JSONObject jObj = results.optJSONObject(0);
if (jObj != null) {
return jObj.optLong(SmartStore.SOUP_LAST_MODIFIED_DATE);
}
}
} catch (IllegalStateException e) {
Log.e(TAG, "IllegalStateException occurred while attempting to read last cached time", e);
} catch (JSONException e) {
Log.e(TAG, "JSONException occurred while attempting to read last cached time", e);
} catch (SmartStoreException e) {
Log.e(TAG, "SmartStoreException occurred while attempting to read last cached time", e);
}
return 0;
}
/**
* Reads a list of Salesforce object types from the cache.
*
* @param cacheType Cache type.
* @param cacheKey Cache key.
* @return List of Salesforce object types.
*/
public List<SalesforceObjectType> readObjectTypes(String cacheType,
String cacheKey) {
if (cacheType == null || cacheKey == null ||
Constants.EMPTY_STRING.equals(cacheType) ||
Constants.EMPTY_STRING.equals(cacheKey)) {
return null;
}
if (!doesCacheExist(cacheType)) {
return null;
}
// Checks in memory cache first.
if (objectTypeCacheMap != null) {
final List<SalesforceObjectType> cachedObjTypes = objectTypeCacheMap.get(cacheKey);
if (cachedObjTypes != null && cachedObjTypes.size() > 0) {
return cachedObjTypes;
}
}
// Falls back on smart store cache if in memory cache is empty.
try {
final QuerySpec querySpec = QuerySpec.buildExactQuerySpec(cacheType,
CACHE_KEY, cacheKey, null, null, 1);
final JSONArray results = smartStore.query(querySpec, 0);
if (results != null && results.length() > 0) {
final JSONObject jObj = results.optJSONObject(0);
if (jObj != null) {
final JSONArray res = jObj.optJSONArray(CACHE_DATA);
if (res != null && res.length() > 0) {
final List<SalesforceObjectType> cachedList = new ArrayList<SalesforceObjectType>();
for (int j = 0; j < res.length(); j++) {
final JSONObject sfObj = res.optJSONObject(j);
if (sfObj != null) {
cachedList.add(new SalesforceObjectType(sfObj));
}
}
if (cachedList.size() > 0) {
// Inserts or updates data in memory cache.
if (objectTypeCacheMap != null) {
if (objectTypeCacheMap.get(cacheKey) != null) {
objectTypeCacheMap.remove(cacheKey);
}
objectTypeCacheMap.put(cacheKey, cachedList);
}
return cachedList;
}
}
}
}
} catch (JSONException e) {
Log.e(TAG, "JSONException occurred while attempting to read cached data", e);
} catch (SmartStoreException e) {
Log.e(TAG, "SmartStoreException occurred while attempting to read cached data", e);
}
return null;
}
/**
* Reads a list of Salesforce objects from the cache.
*
* @param cacheType Cache type.
* @param cacheKey Cache key.
* @return List of Salesforce objects.
*/
public List<SalesforceObject> readObjects(String cacheType, String cacheKey) {
if (cacheType == null || cacheKey == null ||
Constants.EMPTY_STRING.equals(cacheType) ||
Constants.EMPTY_STRING.equals(cacheKey)) {
return null;
}
if (!doesCacheExist(cacheType)) {
return null;
}
// Checks in memory cache first.
if (objectCacheMap != null) {
final List<SalesforceObject> cachedObjs = objectCacheMap.get(cacheKey);
if (cachedObjs != null && cachedObjs.size() > 0) {
return cachedObjs;
}
}
// Falls back on smart store cache if in memory cache is empty.
try {
final QuerySpec querySpec = QuerySpec.buildExactQuerySpec(cacheType,
CACHE_KEY, cacheKey, null, null, 1);
final JSONArray results = smartStore.query(querySpec, 0);
if (results != null && results.length() > 0) {
final JSONObject jObj = results.optJSONObject(0);
if (jObj != null) {
final JSONArray res = jObj.optJSONArray(CACHE_DATA);
if (res != null && res.length() > 0) {
final List<SalesforceObject> cachedList = new ArrayList<SalesforceObject>();
for (int j = 0; j < res.length(); j++) {
final JSONObject sfObj = res.optJSONObject(j);
if (sfObj != null) {
cachedList.add(new SalesforceObject(sfObj));
}
}
if (cachedList.size() > 0) {
// Inserts or updates data in memory cache.
if (objectCacheMap != null) {
if (objectCacheMap.get(cacheKey) != null) {
objectCacheMap.remove(cacheKey);
}
objectCacheMap.put(cacheKey, cachedList);
}
return cachedList;
}
}
}
}
} catch (JSONException e) {
Log.e(TAG, "JSONException occurred while attempting to read cached data", e);
} catch (SmartStoreException e) {
Log.e(TAG, "SmartStoreException occurred while attempting to read cached data", e);
}
return null;
}
/**
* Reads a list of Salesforce object layouts from the cache.
*
* @param cacheType Cache type.
* @param cacheKey Cache key.
* @return List of Salesforce object layouts.
*/
public List<SalesforceObjectTypeLayout> readObjectLayouts(String cacheType, String cacheKey) {
if (cacheType == null || cacheKey == null ||
Constants.EMPTY_STRING.equals(cacheType) ||
Constants.EMPTY_STRING.equals(cacheKey)) {
return null;
}
if (!doesCacheExist(cacheType)) {
return null;
}
// Checks in memory cache first.
if (objectTypeLayoutCacheMap != null) {
final List<SalesforceObjectTypeLayout> cachedObjs = objectTypeLayoutCacheMap.get(cacheKey);
if (cachedObjs != null && cachedObjs.size() > 0) {
return cachedObjs;
}
}
// Falls back on smart store cache if in memory cache is empty.
try {
final QuerySpec querySpec = QuerySpec.buildExactQuerySpec(cacheType,
CACHE_KEY, cacheKey, null, null, 1);
final JSONArray results = smartStore.query(querySpec, 0);
if (results != null && results.length() > 0) {
final JSONObject jObj = results.optJSONObject(0);
if (jObj != null) {
final JSONArray res = jObj.optJSONArray(CACHE_DATA);
if (res != null && res.length() > 0) {
final List<SalesforceObjectTypeLayout> cachedList = new ArrayList<SalesforceObjectTypeLayout>();
for (int j = 0; j < res.length(); j++) {
final JSONObject sfObj = res.optJSONObject(j);
if (sfObj != null) {
final JSONObject rawData = sfObj.optJSONObject("rawData");
final String type = sfObj.optString("type");
if (rawData != null && type != null &&
!Constants.EMPTY_STRING.equals(type)) {
cachedList.add(new SalesforceObjectTypeLayout(type, rawData));
}
}
}
if (cachedList.size() > 0) {
// Inserts or updates data in memory cache.
if (objectTypeLayoutCacheMap != null) {
if (objectTypeLayoutCacheMap.get(cacheKey) != null) {
objectTypeLayoutCacheMap.remove(cacheKey);
}
objectTypeLayoutCacheMap.put(cacheKey, cachedList);
}
return cachedList;
}
}
}
}
} catch (JSONException e) {
Log.e(TAG, "JSONException occurred while attempting to read cached data", e);
} catch (SmartStoreException e) {
Log.e(TAG, "SmartStoreException occurred while attempting to read cached data", e);
}
return null;
}
/**
* Writes a list of Salesforce object types to the cache.
*
* @param objectTypes List of Salesforce object types.
* @param cacheKey Cache key.
* @param cacheType Cache type.
*/
public void writeObjectTypes(List<SalesforceObjectType> objectTypes,
String cacheKey, String cacheType) {
if (objectTypes == null || cacheType == null || cacheKey == null ||
Constants.EMPTY_STRING.equals(cacheType) ||
Constants.EMPTY_STRING.equals(cacheKey) ||
objectTypes.size() == 0) {
return;
}
// Inserts or updates data in memory cache.
if (objectTypeCacheMap != null) {
if (objectTypeCacheMap.get(cacheKey) != null) {
objectTypeCacheMap.remove(cacheKey);
}
objectTypeCacheMap.put(cacheKey, objectTypes);
}
// Inserts or updates data in smart store.
final JSONArray data = new JSONArray();
for (final SalesforceObjectType objectType : objectTypes) {
if (objectType != null) {
data.put(objectType.getRawData());
}
}
if (data.length() > 0) {
final JSONObject object = new JSONObject();
try {
object.put(CACHE_KEY, cacheKey);
object.put(CACHE_DATA, data);
upsertData(cacheType, object, cacheKey);
} catch (JSONException e) {
Log.e(TAG, "JSONException occurred while attempting to cache data", e);
} catch (SmartStoreException e) {
Log.e(TAG, "SmartStoreException occurred while attempting to cache data", e);
}
}
}
/**
* Writes a list of Salesforce object layouts to the cache.
*
* @param objects List of Salesforce object layouts.
* @param cacheKey Cache key.
* @param cacheType Cache type.O
*/
public void writeObjectLayouts(List<SalesforceObjectTypeLayout> objects,
String cacheKey, String cacheType) {
if (objects == null || cacheType == null || cacheKey == null ||
Constants.EMPTY_STRING.equals(cacheType) ||
Constants.EMPTY_STRING.equals(cacheKey) ||
objects.size() == 0) {
return;
}
// Inserts or updates data in memory cache.
if (objectTypeLayoutCacheMap != null) {
if (objectTypeLayoutCacheMap.get(cacheKey) != null) {
objectTypeLayoutCacheMap.remove(cacheKey);
}
objectTypeLayoutCacheMap.put(cacheKey, objects);
}
// Inserts or updates data in smart store.
final JSONArray data = new JSONArray();
for (final SalesforceObjectTypeLayout object : objects) {
if (object != null) {
final JSONObject obj = new JSONObject();
try {
obj.put("rawData", object.getRawData());
obj.put("type", object.getObjectType());
data.put(obj);
} catch (JSONException e) {
Log.e(TAG, "JSONException occurred while attempting to cache data", e);
}
}
}
if (data.length() > 0) {
final JSONObject obj = new JSONObject();
try {
obj.put(CACHE_KEY, cacheKey);
obj.put(CACHE_DATA, data);
upsertData(cacheType, obj, cacheKey);
} catch (JSONException e) {
Log.e(TAG, "JSONException occurred while attempting to cache data", e);
} catch (SmartStoreException e) {
Log.e(TAG, "SmartStoreException occurred while attempting to cache data", e);
}
}
}
/**
* Writes a list of Salesforce objects to the cache.
*
* @param objects List of Salesforce objects.
* @param cacheKey Cache key.
* @param cacheType Cache type.
*/
public void writeObjects(List<SalesforceObject> objects, String cacheKey,
String cacheType) {
if (objects == null || cacheType == null || cacheKey == null ||
Constants.EMPTY_STRING.equals(cacheType) ||
Constants.EMPTY_STRING.equals(cacheKey) ||
objects.size() == 0) {
return;
}
// Inserts or updates data in memory cache.
if (objectCacheMap != null) {
if (objectCacheMap.get(cacheKey) != null) {
objectCacheMap.remove(cacheKey);
}
objectCacheMap.put(cacheKey, objects);
}
// Inserts or updates data in smart store.
final JSONArray data = new JSONArray();
for (final SalesforceObject object : objects) {
if (object != null) {
data.put(object.getRawData());
}
}
if (data.length() > 0) {
final JSONObject obj = new JSONObject();
try {
obj.put(CACHE_KEY, cacheKey);
obj.put(CACHE_DATA, data);
upsertData(cacheType, obj, cacheKey);
} catch (JSONException e) {
Log.e(TAG, "JSONException occurred while attempting to cache data", e);
} catch (SmartStoreException e) {
Log.e(TAG, "SmartStoreException occurred while attempting to cache data", e);
}
}
}
/**
* @return SmartStore instance used by this CacheManager
*/
SmartStore getSmartStore() {
return smartStore;
}
/**
* Helper method that registers a soup with index specs.
*
* @param soupName Soup name.
* @param cacheKey Cache key.
*/
private void registerSoup(String soupName, String cacheKey) {
registerMasterSoup();
if (!doesCacheExist(soupName)) {
final IndexSpec[] indexSpecs = {
new IndexSpec(CACHE_KEY, Type.string)
};
smartStore.registerSoup(soupName, indexSpecs);
}
}
/**
* Helper method that registers the master soup, if necessary.
*/
private void registerMasterSoup() {
if (doesCacheExist(SOUP_OF_SOUPS)) {
return;
}
final IndexSpec[] indexSpecs = {
new IndexSpec(SOUP_NAMES_KEY, Type.string)
};
smartStore.registerSoup(SOUP_OF_SOUPS, indexSpecs);
}
/**
* Helper method that inserts/updates a record in the cache.
*
* @param soupName Soup name.
* @param object Object to be inserted.
* @param cacheKey Cache key.
*/
private void upsertData(String soupName, JSONObject object, String cacheKey) {
if (soupName == null || object == null ||
Constants.EMPTY_STRING.equals(soupName)) {
return;
}
registerSoup(soupName, cacheKey);
try {
smartStore.upsert(soupName, object, cacheKey);
addSoupNameToMasterSoup(soupName);
} catch (JSONException e) {
Log.e(TAG, "JSONException occurred while attempting to cache data", e);
} catch (SmartStoreException e) {
Log.e(TAG, "SmartStoreException occurred while attempting to cache data", e);
}
}
/**
* Helper method that returns whether the specified soup name exists
* in the master soup.
*
* @param soupName Soup name.
* @return True - if it exists, False - otherwise.
*/
private boolean doesMasterSoupContainSoup(String soupName) {
final JSONArray soupNames = getAllSoupNames();
for (int i = 0; i < soupNames.length(); i++) {
final JSONArray names = soupNames.optJSONArray(i);
if (names != null && names.length() > 0) {
final String name = names.optString(0);
if (soupName.equals(name)) {
return true;
}
}
}
return false;
}
/**
* Returns the list of soups being used in the cache.
*
* @return List of soup names.
*/
private JSONArray getAllSoupNames() {
JSONArray results = null;
if (smartStore.hasSoup(SOUP_OF_SOUPS)) {
final String smartSql = "SELECT {" + SOUP_OF_SOUPS + ":" +
SOUP_NAMES_KEY + "} FROM {" + SOUP_OF_SOUPS + "}";
QuerySpec querySpec = QuerySpec.buildSmartQuerySpec(smartSql, 1);
try {
int count = smartStore.countQuery(querySpec);
querySpec = QuerySpec.buildSmartQuerySpec(smartSql, count);
results = smartStore.query(querySpec, 0);
} catch (JSONException e) {
Log.e(TAG, "JSONException occurred while attempting to read cached data", e);
} catch (SmartStoreException e) {
Log.e(TAG, "SmartStoreException occurred while attempting to read cached data", e);
}
}
if (results == null) {
results = new JSONArray();
}
return results;
}
/**
* Adds a soup name to the master soup, if it does not exist.
*
* @param soupName Soup name to be added.
*/
private void addSoupNameToMasterSoup(String soupName) {
if (doesMasterSoupContainSoup(soupName)) {
return;
}
final JSONObject object = new JSONObject();
try {
object.put(SOUP_NAMES_KEY, soupName);
smartStore.upsert(SOUP_OF_SOUPS, object);
} catch (JSONException e) {
Log.e(TAG, "JSONException occurred while attempting to cache data", e);
} catch (SmartStoreException e) {
Log.e(TAG, "SmartStoreException occurred while attempting to cache data", e);
}
}
/**
* Removes a soup name from the master soup, if it exists.
*
* @param soupName Soup name to be removed.
*/
private void removeSoupNameFromMasterSoup(String soupName) {
if (!doesMasterSoupContainSoup(soupName)) {
return;
}
try {
QuerySpec querySpec = QuerySpec.buildExactQuerySpec(SOUP_OF_SOUPS, SOUP_NAMES_KEY,
soupName, SOUP_NAMES_KEY, QuerySpec.Order.ascending, 1);
smartStore.deleteByQuery(SOUP_OF_SOUPS, querySpec);
} catch (SmartStoreException e) {
Log.e(TAG, "SmartStoreException occurred while attempting to remove data", e);
}
}
/**
* Clears the master soup of all data.
*/
private void clearMasterSoup() {
smartStore.dropSoup(SOUP_OF_SOUPS);
}
/**
* Clears all soups used by this class and the master soup.
*/
private void clearAllSoups() {
final JSONArray soupNames = getAllSoupNames();
for (int i = 0; i < soupNames.length(); i++) {
final JSONArray names = soupNames.optJSONArray(i);
if (names != null && names.length() > 0) {
final String name = names.optString(0);
if (name != null) {
smartStore.dropSoup(name);
}
}
}
clearMasterSoup();
}
/**
* Resets the in memory cache.
*/
private void resetInMemoryCache() {
objectCacheMap = new HashMap<String, List<SalesforceObject>>();
objectTypeCacheMap = new HashMap<String, List<SalesforceObjectType>>();
objectTypeLayoutCacheMap = new HashMap<String, List<SalesforceObjectTypeLayout>>();
}
/**
* Clears the cache and creates a new clean cache.
*/
private void cleanCache() {
resetInMemoryCache();
// Checks to make sure SmartStore hasn't already been cleaned up.
if (SmartSyncSDKManager.getInstance().hasSmartStore()) {
clearAllSoups();
}
}
}