package org.commcare.engine.resource;
import org.commcare.models.database.SqlStorage;
import org.commcare.resources.model.InstallerFactory;
import org.commcare.resources.model.Resource;
import org.commcare.resources.model.ResourceTable;
import org.javarosa.core.services.storage.IStorageIterator;
import org.javarosa.core.services.storage.IStorageUtilityIndexed;
import java.util.HashSet;
import java.util.Vector;
/**
* Override resource table logic with more performant storage access.
*
* @author Phillip Mates (pmates@dimagi.com)
*/
public class AndroidResourceTable extends ResourceTable {
private final SqlStorage<Resource> sqlStorage;
// An in-memory represesntation of resources in the table. Used to avoid
// hitting storage to check resource existence.
// Only resource IDs are stored in the set.
private HashSet<String> resourcesInTable;
public AndroidResourceTable(SqlStorage<Resource> storage, InstallerFactory factory) {
super((IStorageUtilityIndexed)storage, factory);
this.sqlStorage = storage;
}
@Override
public Vector<Resource> getResourcesForParent(String parent) {
// avoids intermediate ID lookup of default implementation
return sqlStorage.getRecordsForValue(Resource.META_INDEX_PARENT_GUID, parent);
}
@Override
protected boolean resourceDoesntExist(Resource resource) {
initResourcesInTable();
// check in-memory cache instead of hitting storage
return !resourcesInTable.contains(resource.getResourceId());
}
/**
* Load IDs for resources present in table's storage into memory.
*/
private void initResourcesInTable() {
if (resourcesInTable == null) {
resourcesInTable = new HashSet<>();
for (IStorageIterator it = sqlStorage.iterate(); it.hasMore(); ) {
Resource r = (Resource)it.nextRecord();
resourcesInTable.add(r.getResourceId());
}
}
}
@Override
protected void cleanup() {
super.cleanup();
initResourcesInTable();
resourcesInTable.clear();
}
@Override
public void commit(Resource r) {
super.commit(r);
initResourcesInTable();
resourcesInTable.add(r.getResourceId());
}
}