use of org.javarosa.core.model.FormDef in project collect by opendatakit.
the class FormLoaderTask method createFormDefFromCacheOrXml.
private FormDef createFormDefFromCacheOrXml(File formXml) {
publishProgress(Collect.getInstance().getString(R.string.survey_loading_reading_form_message));
final FormDef formDefFromCache = FormDefCache.readCache(formXml);
if (formDefFromCache != null) {
return formDefFromCache;
}
FileInputStream fis = null;
// no binary, read from xml
try {
Timber.i("Attempting to load from: %s", formXml.getAbsolutePath());
final long start = System.currentTimeMillis();
fis = new FileInputStream(formXml);
FormDef formDefFromXml = XFormUtils.getFormFromInputStream(fis);
if (formDefFromXml == null) {
errorMsg = "Error reading XForm file";
} else {
Timber.i("Loaded in %.3f seconds.", (System.currentTimeMillis() - start) / 1000F);
formDef = formDefFromXml;
return formDefFromXml;
}
} catch (Exception e) {
Timber.e(e);
errorMsg = e.getMessage();
} finally {
IOUtils.closeQuietly(fis);
}
return null;
}
use of org.javarosa.core.model.FormDef in project collect by opendatakit.
the class ExternalAppsUtils method populateParameters.
public static void populateParameters(Intent intent, Map<String, String> exParams, TreeReference reference) throws ExternalParamsException {
FormDef formDef = Collect.getInstance().getFormController().getFormDef();
FormInstance formInstance = formDef.getInstance();
EvaluationContext evaluationContext = new EvaluationContext(formDef.getEvaluationContext(), reference);
if (exParams != null) {
for (Map.Entry<String, String> paramEntry : exParams.entrySet()) {
String paramEntryValue = paramEntry.getValue();
try {
Object result;
if (paramEntryValue.startsWith("'")) {
// but not require an ending quote
if (paramEntryValue.endsWith("'")) {
result = paramEntryValue.substring(1, paramEntryValue.length() - 1);
} else {
result = paramEntryValue.substring(1, paramEntryValue.length());
}
} else if (paramEntryValue.startsWith("/")) {
// treat this is an xpath
XPathPathExpr pathExpr = XPathReference.getPathExpr(paramEntryValue);
XPathNodeset xpathNodeset = pathExpr.eval(formInstance, evaluationContext);
result = XPathFuncExpr.unpack(xpathNodeset);
} else if (paramEntryValue.equals("instanceProviderID()")) {
// instanceProviderID returns -1 if the current instance has not been
// saved to disk already
String path = Collect.getInstance().getFormController().getInstanceFile().getAbsolutePath();
String instanceProviderID = "-1";
Cursor c = new InstancesDao().getInstancesCursorForFilePath(path);
if (c != null && c.getCount() > 0) {
// should only ever be one
c.moveToFirst();
instanceProviderID = c.getString(c.getColumnIndex(InstanceColumns._ID));
}
if (c != null) {
c.close();
}
result = instanceProviderID;
} else {
// treat this is a function
XPathExpression xpathExpression = XPathParseTool.parseXPath(paramEntryValue);
result = xpathExpression.eval(formInstance, evaluationContext);
}
if (result != null && result instanceof Serializable) {
intent.putExtra(paramEntry.getKey(), (Serializable) result);
}
} catch (Exception e) {
throw new ExternalParamsException("Could not evaluate '" + paramEntryValue + "'", e);
}
}
}
}
use of org.javarosa.core.model.FormDef in project collect by opendatakit.
the class FormNavigationTestCase method testIndices.
private void testIndices(String formName, String[] expectedIndices) throws ExecutionException, InterruptedException {
try {
copyToSdCard(formName);
} catch (IOException e) {
Timber.i(e);
}
FormLoaderTask formLoaderTask = new FormLoaderTask(formPath(formName), null, null);
formLoaderTask.setFormLoaderListener(new FormLoaderListener() {
@Override
public void loadingComplete(FormLoaderTask task, FormDef fd) {
try {
// form and then swiping back once. Verify the expected indices before and after each swipe.
for (int i = 0; i < expectedIndices.length - 1; i++) {
FormController formController = task.getFormController();
// check the current index
assertEquals(expectedIndices[i], formController.getFormIndex().toString());
if (i < expectedIndices.length - 2) {
formController.stepToNextScreenEvent();
} else {
formController.stepToPreviousScreenEvent();
}
// check the index again after navigating
assertEquals(expectedIndices[i + 1], formController.getFormIndex().toString());
}
} catch (Exception e) {
Timber.i(e);
}
}
@Override
public void loadingError(String errorMsg) {
}
@Override
public void onProgressStep(String stepMessage) {
}
});
formLoaderTask.execute(formPath(formName)).get();
}
use of org.javarosa.core.model.FormDef in project briefcase by opendatakit.
the class BaseFormParserForJavaRosa method compareXml.
/**
* Compare two XML files to assess their level of structural difference (if
* any).
*
* @param incomingParser -- parsed version of incoming form
* @param existingXml -- the existing Xml for this form
* @return XFORMS_SHARE_INSTANCE when bodies differ but instances and bindings
* are identical; XFORMS_SHARE_SCHEMA when bodies and/or bindings
* differ, but database structure remains unchanged; XFORMS_DIFFERENT
* when forms are different enough to affect database structure and/or
* encryption.
* @throws ODKIncompleteSubmissionData
*/
public static DifferenceResult compareXml(BaseFormParserForJavaRosa incomingParser, String existingXml, String existingTitle, boolean isWithinUpdateWindow) throws ODKIncompleteSubmissionData {
if (incomingParser == null || existingXml == null) {
throw new ODKIncompleteSubmissionData(Reason.MISSING_XML);
}
// generally only the case within Briefcase
if (incomingParser.xml.equals(existingXml)) {
return DifferenceResult.XFORMS_IDENTICAL;
}
// parse XML
FormDef formDef1;
FormDef formDef2;
BaseFormParserForJavaRosa existingParser = new BaseFormParserForJavaRosa(existingXml, existingTitle, true);
formDef1 = incomingParser.rootJavaRosaFormDef;
formDef2 = existingParser.rootJavaRosaFormDef;
if (formDef1 == null || formDef2 == null) {
throw new ODKIncompleteSubmissionData("Javarosa failed to construct a FormDef. Is this an XForm definition?", Reason.BAD_JR_PARSE);
}
// check that the version is advancing from the earlier
// form upload. The comparison is string-based, not
// numeric-based (OpenRosa compliance). The recommended
// version format is: yyyymmddnn e.g., 2012060100
String ivs = incomingParser.rootElementDefn.versionString;
if (ivs == null) {
// if we are changing the file, the new file must have a version string
return DifferenceResult.XFORMS_MISSING_VERSION;
}
String evs = existingParser.rootElementDefn.versionString;
boolean modelVersionSame = (incomingParser.rootElementDefn.modelVersion == null) ? (existingParser.rootElementDefn.modelVersion == null) : incomingParser.rootElementDefn.modelVersion.equals(existingParser.rootElementDefn.modelVersion);
boolean isEarlierVersion = false;
if (!(evs == null || (modelVersionSame && ivs.length() > evs.length()) || (!modelVersionSame && ivs.compareTo(evs) > 0))) {
// disallow updates if none of the following applies:
// (1) if the existing form does not have a version (the new one does).
// (2) if the existing form and new form have the same model version
// and the new form has more leading zeros.
// (3) if the existing form and new form have different model versions
// and the new version string is lexically greater than the old one.
isEarlierVersion = true;
return DifferenceResult.XFORMS_EARLIER_VERSION;
}
/*
* Changes in encryption (either on or off, or change in key) are a major
* change. We could allow the public key to be revised, but most users won't
* understand that this is possible or know how to do it.
*
* Ignore whether a submission profile is present or absent provided it does
* not affect encryption or change the portion of the form being returned.
*/
SubmissionProfile subProfile1 = formDef1.getSubmissionProfile();
SubmissionProfile subProfile2 = formDef2.getSubmissionProfile();
if (subProfile1 != null && subProfile2 != null) {
// we have two profiles -- check that any encryption key matches...
String publicKey1 = subProfile1.getAttribute(BASE64_RSA_PUBLIC_KEY);
String publicKey2 = subProfile2.getAttribute(BASE64_RSA_PUBLIC_KEY);
if (publicKey1 != null && publicKey2 != null) {
// both have encryption
if (!publicKey1.equals(publicKey2)) {
// keys differ
return (DifferenceResult.XFORMS_DIFFERENT);
}
} else if (publicKey1 != null || publicKey2 != null) {
// one or the other has encryption (and the other doesn't)...
return (DifferenceResult.XFORMS_DIFFERENT);
}
// get the TreeElement (e1, e2) that identifies the portion of the form
// that will be submitted to Aggregate.
IDataReference r;
r = subProfile1.getRef();
AbstractTreeElement<?> e1 = (r != null) ? formDef1.getInstance().resolveReference(r) : null;
r = subProfile2.getRef();
AbstractTreeElement<?> e2 = (r != null) ? formDef2.getInstance().resolveReference(r) : null;
if (e1 != null && e2 != null) {
// Ignore all namespace differences (Aggregate ignores them)...
while (e1 != null && e2 != null) {
if (!e1.getName().equals(e2.getName())) {
return (DifferenceResult.XFORMS_DIFFERENT);
}
e1 = e1.getParent();
e2 = e2.getParent();
}
if (e1 != null || e2 != null) {
// they should both terminate at the same time...
return (DifferenceResult.XFORMS_DIFFERENT);
}
// we may still have differences, but if the overall form
// is identical, we are golden...
} else if (e1 != null || e2 != null) {
// one returns a portion of the form and the other doesn't
return (DifferenceResult.XFORMS_DIFFERENT);
}
} else if (subProfile1 != null) {
if (subProfile1.getAttribute(BASE64_RSA_PUBLIC_KEY) != null) {
// xml1 does encryption, the other doesn't
return (DifferenceResult.XFORMS_DIFFERENT);
}
IDataReference r = subProfile1.getRef();
if (r != null && formDef1.getInstance().resolveReference(r) != null) {
// xml1 returns a portion of the form, the other doesn't
return (DifferenceResult.XFORMS_DIFFERENT);
}
} else if (subProfile2 != null) {
if (subProfile2.getAttribute(BASE64_RSA_PUBLIC_KEY) != null) {
// xml2 does encryption, the other doesn't
return (DifferenceResult.XFORMS_DIFFERENT);
}
IDataReference r = subProfile2.getRef();
if (r != null && formDef2.getInstance().resolveReference(r) != null) {
// xml2 returns a portion of the form, the other doesn't
return (DifferenceResult.XFORMS_DIFFERENT);
}
}
// get data model to compare instances
FormInstance dataModel1 = formDef1.getInstance();
FormInstance dataModel2 = formDef2.getInstance();
if (dataModel1 == null || dataModel2 == null) {
throw new ODKIncompleteSubmissionData("Javarosa failed to construct a FormInstance. Is this an XForm definition?", Reason.BAD_JR_PARSE);
}
// return result of element-by-element instance/binding comparison
DifferenceResult rc = compareTreeElements(dataModel1.getRoot(), incomingParser, dataModel2.getRoot(), existingParser);
if (DifferenceResult.XFORMS_DIFFERENT == rc) {
return rc;
} else if (isEarlierVersion) {
return DifferenceResult.XFORMS_EARLIER_VERSION;
} else {
return rc;
}
}
use of org.javarosa.core.model.FormDef in project javarosa by opendatakit.
the class XFormParser method getFormElementRef.
private TreeReference getFormElementRef(IFormElement fe) {
if (fe instanceof FormDef) {
TreeReference ref = TreeReference.rootRef();
ref.add(mainInstanceNode.getName(), 0);
return ref;
} else {
return (TreeReference) fe.getBind().getReference();
}
}
Aggregations