Search in sources :

Example 1 with RemoteFormDefinition

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

the class RetrieveAvailableFormsFromServer method doAction.

public void doAction() throws XmlDocumentFetchException, ParsingException {
    List<RemoteFormDefinition> formDefs = Collections.emptyList();
    formDefs = ServerFetcher.retrieveAvailableFormsFromServer(originServerInfo, terminationFuture);
    for (IFormDefinition fd : formDefs) {
        formStatuses.add(new FormStatus(FormStatus.TransferType.GATHER, fd));
    }
}
Also used : RemoteFormDefinition(org.opendatakit.briefcase.model.RemoteFormDefinition) FormStatus(org.opendatakit.briefcase.model.FormStatus) IFormDefinition(org.opendatakit.briefcase.model.IFormDefinition)

Example 2 with RemoteFormDefinition

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

the class ServerFetcher method downloadManifestAndMediaFiles.

private String downloadManifestAndMediaFiles(File mediaDir, FormStatus fs) {
    RemoteFormDefinition fd = getRemoteFormDefinition(fs);
    if (fd.getManifestUrl() == null)
        return null;
    fs.setStatusString("Fetching form manifest", true);
    EventBus.publish(new FormStatusEvent(fs));
    List<MediaFile> files = new ArrayList<>();
    AggregateUtils.DocumentFetchResult result;
    try {
        DocumentDescription formManifestDescription = new DocumentDescription("Fetch of manifest failed. Detailed reason: ", "Fetch of manifest failed ", "form manifest", terminationFuture);
        result = AggregateUtils.getXmlDocument(fd.getManifestUrl(), serverInfo, false, formManifestDescription, null);
    } catch (XmlDocumentFetchException e) {
        return e.getMessage();
    }
    try {
        files = XmlManipulationUtils.parseFormManifestResponse(result.isOpenRosaResponse, result.doc);
    } catch (ParsingException e) {
        return e.getMessage();
    }
    // OK we now have the full set of files to download...
    log.info("Downloading " + files.size() + " media files.");
    int mCount = 0;
    if (files.size() > 0) {
        for (MediaFile m : files) {
            ++mCount;
            fs.setStatusString(String.format(" (getting %1$d of %2$d media files)", mCount, files.size()), true);
            EventBus.publish(new FormStatusEvent(fs));
            try {
                downloadMediaFileIfChanged(mediaDir, m, fs);
            } catch (Exception e) {
                return e.getLocalizedMessage();
            }
        }
    }
    return null;
}
Also used : XmlDocumentFetchException(org.opendatakit.briefcase.model.XmlDocumentFetchException) DocumentDescription(org.opendatakit.briefcase.model.DocumentDescription) RemoteFormDefinition(org.opendatakit.briefcase.model.RemoteFormDefinition) FormStatusEvent(org.opendatakit.briefcase.model.FormStatusEvent) ParsingException(org.opendatakit.briefcase.model.ParsingException) ArrayList(java.util.ArrayList) URISyntaxException(java.net.URISyntaxException) FileSystemException(org.opendatakit.briefcase.model.FileSystemException) SQLException(java.sql.SQLException) SocketTimeoutException(java.net.SocketTimeoutException) TransmissionException(org.opendatakit.briefcase.model.TransmissionException) XmlDocumentFetchException(org.opendatakit.briefcase.model.XmlDocumentFetchException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) ParsingException(org.opendatakit.briefcase.model.ParsingException)

Example 3 with RemoteFormDefinition

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

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

the class ServerFetcher method downloadAllSubmissionsForForm.

private boolean downloadAllSubmissionsForForm(File formInstancesDir, DatabaseUtils formDatabase, BriefcaseFormDefinition lfd, FormStatus fs) {
    int submissionCount = 1;
    int chunkCount = 1;
    boolean allSuccessful = true;
    RemoteFormDefinition fd = getRemoteFormDefinition(fs);
    ExecutorService execSvc = getFetchExecutorService();
    CompletionService<SubmissionChunk> chunkCompleter = new ExecutorCompletionService<>(execSvc);
    CompletionService<String> submissionCompleter = new ExecutorCompletionService<>(execSvc);
    String oldWebsafeCursorString;
    String websafeCursorString = "";
    chunkCompleter.submit(new SubmissionChunkDownload(fs, fd.getFormId(), websafeCursorString));
    boolean cursorFinished;
    try {
        do {
            if (isCancelled()) {
                fs.setStatusString("aborting fetching submission chunks...", true);
                EventBus.publish(new FormStatusEvent(fs));
                return false;
            }
            fs.setStatusString("processing chunk " + chunkCount + "...", true);
            EventBus.publish(new FormStatusEvent(fs));
            // remember what we had...
            oldWebsafeCursorString = websafeCursorString;
            SubmissionChunk chunk;
            try {
                chunk = chunkCompleter.take().get();
                chunkCount += 1;
                websafeCursorString = chunk.websafeCursorString;
                cursorFinished = oldWebsafeCursorString.equals(websafeCursorString);
            } catch (InterruptedException | ExecutionException e) {
                return false;
            }
            if (!cursorFinished) {
                // submit another chunk request so it's ready by the time we finish processing this chunk
                chunkCompleter.submit(new SubmissionChunkDownload(fs, fd.getFormId(), websafeCursorString));
            }
            // submit a download job for each uri in the chunk
            for (String uri : chunk.uriList) {
                if (isCancelled()) {
                    fs.setStatusString("aborting requesting submissions...", true);
                    EventBus.publish(new FormStatusEvent(fs));
                    return false;
                }
                submissionCompleter.submit(new SubmissionDownload(formInstancesDir, formDatabase, lfd, fs, uri));
            }
            // call take() and get() exactly once for each download submitted above (we don't need the uri)
            for (int i = 0; i < chunk.uriList.size(); i++) {
                if (isCancelled()) {
                    fs.setStatusString("aborting processing submissions...", true);
                    EventBus.publish(new FormStatusEvent(fs));
                    return false;
                }
                try {
                    submissionCompleter.take().get();
                    fs.setStatusString(String.format("fetched instance %s...", submissionCount++), true);
                    EventBus.publish(new FormStatusEvent(fs));
                } catch (InterruptedException | ExecutionException e) {
                    log.error("failure during submission download", e);
                    allSuccessful = false;
                    fs.setStatusString("Submission not retrieved: " + e.getMessage(), false);
                    EventBus.publish(new FormStatusEvent(fs));
                // but try to get the next one...
                }
            }
        } while (!cursorFinished);
    } finally {
        execSvc.shutdown();
        try {
            execSvc.awaitTermination(1, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            log.warn("interrupted while waiting for pull to complete");
        }
    }
    return allSuccessful;
}
Also used : FormStatusEvent(org.opendatakit.briefcase.model.FormStatusEvent) ExecutorCompletionService(java.util.concurrent.ExecutorCompletionService) RemoteFormDefinition(org.opendatakit.briefcase.model.RemoteFormDefinition) ExecutorService(java.util.concurrent.ExecutorService) ExecutionException(java.util.concurrent.ExecutionException)

Example 5 with RemoteFormDefinition

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

the class ServerFetcher method downloadFormAndSubmissionFiles.

public boolean downloadFormAndSubmissionFiles(List<FormStatus> formsToTransfer) {
    boolean allSuccessful = true;
    // boolean error = false;
    int total = formsToTransfer.size();
    for (int i = 0; i < total; i++) {
        FormStatus fs = formsToTransfer.get(i);
        if (isCancelled()) {
            fs.setStatusString("Aborted. Skipping fetch of form and submissions...", true);
            EventBus.publish(new FormStatusEvent(fs));
            return false;
        }
        RemoteFormDefinition fd = getRemoteFormDefinition(fs);
        fs.setStatusString("Fetching form definition", true);
        EventBus.publish(new FormStatusEvent(fs));
        try {
            File tmpdl = FileSystemUtils.getTempFormDefinitionFile();
            AggregateUtils.commonDownloadFile(serverInfo, tmpdl, fd.getDownloadUrl());
            fs.setStatusString("resolving against briefcase form definitions", true);
            EventBus.publish(new FormStatusEvent(fs));
            boolean successful = false;
            BriefcaseFormDefinition briefcaseLfd;
            DatabaseUtils formDatabase = null;
            try {
                try {
                    briefcaseLfd = BriefcaseFormDefinition.resolveAgainstBriefcaseDefn(tmpdl);
                    if (briefcaseLfd.needsMediaUpdate()) {
                        if (fd.getManifestUrl() != null) {
                            File mediaDir = FileSystemUtils.getMediaDirectory(briefcaseLfd.getFormDirectory());
                            String error = downloadManifestAndMediaFiles(mediaDir, fs);
                            if (error != null) {
                                allSuccessful = false;
                                fs.setStatusString("Error fetching form definition: " + error, false);
                                EventBus.publish(new FormStatusEvent(fs));
                                continue;
                            }
                        }
                    }
                    formDatabase = DatabaseUtils.newInstance(briefcaseLfd.getFormDirectory());
                } catch (BadFormDefinition e) {
                    allSuccessful = false;
                    String msg = "Error parsing form definition";
                    log.error(msg, e);
                    fs.setStatusString(msg + ": " + e.getMessage(), false);
                    EventBus.publish(new FormStatusEvent(fs));
                    continue;
                }
                fs.setStatusString("preparing to retrieve instance data", true);
                EventBus.publish(new FormStatusEvent(fs));
                File formInstancesDir = FileSystemUtils.getFormInstancesDirectory(briefcaseLfd.getFormDirectory());
                // this will publish events
                successful = downloadAllSubmissionsForForm(formInstancesDir, formDatabase, briefcaseLfd, fs);
            } catch (SQLException | FileSystemException e) {
                allSuccessful = 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 = false;
                        String msg = "unable to close form database";
                        log.error(msg, e);
                        fs.setStatusString(msg + ": " + e.getMessage(), false);
                        EventBus.publish(new FormStatusEvent(fs));
                        continue;
                    }
                }
            }
            allSuccessful = allSuccessful && successful;
            // on success, we haven't actually set a success event (because we don't know we're done)
            if (successful) {
                fs.setStatusString(SUCCESS_STATUS, true);
                EventBus.publish(new FormStatusEvent(fs));
            } else {
                fs.setStatusString(FAILED_STATUS, true);
                EventBus.publish(new FormStatusEvent(fs));
            }
        } catch (SocketTimeoutException se) {
            allSuccessful = false;
            log.error("error accessing URL", se);
            fs.setStatusString("Communications to the server timed out. Detailed message: " + se.getLocalizedMessage() + " while accessing: " + fd.getDownloadUrl() + " A network login screen may be interfering with the transmission to the server.", false);
            EventBus.publish(new FormStatusEvent(fs));
        } catch (IOException e) {
            allSuccessful = false;
            log.error("error accessing form download URL", e);
            fs.setStatusString("Unexpected error: " + e.getLocalizedMessage() + " while accessing: " + fd.getDownloadUrl() + " A network login screen may be interfering with the transmission to the server.", false);
            EventBus.publish(new FormStatusEvent(fs));
        } catch (FileSystemException | TransmissionException | URISyntaxException e) {
            allSuccessful = false;
            log.error("error accessing form download URL", e);
            fs.setStatusString("Unexpected error: " + e.getLocalizedMessage() + " while accessing: " + fd.getDownloadUrl(), false);
            EventBus.publish(new FormStatusEvent(fs));
        }
    }
    return allSuccessful;
}
Also used : SQLException(java.sql.SQLException) FormStatusEvent(org.opendatakit.briefcase.model.FormStatusEvent) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) FileSystemException(org.opendatakit.briefcase.model.FileSystemException) SocketTimeoutException(java.net.SocketTimeoutException) RemoteFormDefinition(org.opendatakit.briefcase.model.RemoteFormDefinition) TransmissionException(org.opendatakit.briefcase.model.TransmissionException) FormStatus(org.opendatakit.briefcase.model.FormStatus) BriefcaseFormDefinition(org.opendatakit.briefcase.model.BriefcaseFormDefinition) File(java.io.File)

Aggregations

RemoteFormDefinition (org.opendatakit.briefcase.model.RemoteFormDefinition)5 IOException (java.io.IOException)3 FileSystemException (org.opendatakit.briefcase.model.FileSystemException)3 FormStatusEvent (org.opendatakit.briefcase.model.FormStatusEvent)3 SocketTimeoutException (java.net.SocketTimeoutException)2 URISyntaxException (java.net.URISyntaxException)2 SQLException (java.sql.SQLException)2 ArrayList (java.util.ArrayList)2 ExecutionException (java.util.concurrent.ExecutionException)2 FormStatus (org.opendatakit.briefcase.model.FormStatus)2 ParsingException (org.opendatakit.briefcase.model.ParsingException)2 TransmissionException (org.opendatakit.briefcase.model.TransmissionException)2 File (java.io.File)1 FileNotFoundException (java.io.FileNotFoundException)1 MalformedURLException (java.net.MalformedURLException)1 URL (java.net.URL)1 ExecutorCompletionService (java.util.concurrent.ExecutorCompletionService)1 ExecutorService (java.util.concurrent.ExecutorService)1 Element (org.kxml2.kdom.Element)1 BriefcaseFormDefinition (org.opendatakit.briefcase.model.BriefcaseFormDefinition)1