package org.commcare.tasks;
import android.util.Log;
import org.commcare.CommCareApplication;
import org.commcare.logging.AndroidLogger;
import org.commcare.tasks.templates.CommCareTask;
import org.commcare.utils.FileUtil;
import org.commcare.utils.FormUploadResult;
import org.commcare.utils.FormUploadUtil;
import org.commcare.utils.SessionUnavailableException;
import org.commcare.views.notifications.NotificationMessageFactory;
import org.commcare.views.notifications.NotificationMessageFactory.StockMessages;
import org.commcare.views.notifications.ProcessIssues;
import org.javarosa.core.model.User;
import org.javarosa.core.services.Logger;
import org.javarosa.core.services.locale.Localization;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Properties;
/**
* @author wspride
*
* This task iterates through all the form instances in dumpDirectory and attempts to
* submit them to the receiver at postUrl. The results array are status codes
* as defined in FormUploadUtil.
*
*/
public abstract class SendTask<R> extends CommCareTask<Void, String, Boolean, R> {
private String postUrl;
private FormUploadResult[] results;
private final File dumpDirectory;
private static final String MALFORMED_FILE_CATEGORY = "malformed-file";
public static final int BULK_SEND_ID = 12335645;
private static final String TAG = SendTask.class.getSimpleName();
// 5MB less 1KB overhead
public SendTask(String url, File dumpDirectory) {
this.postUrl = url;
this.taskId = SendTask.BULK_SEND_ID;
this.dumpDirectory = dumpDirectory;
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
//These will never get Zero'd otherwise
postUrl = null;
results = null;
}
@Override
protected void onCancelled() {
super.onCancelled();
CommCareApplication.notificationManager().reportNotificationMessage(NotificationMessageFactory.message(ProcessIssues.LoggedOut));
}
@Override
protected Boolean doTaskBackground(Void... params) {
publishProgress(Localization.get("bulk.form.send.start"));
//sanity check
if (!(dumpDirectory.isDirectory())) {
return false;
}
File[] files = dumpDirectory.listFiles();
int counter = 0;
results = new FormUploadResult[files.length];
for (int i = 0; i < files.length; ++i) {
//Assume failure
results[i] = FormUploadResult.FAILURE;
}
boolean allSuccessful = true;
for (int i = 0; i < files.length; i++) {
publishProgress(Localization.get("bulk.send.dialog.progress", new String[]{"" + (i + 1)}));
File formFolder = files[i];
if (!(formFolder.isDirectory())) {
Log.e(TAG, "Encountered non form entry in file dump folder at path: " + formFolder.getAbsolutePath());
CommCareApplication.notificationManager().reportNotificationMessage(NotificationMessageFactory.message(StockMessages.Send_MalformedFile, new String[]{null, formFolder.getName()}, MALFORMED_FILE_CATEGORY));
continue;
}
try {
tryLoadPropertiesFile(formFolder);
} catch(IOException e){
Log.e(TAG, "Could not load properties file in folder: " + formFolder +
" with error: " + e.getMessage());
CommCareApplication.notificationManager().reportNotificationMessage(NotificationMessageFactory.message(StockMessages.Send_MalformedFile, new String[]{null, formFolder.getName()}, MALFORMED_FILE_CATEGORY));
continue;
}
try {
User user = CommCareApplication.instance().getSession().getLoggedInUser();
results[i] = FormUploadUtil.sendInstance(counter, formFolder, postUrl, user);
if (results[i] == FormUploadResult.FULL_SUCCESS) {
FileUtil.deleteFileOrDir(formFolder);
} else if (results[i] == FormUploadResult.TRANSPORT_FAILURE) {
allSuccessful = false;
publishProgress(Localization.get("bulk.send.transport.error"));
return false;
} else {
allSuccessful = false;
CommCareApplication.notificationManager().reportNotificationMessage(NotificationMessageFactory.message(StockMessages.Send_MalformedFile, new String[]{null, formFolder.getName()}, MALFORMED_FILE_CATEGORY));
publishProgress(Localization.get("bulk.send.file.error", new String[]{formFolder.getAbsolutePath()}));
}
counter++;
} catch (SessionUnavailableException | FileNotFoundException fe) {
Log.e(TAG, Localization.get("bulk.send.file.error", new String[]{formFolder.getAbsolutePath()}), fe);
publishProgress(Localization.get("bulk.send.file.error", new String[]{fe.getMessage()}));
}
}
return allSuccessful;
}
/**
* See if this form submission has a properties file (which it should in 2.27+)
* If so, update override class's properties with the relevant fields. Fields:
*
* PostURL - the receiver URL to submit this form to (the app user is the default)
*
* @param formFolder the form instance folder currently being submitted
*/
protected void tryLoadPropertiesFile(File formFolder) throws IOException{
// see if we have a form.properties file to load the PostURL from
FilenameFilter filter = new FilenameFilter() {
@Override
public boolean accept(File dir, String filename) {
return filename.equals(ZipTask.FORM_PROPERTIES_FILE);
}
};
// there should only be one of these
File[] formPropertiesFile = formFolder.listFiles(filter);
if(formPropertiesFile != null && formPropertiesFile.length > 0){
Properties properties = FileUtil.loadProperties(formPropertiesFile[0]);
if(properties != null && properties.getProperty(ZipTask.FORM_PROPERTY_POST_URL) != null){
postUrl = properties.getProperty(ZipTask.FORM_PROPERTY_POST_URL);
Logger.log(AndroidLogger.TYPE_FORM_DUMP, "Successfully got form.property PostURL: " + postUrl);
}
// don't submit this file
FileUtil.deleteFileOrDir(formPropertiesFile[0]);
}
}
}