Search in sources :

Example 6 with FormStatusEvent

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

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

the class ServerUploader method uploadForm.

public boolean uploadForm(FormStatus formToTransfer, File briefcaseFormDefFile, File briefcaseFormMediaDir) {
    // very similar to upload submissions...
    URI u;
    try {
        u = AggregateUtils.testServerConnectionWithHeadRequest(serverInfo, "formUpload");
    } catch (TransmissionException e) {
        formToTransfer.setStatusString(e.getMessage(), false);
        EventBus.publish(new FormStatusEvent(formToTransfer));
        return false;
    }
    // try to send form...
    if (!briefcaseFormDefFile.exists()) {
        String msg = "Form definition file not found: " + briefcaseFormDefFile.getAbsolutePath();
        formToTransfer.setStatusString(msg, false);
        EventBus.publish(new FormStatusEvent(formToTransfer));
        return false;
    }
    // find all files in parent directory
    File[] allFiles = null;
    if (briefcaseFormMediaDir != null) {
        allFiles = briefcaseFormMediaDir.listFiles();
    }
    // clean up the list, removing anything that is suspicious
    // or that we won't attempt to upload. For OpenRosa servers,
    // we'll upload just about everything...
    List<File> files = new ArrayList<>();
    if (allFiles != null) {
        for (File f : allFiles) {
            String fileName = f.getName();
            if (fileName.startsWith(".")) {
                // potential Apple file attributes file -- ignore it
                continue;
            }
            files.add(f);
        }
    }
    DocumentDescription formDefinitionUploadDescription = new DocumentDescription("Form definition upload failed.  Detailed error: ", "Form definition upload failed.", "form definition", terminationFuture);
    return AggregateUtils.uploadFilesToServer(serverInfo, u, "form_def_file", briefcaseFormDefFile, files, formDefinitionUploadDescription, null, terminationFuture, formToTransfer);
}
Also used : DocumentDescription(org.opendatakit.briefcase.model.DocumentDescription) TransmissionException(org.opendatakit.briefcase.model.TransmissionException) FormStatusEvent(org.opendatakit.briefcase.model.FormStatusEvent) ArrayList(java.util.ArrayList) URI(java.net.URI) File(java.io.File)

Example 8 with FormStatusEvent

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

the class ServerUploader method uploadSubmission.

private final boolean uploadSubmission(DatabaseUtils formDatabase, FormStatus formToTransfer, URI u, int count, int totalCount, File instanceDirectory) {
    // We have the actual server URL in u, possibly redirected to https.
    // We know we are talking to the server because the head request
    // succeeded and had a Location header field.
    // try to send instance
    // get instance file
    File file = new File(instanceDirectory, "submission.xml");
    String submissionFile = file.getName();
    if (!file.exists()) {
        String msg = "Submission file not found: " + file.getAbsolutePath();
        formToTransfer.setStatusString(msg, false);
        EventBus.publish(new FormStatusEvent(formToTransfer));
        return false;
    }
    // find all files in parent directory
    File[] allFiles = instanceDirectory.listFiles();
    // clean up the list, removing anything that is suspicious
    // or that we won't attempt to upload. For OpenRosa servers,
    // we'll upload just about everything...
    List<File> files = new ArrayList<>();
    for (File f : allFiles) {
        String fileName = f.getName();
        if (fileName.startsWith(".")) {
            // potential Apple file attributes file -- ignore it
            continue;
        }
        if (fileName.equals(submissionFile)) {
            // this is always added
            continue;
        } else {
            files.add(f);
        }
    }
    SubmissionResponseAction action = new SubmissionResponseAction(file);
    if (isCancelled()) {
        formToTransfer.setStatusString("aborting upload of submission...", true);
        EventBus.publish(new FormStatusEvent(formToTransfer));
        return false;
    }
    DocumentDescription submissionUploadDescription = new DocumentDescription("Submission upload failed.  Detailed error: ", "Submission upload failed.", "submission (" + count + " of " + totalCount + ")", terminationFuture);
    boolean outcome = AggregateUtils.uploadFilesToServer(serverInfo, u, "xml_submission_file", file, files, submissionUploadDescription, action, terminationFuture, formToTransfer);
    // and try to rename the instance directory to be its instanceID
    action.afterUpload(formToTransfer);
    return outcome;
}
Also used : DocumentDescription(org.opendatakit.briefcase.model.DocumentDescription) FormStatusEvent(org.opendatakit.briefcase.model.FormStatusEvent) ArrayList(java.util.ArrayList) File(java.io.File)

Example 9 with FormStatusEvent

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

the class ServerUploader method uploadFormAndSubmissionFiles.

public boolean uploadFormAndSubmissionFiles(List<FormStatus> formsToTransfer) {
    boolean allSuccessful = true;
    for (FormStatus formToTransfer : formsToTransfer) {
        BriefcaseFormDefinition briefcaseLfd = (BriefcaseFormDefinition) formToTransfer.getFormDefinition();
        boolean thisFormSuccessful = true;
        if (isCancelled()) {
            formToTransfer.setStatusString("Aborted upload.", true);
            EventBus.publish(new FormStatusEvent(formToTransfer));
            return false;
        }
        if (!formToTransfer.isSuccessful()) {
            formToTransfer.setStatusString("Skipping upload -- download failed", false);
            EventBus.publish(new FormStatusEvent(formToTransfer));
            continue;
        }
        File briefcaseFormDefFile = FileSystemUtils.getFormDefinitionFileIfExists(briefcaseLfd.getFormDirectory());
        if (briefcaseFormDefFile == null) {
            formToTransfer.setStatusString("Form does not exist", true);
            EventBus.publish(new FormStatusEvent(formToTransfer));
            continue;
        }
        File briefcaseFormMediaDir = FileSystemUtils.getMediaDirectoryIfExists(briefcaseLfd.getFormDirectory());
        boolean outcome;
        outcome = uploadForm(formToTransfer, briefcaseFormDefFile, briefcaseFormMediaDir);
        thisFormSuccessful = thisFormSuccessful & outcome;
        allSuccessful = allSuccessful & outcome;
        URI u = getUploadSubmissionUri(formToTransfer);
        if (u == null) {
            // error already logged...
            continue;
        }
        Set<File> briefcaseInstances = FileSystemUtils.getFormSubmissionDirectories(briefcaseLfd.getFormDirectory());
        DatabaseUtils formDatabase = null;
        try {
            formDatabase = DatabaseUtils.newInstance(briefcaseLfd.getFormDirectory());
            // make sure all the local instances are in the database...
            formDatabase.updateInstanceLists(briefcaseInstances);
            // exclude submissions the server reported as already submitted
            subtractServerInstances(formToTransfer, formDatabase, briefcaseInstances);
            int i = 1;
            for (File briefcaseInstance : briefcaseInstances) {
                outcome = uploadSubmission(formDatabase, formToTransfer, u, i++, briefcaseInstances.size(), briefcaseInstance);
                thisFormSuccessful = thisFormSuccessful & outcome;
                allSuccessful = allSuccessful & outcome;
                // and stop this loop quickly if we're cancelled...
                if (isCancelled()) {
                    break;
                }
            }
        } catch (SQLException | FileSystemException e) {
            thisFormSuccessful = false;
            allSuccessful = false;
            String msg = "unable to open form database";
            log.error(msg, e);
            formToTransfer.setStatusString(msg + ": " + e.getMessage(), false);
            EventBus.publish(new FormStatusEvent(formToTransfer));
        } finally {
            if (formDatabase != null) {
                try {
                    formDatabase.close();
                } catch (SQLException e) {
                    thisFormSuccessful = false;
                    allSuccessful = false;
                    String msg = "unable to close form database";
                    log.warn(msg, e);
                    formToTransfer.setStatusString(msg + ": " + e.getMessage(), false);
                    EventBus.publish(new FormStatusEvent(formToTransfer));
                }
            }
        }
        if (isCancelled()) {
            formToTransfer.setStatusString("Aborted upload.", true);
            EventBus.publish(new FormStatusEvent(formToTransfer));
        } else if (thisFormSuccessful) {
            formToTransfer.setStatusString("Successful upload!", true);
            EventBus.publish(new FormStatusEvent(formToTransfer));
        } else {
            formToTransfer.setStatusString("Partially successful upload...", true);
            EventBus.publish(new FormStatusEvent(formToTransfer));
        }
    }
    return allSuccessful;
}
Also used : SQLException(java.sql.SQLException) FormStatusEvent(org.opendatakit.briefcase.model.FormStatusEvent) URI(java.net.URI) FileSystemException(org.opendatakit.briefcase.model.FileSystemException) FormStatus(org.opendatakit.briefcase.model.FormStatus) BriefcaseFormDefinition(org.opendatakit.briefcase.model.BriefcaseFormDefinition) File(java.io.File)

Example 10 with FormStatusEvent

use of org.opendatakit.briefcase.model.FormStatusEvent 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)

Aggregations

FormStatusEvent (org.opendatakit.briefcase.model.FormStatusEvent)12 File (java.io.File)10 IOException (java.io.IOException)5 SQLException (java.sql.SQLException)5 DocumentDescription (org.opendatakit.briefcase.model.DocumentDescription)5 FileSystemException (org.opendatakit.briefcase.model.FileSystemException)5 ParsingException (org.opendatakit.briefcase.model.ParsingException)5 TransmissionException (org.opendatakit.briefcase.model.TransmissionException)5 BriefcaseFormDefinition (org.opendatakit.briefcase.model.BriefcaseFormDefinition)4 XmlDocumentFetchException (org.opendatakit.briefcase.model.XmlDocumentFetchException)4 URISyntaxException (java.net.URISyntaxException)3 ArrayList (java.util.ArrayList)3 FormStatus (org.opendatakit.briefcase.model.FormStatus)3 RemoteFormDefinition (org.opendatakit.briefcase.model.RemoteFormDefinition)3 SocketTimeoutException (java.net.SocketTimeoutException)2 URI (java.net.URI)2 HashMap (java.util.HashMap)2 ExecutionException (java.util.concurrent.ExecutionException)2 OdkCollectFormDefinition (org.opendatakit.briefcase.model.OdkCollectFormDefinition)2 FileOutputStream (java.io.FileOutputStream)1