Search in sources :

Example 16 with FormDef

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;
}
Also used : FormDef(org.javarosa.core.model.FormDef) FileInputStream(java.io.FileInputStream) IOException(java.io.IOException) XPathTypeMismatchException(org.javarosa.xpath.XPathTypeMismatchException)

Example 17 with FormDef

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);
            }
        }
    }
}
Also used : XPathExpression(org.javarosa.xpath.expr.XPathExpression) Serializable(java.io.Serializable) XPathPathExpr(org.javarosa.xpath.expr.XPathPathExpr) Cursor(android.database.Cursor) ExternalParamsException(org.odk.collect.android.exception.ExternalParamsException) ExternalParamsException(org.odk.collect.android.exception.ExternalParamsException) InstancesDao(org.odk.collect.android.dao.InstancesDao) FormDef(org.javarosa.core.model.FormDef) XPathNodeset(org.javarosa.xpath.XPathNodeset) EvaluationContext(org.javarosa.core.model.condition.EvaluationContext) FormInstance(org.javarosa.core.model.instance.FormInstance) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Example 18 with FormDef

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();
}
Also used : FormController(org.odk.collect.android.logic.FormController) FormDef(org.javarosa.core.model.FormDef) FormLoaderListener(org.odk.collect.android.listeners.FormLoaderListener) IOException(java.io.IOException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) FormLoaderTask(org.odk.collect.android.tasks.FormLoaderTask)

Example 19 with FormDef

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;
    }
}
Also used : FormDef(org.javarosa.core.model.FormDef) IDataReference(org.javarosa.core.model.IDataReference) ODKIncompleteSubmissionData(org.opendatakit.aggregate.exception.ODKIncompleteSubmissionData) SubmissionProfile(org.javarosa.core.model.SubmissionProfile) FormInstance(org.javarosa.core.model.instance.FormInstance)

Example 20 with FormDef

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();
    }
}
Also used : FormDef(org.javarosa.core.model.FormDef) TreeReference(org.javarosa.core.model.instance.TreeReference)

Aggregations

FormDef (org.javarosa.core.model.FormDef)31 Test (org.junit.Test)10 IOException (java.io.IOException)9 TreeElement (org.javarosa.core.model.instance.TreeElement)7 FormInstance (org.javarosa.core.model.instance.FormInstance)5 File (java.io.File)4 FileInputStream (java.io.FileInputStream)4 EvaluationContext (org.javarosa.core.model.condition.EvaluationContext)4 AbstractTreeElement (org.javarosa.core.model.instance.AbstractTreeElement)4 DataInputStream (java.io.DataInputStream)3 SubmissionProfile (org.javarosa.core.model.SubmissionProfile)3 IAnswerData (org.javarosa.core.model.data.IAnswerData)3 TreeReference (org.javarosa.core.model.instance.TreeReference)3 FormEntryController (org.javarosa.form.api.FormEntryController)3 ParseResult (org.javarosa.xform.parse.FormParserHelper.ParseResult)3 XPathExpression (org.javarosa.xpath.expr.XPathExpression)3 InputStream (java.io.InputStream)2 GroupDef (org.javarosa.core.model.GroupDef)2 IDataReference (org.javarosa.core.model.IDataReference)2 QuestionDef (org.javarosa.core.model.QuestionDef)2