package org.commcare.xml; import android.content.Context; import org.commcare.CommCareApplication; import org.commcare.android.database.user.models.ACase; import org.commcare.core.parse.CommCareTransactionParserFactory; import org.commcare.data.xml.TransactionParser; import org.commcare.data.xml.TransactionParserFactory; import org.commcare.interfaces.HttpRequestEndpoints; import org.commcare.models.database.AndroidSandbox; import org.commcare.models.database.SqlStorage; import org.commcare.preferences.DeveloperPreferences; import org.commcare.utils.GlobalConstants; import org.kxml2.io.KXmlParser; import java.util.ArrayList; import java.util.Collections; import java.util.Hashtable; /** * The CommCare Transaction Parser Factory wraps all of the current * transactions that CommCare knows about, and provides the appropriate hooks * for parsing through XML and dispatching the right handler for each * transaction. * * It should be the central point of processing for transactions (eliminating * the use of the old datamodel based processors) and should be used in any * situation where a transaction is expected to be present. * * It is expected to behave more or less as a black box, in that it directly * creates/modifies the data models on the system, rather than producing them * for another layer or processing. * * @author ctsims */ public class AndroidTransactionParserFactory extends CommCareTransactionParserFactory { final private Context context; final private HttpRequestEndpoints generator; final private ArrayList<String> createdAndUpdatedCases = new ArrayList<>(); private TransactionParserFactory formInstanceParser; private boolean caseIndexesWereDisrupted = false; /** * A mapping from an installed form's namespace its install path. */ private Hashtable<String, String> formInstanceNamespaces; public AndroidTransactionParserFactory(Context context, HttpRequestEndpoints generator) { super(new AndroidSandbox(CommCareApplication.instance()), DeveloperPreferences.isBulkPerformanceEnabled()); this.context = context; this.generator = generator; } @Override public TransactionParser getParser(KXmlParser parser) { String namespace = parser.getNamespace(); if (namespace != null && formInstanceNamespaces != null && formInstanceNamespaces.containsKey(namespace)) { req(); return formInstanceParser.getParser(parser); } return super.getParser(parser); } /* * need to override to use the Android User class */ public void initUserParser(final byte[] wrappedKey) { userParser = new TransactionParserFactory() { AndroidUserXmlParser created = null; @Override public TransactionParser getParser(KXmlParser parser) { if (created == null) { created = new AndroidUserXmlParser(parser, sandbox.getUserStorage(), wrappedKey); } return created; } }; } public ArrayList<String> getCreatedAndUpdatedCases() { return createdAndUpdatedCases; } /** * Used to load Saved Forms from HQ into our local file system * * @param namespaces A mapping from an installed form's namespace its install path. */ public void initFormInstanceParser(Hashtable<String, String> namespaces) { this.formInstanceNamespaces = namespaces; formInstanceParser = new TransactionParserFactory() { FormInstanceXmlParser created = null; @Override public TransactionParser getParser(KXmlParser parser) { if (created == null) { //TODO: We really don't wanna keep using fsPath eventually created = new FormInstanceXmlParser(parser, context, Collections.unmodifiableMap(formInstanceNamespaces), CommCareApplication.instance().getCurrentApp().fsPath(GlobalConstants.FILE_CC_FORMS)); } return created; } }; } public boolean wereCaseIndexesDisrupted() { return caseIndexesWereDisrupted; } @Override public TransactionParserFactory getNormalCaseParser() { return new TransactionParserFactory() { AndroidCaseXmlParser created = null; @Override public AndroidCaseXmlParser getParser(KXmlParser parser) { if (created == null) { created = new AndroidCaseXmlParser(parser, true, (SqlStorage<ACase>)sandbox.getCaseStorage(), generator) { @Override public void onIndexDisrupted(String caseId) { caseIndexesWereDisrupted = true; } @Override protected void onCaseCreateUpdate(String caseId) { createdAndUpdatedCases.add(caseId); } }; } return created; } }; } @Override public TransactionParserFactory getBulkCaseParser() { return new TransactionParserFactory() { AndroidBulkCaseXmlParser created = null; @Override public AndroidBulkCaseXmlParser getParser(KXmlParser parser) { if (created == null) { created = new AndroidBulkCaseXmlParser(parser, (SqlStorage<ACase>)sandbox.getCaseStorage(), generator) { @Override public void onIndexDisrupted(String caseId) { caseIndexesWereDisrupted = true; } @Override protected void onCaseCreateUpdate(String caseId) { createdAndUpdatedCases.add(caseId); } }; } return created; } }; } }