package org.commcare.xml; import java.io.IOException; import java.util.Hashtable; import org.commcare.android.database.user.models.ACase; import org.commcare.android.logic.GlobalConstants; import org.commcare.android.net.HttpRequestGenerator; import org.commcare.cases.ledger.Ledger; import org.commcare.cases.model.Case; import org.commcare.dalvik.application.CommCareApplication; import org.commcare.data.xml.TransactionParser; import org.commcare.data.xml.TransactionParserFactory; import org.commcare.xml.util.InvalidStructureException; import org.commcare.xml.util.UnfullfilledRequirementsException; import org.javarosa.core.model.instance.FormInstance; import org.javarosa.core.services.storage.IStorageUtilityIndexed; import org.javarosa.core.services.storage.StorageManager; import org.kxml2.io.KXmlParser; import org.xmlpull.v1.XmlPullParserException; import android.content.Context; /** * @author ctsims * */ public class CommCareTransactionParserFactory implements TransactionParserFactory { private Context context; private TransactionParserFactory userParser; private TransactionParserFactory caseParser; private TransactionParserFactory stockParser; private TransactionParserFactory formInstanceParser; private TransactionParserFactory fixtureParser; private Hashtable<String, String> formInstanceNamespaces; HttpRequestGenerator generator; int requests = 0; String syncToken; public CommCareTransactionParserFactory(Context context, HttpRequestGenerator generator) { this.context = context; this.generator = generator; fixtureParser = new TransactionParserFactory() { FixtureXmlParser created = null; public TransactionParser getParser(String name, String namespace, KXmlParser parser) { if(created == null) { created = new FixtureXmlParser(parser) { //TODO: store these on the file system instead of in DB? private IStorageUtilityIndexed fixtureStorage; /* * (non-Javadoc) * @see org.commcare.xml.FixtureXmlParser#storage() */ @Override public IStorageUtilityIndexed storage() { if(fixtureStorage == null) { fixtureStorage = CommCareApplication._().getUserStorage("fixture", FormInstance.class); } return fixtureStorage; } }; } return created; } }; } /* (non-Javadoc) * @see org.commcare.data.xml.TransactionParserFactory#getParser(java.lang.String, java.lang.String, org.kxml2.io.KXmlParser) */ public TransactionParser getParser(String name, String namespace, KXmlParser parser) { if(namespace != null && formInstanceNamespaces != null && formInstanceNamespaces.containsKey(namespace)) { req(); return formInstanceParser.getParser(name, namespace, parser); } else if(LedgerXmlParsers.STOCK_XML_NAMESPACE.matches(namespace)) { if(stockParser == null) { throw new RuntimeException("Couldn't process Stock transaction without initialization!"); } req(); return stockParser.getParser(name, namespace, parser); } else if(name != null && name.toLowerCase().equals("case")) { if(caseParser == null) { throw new RuntimeException("Couldn't receive Case transaction without initialization!"); } req(); return caseParser.getParser(name, namespace, parser); } else if(name != null && name.toLowerCase().equals("registration")) { if(userParser == null) { throw new RuntimeException("Couldn't receive User transaction without initialization!"); } req(); return userParser.getParser(name, namespace, parser); } else if(name != null && name.toLowerCase().equals("fixture")) { req(); return fixtureParser.getParser(name, namespace, parser); }else if(name != null && name.toLowerCase().equals("message")) { //server message; //" <message nature=""/>" } else if(name != null && name.toLowerCase().equals("sync") && namespace != null && "http://commcarehq.org/sync".equals(namespace)) { return new TransactionParser<String>(parser, namespace, namespace) { /* * (non-Javadoc) * @see org.commcare.data.xml.TransactionParser#commit(java.lang.Object) */ @Override public void commit(String parsed) throws IOException {} /* * (non-Javadoc) * @see org.commcare.xml.ElementParser#parse() */ @Override public String parse() throws InvalidStructureException, IOException, XmlPullParserException, UnfullfilledRequirementsException { this.checkNode("sync"); this.nextTag("restore_id"); syncToken = parser.nextText(); if(syncToken == null) { throw new InvalidStructureException("Sync block must contain restore_id with valid ID inside!", parser); } syncToken = syncToken.trim(); return syncToken; } }; } return null; } private void req() { requests++; reportProgress(requests); } public void reportProgress(int total) { //nothing } public void initUserParser(final byte[] wrappedKey) { userParser = new TransactionParserFactory() { UserXmlParser created = null; public TransactionParser getParser(String name, String namespace, KXmlParser parser) { if(created == null) { created = new UserXmlParser(parser, context, wrappedKey); } return created; } }; } public void initCaseParser() { final int[] tallies = new int[3]; caseParser = new TransactionParserFactory() { CaseXmlParser created = null; public TransactionParser<Case> getParser(String name, String namespace, KXmlParser parser) { if(created == null) { created = new AndroidCaseXmlParser(parser, tallies, true, CommCareApplication._().getUserStorage(ACase.STORAGE_KEY, ACase.class), generator); } return created; } }; } public void initStockParser() { stockParser = new TransactionParserFactory() { public TransactionParser<Ledger[]> getParser(String name, String namespace, KXmlParser parser) { return new LedgerXmlParsers(parser, CommCareApplication._().getUserStorage(Ledger.STORAGE_KEY, Ledger.class)); } }; } public void initFormInstanceParser(Hashtable<String, String> namespaces) { this.formInstanceNamespaces = namespaces; formInstanceParser = new TransactionParserFactory() { FormInstanceXmlParser created = null; public TransactionParser getParser(String name, String namespace, KXmlParser parser) { if(created == null) { //TODO: We really don't wanna keep using fsPath eventually created = new FormInstanceXmlParser(parser, context, formInstanceNamespaces, CommCareApplication._().getCurrentApp().fsPath(GlobalConstants.FILE_CC_FORMS)); } return created; } }; } public String getSyncToken() { return syncToken; } }