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;
}
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);
}
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;
}
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;
}
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;
}
Aggregations