package org.activityinfo.server.endpoint.odk;
import com.google.appengine.tools.cloudstorage.GcsFileOptions;
import com.google.appengine.tools.cloudstorage.GcsFileOptions.Builder;
import com.google.appengine.tools.cloudstorage.GcsFilename;
import com.google.appengine.tools.cloudstorage.GcsOutputChannel;
import com.google.appengine.tools.cloudstorage.GcsService;
import com.google.appengine.tools.cloudstorage.GcsServiceFactory;
import com.google.appengine.tools.cloudstorage.RetryParams;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.io.ByteSource;
import com.google.inject.Inject;
import org.activityinfo.model.resource.ResourceId;
import org.activityinfo.service.DeploymentConfiguration;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.channels.Channels;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Archives the original XForm instances for debugging and
* data recovery in the event of problems in translation from XForm to our internal
* model.
*/
public class SubmissionArchiver {
public static final String GCS_BUCKET_NAME_PROPERTY = "odk.backup.gcs.bucket.name";
private static final Logger LOGGER = Logger.getLogger(SubmissionArchiver.class.getName());
private final String bucketName;
private final DateTimeFormatter dateFormat;
private final DateTimeFormatter timeFormat;
@Inject
public SubmissionArchiver(DeploymentConfiguration config) {
this.bucketName = config.getProperty(SubmissionArchiver.GCS_BUCKET_NAME_PROPERTY);
this.dateFormat = DateTimeFormat.forPattern("yyyy-MM-dd");
this.timeFormat = DateTimeFormat.forPattern("HH:mm:ss.SSS");
}
public void backup(ResourceId formClassId, ResourceId formId, ByteSource byteSource) {
try {
DateTime submissionTime = new DateTime(DateTimeZone.UTC);
String path = Joiner.on('/').join(
formClassId,
dateFormat.print(submissionTime),
timeFormat.print(submissionTime) + " " + formId + ".xml");
GcsFilename gcsFilename = new GcsFilename(bucketName, path);
GcsService gcsService = GcsServiceFactory.createGcsService(RetryParams.getDefaultInstance());
GcsFileOptions gcsFileOptions = new Builder().mimeType(MediaType.MULTIPART_FORM_DATA).build();
GcsOutputChannel channel = gcsService.createOrReplace(gcsFilename, gcsFileOptions);
try (OutputStream outputStream = Channels.newOutputStream(channel)) {
byteSource.copyTo(outputStream);
}
LOGGER.log(Level.INFO, "Archived XForm to " + gcsFilename);
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Form submission could not be backed up to GCS", e);
try {
LOGGER.info(byteSource.asCharSource(Charsets.UTF_8).read());
} catch (IOException ioException) {
}
}
}
}