package org.commcare.xml; import android.net.ParseException; import android.net.Uri; import android.util.Pair; import net.sqlcipher.database.SQLiteDatabase; import org.commcare.CommCareApplication; import org.commcare.android.database.user.models.ACase; import org.commcare.cases.model.Case; import org.commcare.engine.references.JavaHttpReference; import org.commcare.interfaces.HttpRequestEndpoints; import org.commcare.logging.AndroidLogger; import org.commcare.models.database.SqlStorage; import org.commcare.models.database.user.models.AndroidCaseIndexTable; import org.commcare.models.database.user.models.EntityStorageCache; import org.commcare.utils.FileUtil; import org.commcare.utils.GlobalConstants; import org.commcare.xml.bulk.BulkProcessingCaseXmlParser; import org.javarosa.core.io.StreamsUtil; import org.javarosa.core.reference.InvalidReferenceException; import org.javarosa.core.reference.Reference; import org.javarosa.core.reference.ReferenceManager; import org.javarosa.core.services.Logger; import org.javarosa.core.services.storage.IStorageUtilityIndexed; import org.javarosa.core.util.PropertyUtils; import org.javarosa.xml.util.InvalidStructureException; import org.kxml2.io.KXmlParser; import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.SortedMap; /** * A bulk processing parser for the android platform. Provides superior performance when * processing high case loads during syncing and/or processing. * * @author ctsims */ public class AndroidBulkCaseXmlParser extends BulkProcessingCaseXmlParser { private HttpRequestEndpoints generator; private final EntityStorageCache mEntityCache; private final AndroidCaseIndexTable mCaseIndexTable; private final SqlStorage<ACase> storage; public AndroidBulkCaseXmlParser(KXmlParser parser, SqlStorage<ACase> storage, HttpRequestEndpoints generator) { this(parser, storage, new EntityStorageCache("case"), new AndroidCaseIndexTable(), generator); } public AndroidBulkCaseXmlParser(KXmlParser parser, SqlStorage<ACase> storage, EntityStorageCache entityStorageCache, AndroidCaseIndexTable indexTable, HttpRequestEndpoints generator) { super(parser); this.generator = generator; mEntityCache = entityStorageCache; mCaseIndexTable = indexTable; this.storage = storage; } protected SQLiteDatabase getDbHandle() { return CommCareApplication.instance().getUserDbHandle(); } @Override protected Case buildCase(String name, String typeId) { return new ACase(name, typeId); } @Override protected void performBulkRead(Set<String> currentBulkReadSet, Map<String, Case> currentOperatingSet) throws InvalidStructureException, IOException, XmlPullParserException { SQLiteDatabase db; db = getDbHandle(); db.beginTransaction(); try { for (ACase c : storage.getBulkRecordsForIndex(Case.INDEX_CASE_ID, currentBulkReadSet)) { currentOperatingSet.put(c.getCaseId(), c); } db.setTransactionSuccessful(); } finally { db.endTransaction(); } } @Override protected void performBulkWrite(LinkedHashMap<String, Case> writeLog) throws IOException { SQLiteDatabase db; db = getDbHandle(); db.beginTransaction(); ArrayList<Integer> recordIdsToWipe = new ArrayList<>(); try { for (String cid : writeLog.keySet()) { Case c = writeLog.get(cid); storage.write(c); recordIdsToWipe.add(c.getID()); } mEntityCache.invalidateCaches(recordIdsToWipe); mCaseIndexTable.clearCaseIndices(recordIdsToWipe); for (String cid : writeLog.keySet()) { Case c = writeLog.get(cid); mCaseIndexTable.indexCase(c); } db.setTransactionSuccessful(); } finally { db.endTransaction(); } } }