package com.airbnb.airpal.api.output.persistors; import com.airbnb.airpal.api.Job; import com.airbnb.airpal.api.output.builders.JobOutputBuilder; import com.airbnb.airpal.core.execution.ExecutionClient; import com.airbnb.airpal.core.execution.QueryExecutionAuthorizer; import com.amazonaws.AmazonClientException; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.PutObjectRequest; import com.google.common.net.MediaType; import lombok.RequiredArgsConstructor; import lombok.val; import javax.ws.rs.core.UriBuilder; import java.io.File; import java.net.URI; import static com.google.common.base.Preconditions.checkNotNull; @RequiredArgsConstructor public class S3FilePersistor implements Persistor { private final AmazonS3 s3Client; private final String outputBucket; private final long maxSizeForTextView; private final boolean compressedOutput; @Override public boolean canPersist(QueryExecutionAuthorizer authorizer) { // Everyone can write to s3 return true; } private String getOutputKey(String fileBaseName) { return "airpal/" + fileBaseName; } @Override public URI persist(JobOutputBuilder outputBuilder, Job job) { File file = checkNotNull(outputBuilder.build(), "output builder resulting file was null"); val objectMetaData = new ObjectMetadata(); objectMetaData.setContentLength(file.length()); objectMetaData.setContentType(MediaType.CSV_UTF_8.toString()); if (compressedOutput) { objectMetaData.setContentEncoding("gzip"); } val putRequest = new PutObjectRequest( outputBucket, getOutputKey(file.getName()), file ).withMetadata(objectMetaData); try { s3Client.putObject(putRequest); return UriBuilder.fromPath("/api/s3/{filename}").build(file.getName()); } catch (AmazonClientException e) { throw new ExecutionClient.ExecutionFailureException(job, "Could not upload CSV to S3", e); } finally { outputBuilder.delete(); } } }