Search in sources :

Example 36 with Element

use of org.kxml2.kdom.Element in project briefcase by opendatakit.

the class XmlManipulationUtils method findMetaTag.

/**
 * Traverse submission looking for OpenRosa metadata tag (with or without
 * namespace).
 *
 * @param parent
 * @return
 */
private static Element findMetaTag(Element parent, String rootUri) {
    for (int i = 0; i < parent.getChildCount(); ++i) {
        if (parent.getType(i) == Node.ELEMENT) {
            Element child = parent.getElement(i);
            String cnUri = child.getNamespace();
            String cnName = child.getName();
            if (cnName.equals(OPEN_ROSA_METADATA_TAG) && (cnUri == null || cnUri.equals(EMPTY_STRING) || cnUri.equals(rootUri) || cnUri.equalsIgnoreCase(OPEN_ROSA_NAMESPACE) || cnUri.equalsIgnoreCase(OPEN_ROSA_NAMESPACE_SLASH) || cnUri.equalsIgnoreCase(OPEN_ROSA_NAMESPACE_PRELIM))) {
                return child;
            } else {
                Element descendent = findMetaTag(child, rootUri);
                if (descendent != null)
                    return descendent;
            }
        }
    }
    return null;
}
Also used : Element(org.kxml2.kdom.Element)

Example 37 with Element

use of org.kxml2.kdom.Element in project briefcase by opendatakit.

the class XmlManipulationUtils method parseFormManifestResponse.

public static final List<MediaFile> parseFormManifestResponse(boolean isOpenRosaResponse, Document doc) throws ParsingException {
    List<MediaFile> files = new ArrayList<>();
    if (!isOpenRosaResponse) {
        log.error("Manifest reply doesn't report an OpenRosa version -- bad server?");
        throw new ParsingException(BAD_NOT_OPENROSA_MANIFEST);
    }
    // Attempt OpenRosa 1.0 parsing
    Element manifestElement = doc.getRootElement();
    if (!manifestElement.getName().equals("manifest")) {
        log.error("Root element is not <manifest> -- was " + manifestElement.getName());
        throw new ParsingException(BAD_NOT_OPENROSA_MANIFEST);
    }
    String namespace = manifestElement.getNamespace();
    if (!isXformsManifestNamespacedElement(manifestElement)) {
        log.error("Root element Namespace is incorrect: " + namespace);
        throw new ParsingException(BAD_NOT_OPENROSA_MANIFEST);
    }
    int nElements = manifestElement.getChildCount();
    for (int i = 0; i < nElements; ++i) {
        if (manifestElement.getType(i) != Element.ELEMENT) {
            // e.g., whitespace (text)
            continue;
        }
        Element mediaFileElement = (Element) manifestElement.getElement(i);
        if (!isXformsManifestNamespacedElement(mediaFileElement)) {
            // someone else's extension?
            continue;
        }
        String name = mediaFileElement.getName();
        if (name.equalsIgnoreCase("mediaFile")) {
            String filename = null;
            String hash = null;
            String downloadUrl = null;
            // don't process descriptionUrl
            int childCount = mediaFileElement.getChildCount();
            for (int j = 0; j < childCount; ++j) {
                if (mediaFileElement.getType(j) != Element.ELEMENT) {
                    // e.g., whitespace (text)
                    continue;
                }
                Element child = mediaFileElement.getElement(j);
                if (!isXformsManifestNamespacedElement(child)) {
                    // someone else's extension?
                    continue;
                }
                String tag = child.getName();
                if (tag.equals("filename")) {
                    filename = XFormParser.getXMLText(child, true);
                    if (filename != null && filename.length() == 0) {
                        filename = null;
                    }
                } else if (tag.equals("hash")) {
                    hash = XFormParser.getXMLText(child, true);
                    if (hash != null && hash.length() == 0) {
                        hash = null;
                    }
                } else if (tag.equals("downloadUrl")) {
                    downloadUrl = XFormParser.getXMLText(child, true);
                    if (downloadUrl != null && downloadUrl.length() == 0) {
                        downloadUrl = null;
                    }
                }
            }
            if (filename == null || downloadUrl == null || hash == null) {
                log.error("Manifest entry " + Integer.toString(i) + " is missing one or more tags: filename, hash, or downloadUrl");
                throw new ParsingException(BAD_NOT_OPENROSA_MANIFEST);
            }
            files.add(new MediaFile(filename, hash, downloadUrl));
        }
    }
    return files;
}
Also used : MediaFile(org.opendatakit.briefcase.util.ServerFetcher.MediaFile) ParsingException(org.opendatakit.briefcase.model.ParsingException) Element(org.kxml2.kdom.Element) ArrayList(java.util.ArrayList)

Example 38 with Element

use of org.kxml2.kdom.Element in project briefcase by opendatakit.

the class XmlManipulationUtils method parseDownloadSubmissionResponse.

public static final SubmissionManifest parseDownloadSubmissionResponse(Document doc) throws ParsingException {
    // and parse the document...
    List<MediaFile> attachmentList = new ArrayList<>();
    Element rootSubmissionElement = null;
    String instanceID = null;
    // Attempt parsing
    Element submissionElement = doc.getRootElement();
    if (!submissionElement.getName().equals("submission")) {
        String msg = "Parsing downloadSubmission reply -- root element is not <submission> :" + submissionElement.getName();
        log.error(msg);
        throw new ParsingException(msg);
    }
    String namespace = submissionElement.getNamespace();
    if (!namespace.equalsIgnoreCase(NAMESPACE_OPENDATAKIT_ORG_SUBMISSIONS)) {
        String msg = "Parsing downloadSubmission reply -- root element namespace is incorrect:" + namespace;
        log.error(msg);
        throw new ParsingException(msg);
    }
    int nElements = submissionElement.getChildCount();
    for (int i = 0; i < nElements; ++i) {
        if (submissionElement.getType(i) != Element.ELEMENT) {
            // e.g., whitespace (text)
            continue;
        }
        Element subElement = (Element) submissionElement.getElement(i);
        namespace = subElement.getNamespace();
        if (!namespace.equalsIgnoreCase(NAMESPACE_OPENDATAKIT_ORG_SUBMISSIONS)) {
            // someone else's extension?
            continue;
        }
        String name = subElement.getName();
        if (name.equalsIgnoreCase("data")) {
            // find the root submission element and get its instanceID attribute
            int nIdElements = subElement.getChildCount();
            for (int j = 0; j < nIdElements; ++j) {
                if (subElement.getType(j) != Element.ELEMENT) {
                    // e.g., whitespace (text)
                    continue;
                }
                rootSubmissionElement = (Element) subElement.getElement(j);
                break;
            }
            if (rootSubmissionElement == null) {
                throw new ParsingException("no submission body found in submissionDownload response");
            }
            instanceID = rootSubmissionElement.getAttributeValue(null, "instanceID");
            if (instanceID == null) {
                throw new ParsingException("instanceID attribute value is null");
            }
        } else if (name.equalsIgnoreCase("mediaFile")) {
            int nIdElements = subElement.getChildCount();
            String filename = null;
            String hash = null;
            String downloadUrl = null;
            for (int j = 0; j < nIdElements; ++j) {
                if (subElement.getType(j) != Element.ELEMENT) {
                    // e.g., whitespace (text)
                    continue;
                }
                Element mediaSubElement = (Element) subElement.getElement(j);
                name = mediaSubElement.getName();
                if (name.equalsIgnoreCase("filename")) {
                    filename = XFormParser.getXMLText(mediaSubElement, true);
                } else if (name.equalsIgnoreCase("hash")) {
                    hash = XFormParser.getXMLText(mediaSubElement, true);
                } else if (name.equalsIgnoreCase("downloadUrl")) {
                    downloadUrl = XFormParser.getXMLText(mediaSubElement, true);
                }
            }
            attachmentList.add(new MediaFile(filename, hash, downloadUrl));
        } else {
            log.warn("Unrecognized tag inside submission: " + name);
        }
    }
    if (rootSubmissionElement == null) {
        throw new ParsingException("No submission body found");
    }
    if (instanceID == null) {
        throw new ParsingException("instanceID attribute value is null");
    }
    // write submission to a string
    StringWriter fo = new StringWriter();
    KXmlSerializer serializer = new KXmlSerializer();
    serializer.setOutput(fo);
    // setting the response content type emits the xml header.
    // just write the body here...
    // this has the xmlns of the submissions download, indicating that it
    // originated from a briefcase download. Might be useful for discriminating
    // real vs. recovered data?
    rootSubmissionElement.setPrefix(null, NAMESPACE_OPENDATAKIT_ORG_SUBMISSIONS);
    try {
        rootSubmissionElement.write(serializer);
        serializer.flush();
        serializer.endDocument();
        fo.close();
    } catch (IOException e) {
        String msg = "Unexpected IOException";
        log.error(msg, e);
        throw new ParsingException(msg + ": " + e.getMessage());
    }
    return new SubmissionManifest(instanceID, fo.toString(), attachmentList);
}
Also used : MediaFile(org.opendatakit.briefcase.util.ServerFetcher.MediaFile) StringWriter(java.io.StringWriter) Element(org.kxml2.kdom.Element) ParsingException(org.opendatakit.briefcase.model.ParsingException) ArrayList(java.util.ArrayList) SubmissionManifest(org.opendatakit.briefcase.util.ServerFetcher.SubmissionManifest) IOException(java.io.IOException) KXmlSerializer(org.kxml2.io.KXmlSerializer)

Example 39 with Element

use of org.kxml2.kdom.Element in project briefcase by opendatakit.

the class XmlManipulationUtils method parseFormListResponse.

public static final List<RemoteFormDefinition> parseFormListResponse(boolean isOpenRosaResponse, Document formListDoc) throws ParsingException {
    // This gets a list of available forms from the specified server.
    List<RemoteFormDefinition> formList = new ArrayList<>();
    if (isOpenRosaResponse) {
        // Attempt OpenRosa 1.0 parsing
        Element xformsElement = formListDoc.getRootElement();
        if (!xformsElement.getName().equals("xforms")) {
            log.error("Parsing OpenRosa reply -- root element is not <xforms> :" + xformsElement.getName());
            throw new ParsingException(BAD_OPENROSA_FORMLIST);
        }
        String namespace = xformsElement.getNamespace();
        if (!isXformsListNamespacedElement(xformsElement)) {
            log.error("Parsing OpenRosa reply -- root element namespace is incorrect:" + namespace);
            throw new ParsingException(BAD_OPENROSA_FORMLIST);
        }
        int nElements = xformsElement.getChildCount();
        for (int i = 0; i < nElements; ++i) {
            if (xformsElement.getType(i) != Element.ELEMENT) {
                // e.g., whitespace (text)
                continue;
            }
            Element xformElement = (Element) xformsElement.getElement(i);
            if (!isXformsListNamespacedElement(xformElement)) {
                // someone else's extension?
                continue;
            }
            String name = xformElement.getName();
            if (!name.equalsIgnoreCase("xform")) {
                // someone else's extension?
                continue;
            }
            // this is something we know how to interpret
            String formId = null;
            String formName = null;
            String version = null;
            String majorMinorVersion = null;
            String description = null;
            String downloadUrl = null;
            String manifestUrl = null;
            // don't process descriptionUrl
            int fieldCount = xformElement.getChildCount();
            for (int j = 0; j < fieldCount; ++j) {
                if (xformElement.getType(j) != Element.ELEMENT) {
                    // whitespace
                    continue;
                }
                Element child = xformElement.getElement(j);
                if (!isXformsListNamespacedElement(child)) {
                    // someone else's extension?
                    continue;
                }
                String tag = child.getName();
                if (tag.equals("formID")) {
                    formId = XFormParser.getXMLText(child, true);
                    if (formId != null && formId.length() == 0) {
                        formId = null;
                    }
                } else if (tag.equals("name")) {
                    formName = XFormParser.getXMLText(child, true);
                    if (formName != null && formName.length() == 0) {
                        formName = null;
                    }
                } else if (tag.equals("version")) {
                    version = XFormParser.getXMLText(child, true);
                    if (version != null && version.length() == 0) {
                        version = null;
                    }
                } else if (tag.equals("majorMinorVersion")) {
                    majorMinorVersion = XFormParser.getXMLText(child, true);
                    if (majorMinorVersion != null && majorMinorVersion.length() == 0) {
                        majorMinorVersion = null;
                    }
                } else if (tag.equals("descriptionText")) {
                    description = XFormParser.getXMLText(child, true);
                    if (description != null && description.length() == 0) {
                        description = null;
                    }
                } else if (tag.equals("downloadUrl")) {
                    downloadUrl = XFormParser.getXMLText(child, true);
                    if (downloadUrl != null && downloadUrl.length() == 0) {
                        downloadUrl = null;
                    }
                } else if (tag.equals("manifestUrl")) {
                    manifestUrl = XFormParser.getXMLText(child, true);
                    if (manifestUrl != null && manifestUrl.length() == 0) {
                        manifestUrl = null;
                    }
                }
            }
            if (formId == null || downloadUrl == null || formName == null) {
                log.error("Parsing OpenRosa reply -- Forms list entry " + Integer.toString(i) + " is missing one or more tags: formId, name, or downloadUrl");
                formList.clear();
                throw new ParsingException(BAD_OPENROSA_FORMLIST);
            }
            String versionString = null;
            if (version != null && version.length() != 0) {
                versionString = version;
            } else if (majorMinorVersion != null && majorMinorVersion.length() != 0) {
                int idx = majorMinorVersion.indexOf(".");
                if (idx == -1) {
                    versionString = majorMinorVersion;
                } else {
                    versionString = majorMinorVersion.substring(0, idx);
                }
            }
            try {
                if (versionString != null) {
                    // verify that  the version string is a long integer value...
                    Long.parseLong(versionString);
                }
            } catch (Exception e) {
                log.error("Parsing OpenRosa reply -- Forms list entry " + Integer.toString(i) + " has an invalid version string: " + versionString, e);
                formList.clear();
                throw new ParsingException(BAD_OPENROSA_FORMLIST);
            }
            formList.add(new RemoteFormDefinition(formName, formId, versionString, downloadUrl, manifestUrl));
        }
    } else {
        // Aggregate 0.9.x mode...
        // populate HashMap with form names and urls
        Element formsElement = formListDoc.getRootElement();
        int formsCount = formsElement.getChildCount();
        for (int i = 0; i < formsCount; ++i) {
            if (formsElement.getType(i) != Element.ELEMENT) {
                // whitespace
                continue;
            }
            Element child = formsElement.getElement(i);
            String tag = child.getName();
            if (tag.equalsIgnoreCase("form")) {
                String formName = XFormParser.getXMLText(child, true);
                if (formName != null && formName.length() == 0) {
                    formName = null;
                }
                String downloadUrl = child.getAttributeValue(null, "url");
                downloadUrl = downloadUrl.trim();
                if (downloadUrl != null && downloadUrl.length() == 0) {
                    downloadUrl = null;
                }
                if (downloadUrl == null || formName == null) {
                    log.error("Parsing OpenRosa reply -- Forms list entry " + Integer.toString(i) + " is missing form name or url attribute");
                    formList.clear();
                    throw new ParsingException(BAD_LEGACY_FORMLIST);
                }
                // Since this is ODK Aggregate 0.9.8 or higher, we know that the
                // formId is
                // given as a parameter of the URL...
                String formId = null;
                try {
                    URL url = new URL(downloadUrl);
                    String qs = url.getQuery();
                    if (qs.startsWith(ODK_ID_PARAMETER_EQUALS)) {
                        formId = qs.substring(ODK_ID_PARAMETER_EQUALS.length());
                    }
                } catch (MalformedURLException e) {
                    log.warn("bad download url", e);
                }
                if (formId == null) {
                    throw new ParsingException("Unable to extract formId from download URL of legacy 0.9.8 server");
                }
                formList.add(new RemoteFormDefinition(formName, formId, null, downloadUrl, null));
            }
        }
    }
    return formList;
}
Also used : MalformedURLException(java.net.MalformedURLException) RemoteFormDefinition(org.opendatakit.briefcase.model.RemoteFormDefinition) Element(org.kxml2.kdom.Element) ParsingException(org.opendatakit.briefcase.model.ParsingException) ArrayList(java.util.ArrayList) FileSystemException(org.opendatakit.briefcase.model.FileSystemException) CannotFixXMLException(org.opendatakit.briefcase.model.CannotFixXMLException) MalformedURLException(java.net.MalformedURLException) IOException(java.io.IOException) MetadataUpdateException(org.opendatakit.briefcase.model.MetadataUpdateException) FileNotFoundException(java.io.FileNotFoundException) XmlPullParserException(org.xmlpull.v1.XmlPullParserException) ParsingException(org.opendatakit.briefcase.model.ParsingException) URL(java.net.URL)

Example 40 with Element

use of org.kxml2.kdom.Element in project briefcase by opendatakit.

the class XmlManipulationUtils method updateSubmissionMetadata.

public static final String updateSubmissionMetadata(File submissionFile, Document doc) throws MetadataUpdateException {
    Element root = doc.getRootElement();
    Element metadata = root.getElement(NAMESPACE_ODK, "submissionMetadata");
    // and get the instanceID and submissionDate from the metadata.
    // we need to put that back into the instance file if not already present
    String instanceID = metadata.getAttributeValue("", INSTANCE_ID_ATTRIBUTE_NAME);
    String submissionDate = metadata.getAttributeValue("", SUBMISSION_DATE_ATTRIBUTE_NAME);
    // read the original document...
    Document originalDoc = null;
    try {
        FileInputStream fs = new FileInputStream(submissionFile);
        InputStreamReader fr = new InputStreamReader(fs, "UTF-8");
        originalDoc = new Document();
        KXmlParser parser = new KXmlParser();
        parser.setInput(fr);
        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
        originalDoc.parse(parser);
        fr.close();
        fs.close();
    } catch (IOException e) {
        String msg = "Original submission file could not be opened";
        log.error(msg, e);
        throw new MetadataUpdateException(msg);
    } catch (XmlPullParserException e) {
        String msg = "Original submission file could not be parsed as XML file";
        log.error(msg, e);
        throw new MetadataUpdateException(msg);
    }
    // determine whether it has the attributes already added.
    // if they are already there, they better match the values returned by
    // Aggregate 1.0
    boolean hasInstanceID = false;
    boolean hasSubmissionDate = false;
    root = originalDoc.getRootElement();
    for (int i = 0; i < root.getAttributeCount(); ++i) {
        String name = root.getAttributeName(i);
        if (name.equals(INSTANCE_ID_ATTRIBUTE_NAME)) {
            if (!root.getAttributeValue(i).equals(instanceID)) {
                String msg = "Original submission file's instanceID does not match that on server!";
                log.error(msg);
                throw new MetadataUpdateException(msg);
            } else {
                hasInstanceID = true;
            }
        }
        if (name.equals(SUBMISSION_DATE_ATTRIBUTE_NAME)) {
            Date oldDate = WebUtils.parseDate(submissionDate);
            String returnDate = root.getAttributeValue(i);
            Date newDate = WebUtils.parseDate(returnDate);
            // cross-platform datetime resolution is 1 second.
            if (Math.abs(newDate.getTime() - oldDate.getTime()) > 1000L) {
                String msg = "Original submission file's submissionDate does not match that on server!";
                log.error(msg);
                throw new MetadataUpdateException(msg);
            } else {
                hasSubmissionDate = true;
            }
        }
    }
    if (hasInstanceID && hasSubmissionDate) {
        log.info("submission already has instanceID and submissionDate attributes: " + submissionFile.getAbsolutePath());
        return instanceID;
    }
    if (!hasInstanceID) {
        root.setAttribute("", INSTANCE_ID_ATTRIBUTE_NAME, instanceID);
    }
    if (!hasSubmissionDate) {
        root.setAttribute("", SUBMISSION_DATE_ATTRIBUTE_NAME, submissionDate);
    }
    // and write out the changes...
    // write the file out...
    File revisedFile = new File(submissionFile.getParentFile(), "." + submissionFile.getName());
    try {
        FileOutputStream fos = new FileOutputStream(revisedFile, false);
        KXmlSerializer serializer = new KXmlSerializer();
        serializer.setOutput(fos, "UTF-8");
        originalDoc.write(serializer);
        serializer.flush();
        fos.close();
        // and swap files...
        boolean restoreTemp = false;
        File temp = new File(submissionFile.getParentFile(), ".back." + submissionFile.getName());
        try {
            if (temp.exists()) {
                if (!temp.delete()) {
                    String msg = "Unable to remove temporary submission backup file";
                    log.error(msg);
                    throw new MetadataUpdateException(msg);
                }
            }
            if (!submissionFile.renameTo(temp)) {
                String msg = "Unable to rename submission to temporary submission backup file";
                log.error(msg);
                throw new MetadataUpdateException(msg);
            }
            // recovery is possible...
            restoreTemp = true;
            if (!revisedFile.renameTo(submissionFile)) {
                String msg = "Original submission file could not be updated";
                log.error(msg);
                throw new MetadataUpdateException(msg);
            }
            // we're successful...
            restoreTemp = false;
        } finally {
            if (restoreTemp) {
                if (!temp.renameTo(submissionFile)) {
                    String msg = "Unable to restore submission from temporary submission backup file";
                    log.error(msg);
                    throw new MetadataUpdateException(msg);
                }
            }
        }
    } catch (FileNotFoundException e) {
        String msg = "Temporary submission file could not be opened";
        log.error(msg, e);
        throw new MetadataUpdateException(msg);
    } catch (IOException e) {
        String msg = "Temporary submission file could not be written";
        log.error(msg, e);
        throw new MetadataUpdateException(msg);
    }
    return instanceID;
}
Also used : InputStreamReader(java.io.InputStreamReader) Element(org.kxml2.kdom.Element) FileNotFoundException(java.io.FileNotFoundException) MetadataUpdateException(org.opendatakit.briefcase.model.MetadataUpdateException) IOException(java.io.IOException) Document(org.kxml2.kdom.Document) FileInputStream(java.io.FileInputStream) Date(java.util.Date) KXmlSerializer(org.kxml2.io.KXmlSerializer) KXmlParser(org.kxml2.io.KXmlParser) FileOutputStream(java.io.FileOutputStream) XmlPullParserException(org.xmlpull.v1.XmlPullParserException) MediaFile(org.opendatakit.briefcase.util.ServerFetcher.MediaFile) File(java.io.File)

Aggregations

Element (org.kxml2.kdom.Element)50 TreeElement (org.javarosa.core.model.instance.TreeElement)25 AbstractTreeElement (org.javarosa.core.model.instance.AbstractTreeElement)23 ArrayList (java.util.ArrayList)21 IOException (java.io.IOException)17 IFormElement (org.javarosa.core.model.IFormElement)17 KXmlParser (org.kxml2.io.KXmlParser)12 XmlPullParserException (org.xmlpull.v1.XmlPullParserException)12 File (java.io.File)8 Test (org.junit.Test)7 ParsingException (org.opendatakit.briefcase.model.ParsingException)7 XmlPullParser (org.xmlpull.v1.XmlPullParser)7 Document (org.kxml2.kdom.Document)6 UnsupportedEncodingException (java.io.UnsupportedEncodingException)4 FileInputStream (java.io.FileInputStream)3 FileNotFoundException (java.io.FileNotFoundException)3 OutputStreamWriter (java.io.OutputStreamWriter)3 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)3 HashMap (java.util.HashMap)3 KXmlSerializer (org.kxml2.io.KXmlSerializer)3