Search in sources :

Example 11 with ParsingException

use of org.opendatakit.briefcase.model.ParsingException 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 12 with ParsingException

use of org.opendatakit.briefcase.model.ParsingException in project briefcase by opendatakit.

the class ExportToCsv method doAction.

@Override
public boolean doAction() {
    boolean allSuccessful = true;
    File instancesDir;
    try {
        instancesDir = FileSystemUtils.getFormInstancesDirectory(briefcaseLfd.getFormDirectory());
    } catch (FileSystemException e) {
        String msg = "Unable to access instances directory of form";
        log.error(msg, e);
        EventBus.publish(new ExportProgressEvent(msg, briefcaseLfd));
        return false;
    }
    if (!outputDir.exists()) {
        if (!outputDir.mkdir()) {
            EventBus.publish(new ExportProgressEvent("Unable to create destination directory", briefcaseLfd));
            return false;
        }
    }
    if (!processFormDefinition()) {
        // weren't able to initialize the csv file...
        return false;
    }
    File[] instances = instancesDir.listFiles(file -> file.isDirectory() && new File(file, "submission.xml").exists());
    totalInstances = instances.length;
    // assume it to be latest.
    if (instances != null) {
        Arrays.sort(instances, (f1, f2) -> {
            try {
                if (f1.isDirectory() && f2.isDirectory()) {
                    File submission1 = new File(f1, "submission.xml");
                    String submissionDate1String = XmlManipulationUtils.parseXml(submission1).getRootElement().getAttributeValue(null, "submissionDate");
                    File submission2 = new File(f2, "submission.xml");
                    String submissionDate2String = XmlManipulationUtils.parseXml(submission2).getRootElement().getAttributeValue(null, "submissionDate");
                    Date submissionDate1 = StringUtils.isNotEmptyNotNull(submissionDate1String) ? WebUtils.parseDate(submissionDate1String) : new Date();
                    Date submissionDate2 = StringUtils.isNotEmptyNotNull(submissionDate2String) ? WebUtils.parseDate(submissionDate2String) : new Date();
                    return submissionDate1.compareTo(submissionDate2);
                }
            } catch (ParsingException | FileSystemException e) {
                log.error("failed to sort submissions", e);
            }
            return 0;
        });
    }
    for (File instanceDir : instances) {
        if (terminationFuture.isCancelled()) {
            EventBus.publish(new ExportProgressEvent("Aborted", briefcaseLfd));
            allSuccessful = false;
            break;
        }
        if (instanceDir.getName().startsWith("."))
            // Mac OSX
            continue;
        allSuccessful = allSuccessful && processInstance(instanceDir);
    }
    for (OutputStreamWriter w : fileMap.values()) {
        try {
            w.flush();
            w.close();
        } catch (IOException e) {
            String msg = "Error flushing csv file";
            EventBus.publish(new ExportProgressEvent(msg, briefcaseLfd));
            log.error(msg, e);
            allSuccessful = false;
        }
    }
    return allSuccessful;
}
Also used : FileSystemException(org.opendatakit.briefcase.model.FileSystemException) ParsingException(org.opendatakit.briefcase.model.ParsingException) OutputStreamWriter(java.io.OutputStreamWriter) IOException(java.io.IOException) File(java.io.File) ExportProgressEvent(org.opendatakit.briefcase.model.ExportProgressEvent) Date(java.util.Date) LocalDate(java.time.LocalDate)

Example 13 with ParsingException

use of org.opendatakit.briefcase.model.ParsingException in project briefcase by opendatakit.

the class FileSystemUtils method decryptSubmissionFiles.

private static boolean decryptSubmissionFiles(String base64EncryptedSymmetricKey, FormInstanceMetadata fim, List<String> mediaNames, String encryptedSubmissionFile, String base64EncryptedElementSignature, PrivateKey rsaPrivateKey, File instanceDir, File unencryptedDir) throws FileSystemException, CryptoException, ParsingException {
    EncryptionInformation ei = new EncryptionInformation(base64EncryptedSymmetricKey, fim.instanceId, rsaPrivateKey);
    byte[] elementDigest;
    try {
        // construct the base64-encoded RSA-encrypted symmetric key
        Cipher pkCipher;
        pkCipher = Cipher.getInstance(ASYMMETRIC_ALGORITHM);
        // extract digest
        pkCipher.init(Cipher.DECRYPT_MODE, rsaPrivateKey);
        byte[] encryptedElementSignature = Base64.decodeBase64(base64EncryptedElementSignature);
        elementDigest = pkCipher.doFinal(encryptedElementSignature);
    } catch (NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException | NoSuchPaddingException e) {
        String msg = "Error decrypting base64EncryptedElementSignature";
        log.error(msg, e);
        throw new CryptoException(msg + " Cause: " + e.toString());
    }
    // NOTE: will decrypt only the files in the media list, plus the encryptedSubmissionFile
    File[] allFiles = instanceDir.listFiles();
    List<File> filesToProcess = new ArrayList<>();
    for (File f : allFiles) {
        if (mediaNames.contains(f.getName())) {
            filesToProcess.add(f);
        } else if (encryptedSubmissionFile.equals(f.getName())) {
            filesToProcess.add(f);
        }
    }
    // should have all media files plus one submission.xml.enc file
    if (filesToProcess.size() != mediaNames.size() + 1) {
        // figure out what we're missing...
        int lostFileCount = 0;
        List<String> missing = new ArrayList<>();
        for (String name : mediaNames) {
            if (name == null) {
                // this was lost due to an pre-ODK Aggregate 1.4.5 mark-as-complete action
                ++lostFileCount;
                continue;
            }
            File f = new File(instanceDir, name);
            if (!filesToProcess.contains(f)) {
                missing.add(name);
            }
        }
        StringBuilder b = new StringBuilder();
        for (String name : missing) {
            b.append(" ").append(name);
        }
        if (!filesToProcess.contains(new File(instanceDir, encryptedSubmissionFile))) {
            b.append(" ").append(encryptedSubmissionFile);
            throw new FileSystemException("Error decrypting: " + instanceDir.getName() + " Missing files:" + b.toString());
        } else {
            // ignore the fact that we don't have the lost files
            if (filesToProcess.size() + lostFileCount != mediaNames.size() + 1) {
                throw new FileSystemException("Error decrypting: " + instanceDir.getName() + " Missing files:" + b.toString());
            }
        }
    }
    // decrypt the media files IN ORDER.
    for (String mediaName : mediaNames) {
        String displayedName = (mediaName == null) ? "<missing .enc file>" : mediaName;
        File f = (mediaName == null) ? null : new File(instanceDir, mediaName);
        try {
            decryptFile(ei, f, unencryptedDir);
        } catch (InvalidKeyException | NoSuchPaddingException | InvalidAlgorithmParameterException | NoSuchAlgorithmException e) {
            String msg = "Error decrypting:" + displayedName;
            log.error(msg, e);
            throw new CryptoException(msg + " Cause: " + e.toString());
        } catch (IOException e) {
            String msg = "Error decrypting:" + displayedName;
            log.error(msg, e);
            throw new FileSystemException(msg + " Cause: " + e.toString());
        }
    }
    // decrypt the submission file
    File f = new File(instanceDir, encryptedSubmissionFile);
    try {
        decryptFile(ei, f, unencryptedDir);
    } catch (InvalidKeyException | NoSuchPaddingException | InvalidAlgorithmParameterException | NoSuchAlgorithmException e) {
        log.error("Error decrypting file", e);
        throw new CryptoException("Error decrypting:" + f.getName() + " Cause: " + e.toString());
    } catch (IOException e) {
        log.error("Error decrypting file", e);
        throw new FileSystemException("Error decrypting:" + f.getName() + " Cause: " + e.toString());
    }
    // get the FIM for the decrypted submission file
    File submissionFile = new File(unencryptedDir, encryptedSubmissionFile.substring(0, encryptedSubmissionFile.lastIndexOf(".enc")));
    FormInstanceMetadata submissionFim;
    try {
        Document subDoc = XmlManipulationUtils.parseXml(submissionFile);
        submissionFim = XmlManipulationUtils.getFormInstanceMetadata(subDoc.getRootElement());
    } catch (ParsingException | FileSystemException e) {
        log.error("Error decrypting submission", e);
        throw new FileSystemException("Error decrypting: " + submissionFile.getName() + " Cause: " + e);
    }
    boolean same = submissionFim.xparam.formId.equals(fim.xparam.formId);
    if (!same) {
        throw new FileSystemException("Error decrypting:" + unencryptedDir.getName() + " Cause: form instance metadata differs from that in manifest");
    }
    // Construct the element signature string
    StringBuilder b = new StringBuilder();
    appendElementSignatureSource(b, fim.xparam.formId);
    if (fim.xparam.modelVersion != null) {
        appendElementSignatureSource(b, fim.xparam.modelVersion);
    }
    appendElementSignatureSource(b, base64EncryptedSymmetricKey);
    appendElementSignatureSource(b, fim.instanceId);
    boolean missingFile = false;
    for (String encFilename : mediaNames) {
        if (encFilename == null) {
            missingFile = true;
            continue;
        }
        File decryptedFile = new File(unencryptedDir, encFilename.substring(0, encFilename.lastIndexOf(".enc")));
        if (decryptedFile.getName().endsWith(".missing")) {
            // this is a missing file -- we will not be able to
            // confirm the signature of the submission.
            missingFile = true;
            continue;
        }
        String md5 = FileSystemUtils.getMd5Hash(decryptedFile);
        appendElementSignatureSource(b, decryptedFile.getName() + "::" + md5);
    }
    String md5 = FileSystemUtils.getMd5Hash(submissionFile);
    appendElementSignatureSource(b, submissionFile.getName() + "::" + md5);
    // compute the digest of the element signature string
    byte[] messageDigest;
    try {
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(b.toString().getBytes("UTF-8"));
        messageDigest = md.digest();
    } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
        String msg = "Error computing xml signature";
        log.error(msg, e);
        throw new CryptoException(msg + " Cause: " + e);
    }
    same = true;
    for (int i = 0; i < messageDigest.length; ++i) {
        if (messageDigest[i] != elementDigest[i]) {
            same = false;
            break;
        }
    }
    return same;
}
Also used : ArrayList(java.util.ArrayList) IllegalBlockSizeException(javax.crypto.IllegalBlockSizeException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) BadPaddingException(javax.crypto.BadPaddingException) Document(org.kxml2.kdom.Document) FileSystemException(org.opendatakit.briefcase.model.FileSystemException) ParsingException(org.opendatakit.briefcase.model.ParsingException) MessageDigest(java.security.MessageDigest) InvalidAlgorithmParameterException(java.security.InvalidAlgorithmParameterException) FormInstanceMetadata(org.opendatakit.briefcase.util.XmlManipulationUtils.FormInstanceMetadata) NoSuchPaddingException(javax.crypto.NoSuchPaddingException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) IOException(java.io.IOException) InvalidKeyException(java.security.InvalidKeyException) Cipher(javax.crypto.Cipher) CryptoException(org.opendatakit.briefcase.model.CryptoException) File(java.io.File)

Example 14 with ParsingException

use of org.opendatakit.briefcase.model.ParsingException in project briefcase by opendatakit.

the class TransferFromODK method doAction.

@Override
public boolean doAction() {
    boolean allSuccessful = true;
    for (FormStatus fs : formsToTransfer) {
        boolean isSuccessful = true;
        try {
            if (terminationFuture.isCancelled()) {
                fs.setStatusString("Aborted. Skipping fetch of form and submissions...", true);
                EventBus.publish(new FormStatusEvent(fs));
                return false;
            }
            BriefcaseFormDefinition briefcaseLfd = doResolveOdkCollectFormDefinition(fs);
            if (briefcaseLfd == null) {
                allSuccessful = isSuccessful = false;
                continue;
            }
            OdkCollectFormDefinition odkFormDef = (OdkCollectFormDefinition) fs.getFormDefinition();
            File odkFormDefFile = odkFormDef.getFormDefinitionFile();
            final String odkFormName = odkFormDefFile.getName().substring(0, odkFormDefFile.getName().lastIndexOf("."));
            DatabaseUtils formDatabase = null;
            try {
                formDatabase = DatabaseUtils.newInstance(briefcaseLfd.getFormDirectory());
                File destinationFormInstancesDir;
                try {
                    destinationFormInstancesDir = FileSystemUtils.getFormInstancesDirectory(briefcaseLfd.getFormDirectory());
                } catch (FileSystemException e) {
                    allSuccessful = isSuccessful = false;
                    String msg = "unable to create instances folder";
                    log.error(msg, e);
                    fs.setStatusString(msg + ": " + e.getMessage(), false);
                    EventBus.publish(new FormStatusEvent(fs));
                    continue;
                }
                // we have the needed directory structure created...
                fs.setStatusString("preparing to retrieve instance data", true);
                EventBus.publish(new FormStatusEvent(fs));
                // construct up the list of folders that might have ODK form data.
                File odkFormInstancesDir = new File(odkFormDefFile.getParentFile().getParentFile(), "instances");
                // rely on ODK naming conventions to identify form data files...
                File[] odkFormInstanceDirs = odkFormInstancesDir.listFiles(pathname -> {
                    boolean beginsWithFormName = pathname.getName().startsWith(odkFormName);
                    if (!beginsWithFormName)
                        return false;
                    // skip the separator character, as it varies between 1.1.5, 1.1.6 and 1.1.7
                    String afterName = pathname.getName().substring(odkFormName.length() + 1);
                    // aftername should be a reasonable date though we allow extra stuff at the end...
                    // protects against someone having "formname" and "formname_2"
                    // and us mistaking "formname_2_2009-01-02_15_10_03" as containing
                    // instance data for "formname" instead of "formname_2"
                    boolean outcome = afterName.matches("^[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2}.*");
                    return outcome;
                });
                if (odkFormInstanceDirs != null) {
                    int instanceCount = 1;
                    for (File dir : odkFormInstanceDirs) {
                        if (terminationFuture.isCancelled()) {
                            allSuccessful = isSuccessful = false;
                            fs.setStatusString("aborting retrieving submissions...", true);
                            EventBus.publish(new FormStatusEvent(fs));
                            return false;
                        }
                        // 1.1.8 -- submission is saved as submission.xml.
                        // full instance data is stored as directoryName.xml (as is the convention in 1.1.5, 1.1.7)
                        String instanceId = null;
                        File fullXml = new File(dir, dir.getName() + ".xml");
                        File xml = new File(dir, "submission.xml");
                        if (!xml.exists() && fullXml.exists()) {
                            // e.g., 1.1.5, 1.1.7
                            xml = fullXml;
                        }
                        // rename it to match the directory name.
                        if (!xml.exists()) {
                            File[] xmlFiles = dir.listFiles(fileEndsWithXml);
                            if (xmlFiles.length == 1) {
                                try {
                                    FileUtils.moveFile(xmlFiles[0], xml);
                                } catch (IOException e) {
                                    allSuccessful = isSuccessful = false;
                                    String msg = "unable to rename form instance xml";
                                    log.error(msg, e);
                                    fs.setStatusString(msg + ": " + e.getMessage(), false);
                                    EventBus.publish(new FormStatusEvent(fs));
                                    continue;
                                }
                            }
                        }
                        if (xml.exists()) {
                            // Check if the instance has an instanceID
                            try {
                                XmlManipulationUtils.FormInstanceMetadata formInstanceMetadata = XmlManipulationUtils.getFormInstanceMetadata(XmlManipulationUtils.parseXml(xml).getRootElement());
                                instanceId = formInstanceMetadata.instanceId;
                            } catch (ParsingException e) {
                                log.error("failed to get instance id from submission", e);
                            }
                            // OK, we can copy the directory off...
                            // Briefcase instances directory name is arbitrary.
                            // Rename the xml within that to always be "submission.xml"
                            // to remove the correspondence to the directory name.
                            File scratchInstance = FileSystemUtils.getFormSubmissionDirectory(destinationFormInstancesDir, dir.getName());
                            String safeName = scratchInstance.getName();
                            int i = 2;
                            boolean same = false;
                            while (scratchInstance.exists()) {
                                File[] contents = scratchInstance.listFiles(fileEndsWithXml);
                                if (contents == null || contents.length == 0)
                                    break;
                                if (contents.length == 1) {
                                    String itsInstanceId = null;
                                    try {
                                        XmlManipulationUtils.FormInstanceMetadata formInstanceMetadata = XmlManipulationUtils.getFormInstanceMetadata(XmlManipulationUtils.parseXml(contents[0]).getRootElement());
                                        itsInstanceId = formInstanceMetadata.instanceId;
                                        // if yes don't copy it, skip to next file
                                        if (itsInstanceId != null && itsInstanceId.equals(instanceId) && FileSystemUtils.getMd5Hash(xml).equals(FileSystemUtils.getMd5Hash(contents[0]))) {
                                            same = true;
                                            break;
                                        }
                                    } catch (ParsingException e) {
                                        log.error("failed to parse submission", e);
                                    }
                                }
                                scratchInstance = new File(destinationFormInstancesDir, safeName + "-" + Integer.toString(i));
                                i++;
                            }
                            if (same) {
                                fs.setStatusString("already present - skipping: " + xml.getName(), true);
                                EventBus.publish(new FormStatusEvent(fs));
                                continue;
                            }
                            try {
                                FileUtils.copyDirectory(dir, scratchInstance);
                            } catch (IOException e) {
                                allSuccessful = isSuccessful = false;
                                String msg = "unable to copy saved instance";
                                log.error(msg, e);
                                fs.setStatusString(msg + ": " + e.getMessage(), false);
                                EventBus.publish(new FormStatusEvent(fs));
                                continue;
                            }
                            if (xml.equals(fullXml)) {
                                // need to rename
                                File odkSubmissionFile = new File(scratchInstance, fullXml.getName());
                                File scratchSubmissionFile = new File(scratchInstance, "submission.xml");
                                try {
                                    FileUtils.moveFile(odkSubmissionFile, scratchSubmissionFile);
                                } catch (IOException e) {
                                    allSuccessful = isSuccessful = false;
                                    String msg = "unable to rename submission file to submission.xml";
                                    log.error(msg, e);
                                    fs.setStatusString(msg + ": " + e.getMessage(), false);
                                    EventBus.publish(new FormStatusEvent(fs));
                                    continue;
                                }
                            } else {
                                // delete the full xml file (keep only the submission.xml)
                                File odkSubmissionFile = new File(scratchInstance, fullXml.getName());
                                odkSubmissionFile.delete();
                            }
                            fs.setStatusString(String.format("retrieving (%1$d)", instanceCount), true);
                            EventBus.publish(new FormStatusEvent(fs));
                            ++instanceCount;
                        }
                    }
                }
            } catch (SQLException | FileSystemException e) {
                allSuccessful = isSuccessful = false;
                String msg = "unable to open form database";
                log.error(msg, e);
                fs.setStatusString(msg + ": " + e.getMessage(), false);
                EventBus.publish(new FormStatusEvent(fs));
                continue;
            } finally {
                if (formDatabase != null) {
                    try {
                        formDatabase.close();
                    } catch (SQLException e) {
                        allSuccessful = isSuccessful = false;
                        String msg = "unable to close form database";
                        log.error(msg, e);
                        fs.setStatusString(msg + ": " + e.getMessage(), false);
                        EventBus.publish(new FormStatusEvent(fs));
                        continue;
                    }
                }
            }
        } finally {
            if (isSuccessful) {
                fs.setStatusString(ServerFetcher.SUCCESS_STATUS, true);
                EventBus.publish(new FormStatusEvent(fs));
            } else {
                fs.setStatusString(ServerFetcher.FAILED_STATUS, true);
                EventBus.publish(new FormStatusEvent(fs));
            }
        }
    }
    return allSuccessful;
}
Also used : SQLException(java.sql.SQLException) FormStatusEvent(org.opendatakit.briefcase.model.FormStatusEvent) IOException(java.io.IOException) OdkCollectFormDefinition(org.opendatakit.briefcase.model.OdkCollectFormDefinition) FileSystemException(org.opendatakit.briefcase.model.FileSystemException) FormStatus(org.opendatakit.briefcase.model.FormStatus) ParsingException(org.opendatakit.briefcase.model.ParsingException) BriefcaseFormDefinition(org.opendatakit.briefcase.model.BriefcaseFormDefinition) File(java.io.File)

Example 15 with ParsingException

use of org.opendatakit.briefcase.model.ParsingException in project briefcase by opendatakit.

the class ServerFetcher method downloadSubmission.

private void downloadSubmission(File formInstancesDir, DatabaseUtils formDatabase, BriefcaseFormDefinition lfd, FormStatus fs, String uri) throws Exception {
    File instanceFolder = formDatabase.hasRecordedInstance(uri);
    if (instanceFolder != null) {
        // check if the submission file is present in the folder before skipping
        File instance = new File(instanceFolder, "submission.xml");
        File instanceEncrypted = new File(instanceFolder, "submission.xml.enc");
        if (instance.exists() || instanceEncrypted.exists()) {
            log.info("already present - skipping fetch: " + uri);
            return;
        }
    }
    String formId = lfd.getSubmissionKey(uri);
    if (isCancelled()) {
        fs.setStatusString("aborting fetch of submission...", true);
        EventBus.publish(new FormStatusEvent(fs));
        throw new SubmissionDownloadException("Transfer cancelled by user.");
    }
    String baseUrl = serverInfo.getUrl() + "/view/downloadSubmission";
    Map<String, String> params = new HashMap<>();
    params.put("formId", formId);
    String fullUrl = WebUtils.createLinkWithProperties(baseUrl, params);
    AggregateUtils.DocumentFetchResult result;
    try {
        DocumentDescription submissionDescription = new DocumentDescription("Fetch of a submission failed.  Detailed error: ", "Fetch of a submission failed.", "submission", terminationFuture);
        result = AggregateUtils.getXmlDocument(fullUrl, serverInfo, false, submissionDescription, null);
    } catch (XmlDocumentFetchException e) {
        throw new SubmissionDownloadException(e.getMessage());
    }
    // and parse the document...
    SubmissionManifest submissionManifest;
    try {
        submissionManifest = XmlManipulationUtils.parseDownloadSubmissionResponse(result.doc);
    } catch (ParsingException e) {
        throw new SubmissionDownloadException(e.getMessage());
    }
    String msg = "Fetched instanceID=" + submissionManifest.instanceID;
    log.info(msg);
    if (FileSystemUtils.hasFormSubmissionDirectory(formInstancesDir, submissionManifest.instanceID)) {
        // create instance directory...
        File instanceDir = FileSystemUtils.assertFormSubmissionDirectory(formInstancesDir, submissionManifest.instanceID);
        // fetch attachments
        for (MediaFile m : submissionManifest.attachmentList) {
            downloadMediaFileIfChanged(instanceDir, m, fs);
        }
        // write submission file -- we rely on instanceId being unique...
        File submissionFile = new File(instanceDir, "submission.xml");
        OutputStreamWriter fo = new OutputStreamWriter(new FileOutputStream(submissionFile), "UTF-8");
        fo.write(submissionManifest.submissionXml);
        fo.close();
        // if we get here, we know that this is a completed submission
        // (because it was in /view/submissionList) and that we safely
        // copied it into the storage area (because we didn't get any
        // exceptions).
        formDatabase.assertRecordedInstanceDirectory(uri, instanceDir);
    } else {
        // create instance directory...
        File instanceDir = FileSystemUtils.assertFormSubmissionDirectory(formInstancesDir, submissionManifest.instanceID);
        // fetch attachments
        for (MediaFile m : submissionManifest.attachmentList) {
            downloadMediaFileIfChanged(instanceDir, m, fs);
        }
        // write submission file
        File submissionFile = new File(instanceDir, "submission.xml");
        OutputStreamWriter fo = new OutputStreamWriter(new FileOutputStream(submissionFile), "UTF-8");
        fo.write(submissionManifest.submissionXml);
        fo.close();
        // if we get here, we know that this is a completed submission
        // (because it was in /view/submissionList) and that we safely
        // copied it into the storage area (because we didn't get any
        // exceptions).
        formDatabase.assertRecordedInstanceDirectory(uri, instanceDir);
    }
}
Also used : HashMap(java.util.HashMap) FormStatusEvent(org.opendatakit.briefcase.model.FormStatusEvent) XmlDocumentFetchException(org.opendatakit.briefcase.model.XmlDocumentFetchException) DocumentDescription(org.opendatakit.briefcase.model.DocumentDescription) ParsingException(org.opendatakit.briefcase.model.ParsingException) FileOutputStream(java.io.FileOutputStream) OutputStreamWriter(java.io.OutputStreamWriter) File(java.io.File)

Aggregations

ParsingException (org.opendatakit.briefcase.model.ParsingException)15 File (java.io.File)9 IOException (java.io.IOException)9 FileSystemException (org.opendatakit.briefcase.model.FileSystemException)8 ArrayList (java.util.ArrayList)7 Element (org.kxml2.kdom.Element)5 FormStatusEvent (org.opendatakit.briefcase.model.FormStatusEvent)4 OutputStreamWriter (java.io.OutputStreamWriter)3 Document (org.kxml2.kdom.Document)3 CannotFixXMLException (org.opendatakit.briefcase.model.CannotFixXMLException)3 DocumentDescription (org.opendatakit.briefcase.model.DocumentDescription)3 MediaFile (org.opendatakit.briefcase.util.ServerFetcher.MediaFile)3 FileNotFoundException (java.io.FileNotFoundException)2 MalformedURLException (java.net.MalformedURLException)2 SQLException (java.sql.SQLException)2 LocalDate (java.time.LocalDate)2 Date (java.util.Date)2 HashMap (java.util.HashMap)2 CryptoException (org.opendatakit.briefcase.model.CryptoException)2 MetadataUpdateException (org.opendatakit.briefcase.model.MetadataUpdateException)2