package com.aol.micro.server.s3.data;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.util.Random;
import cyclops.control.Eval;
import cyclops.control.Try;
import cyclops.function.FluentFunctions;
import org.apache.commons.io.FileUtils;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.transfer.TransferManager;
import com.amazonaws.services.s3.transfer.Upload;
import com.amazonaws.services.s3.transfer.model.UploadResult;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class S3ObjectWriter {
private final TransferManager manager;
private final String bucket;
private final File dir;
private final boolean aes256Encryption;
private final Random r = new Random();
/**
*
* Writes java Objects to defined S3 bucket with provided key. Calling
* map / flatMap on the returned try instance will catch any exceptions, any
* exceptions thrown will convert a Success to a Failure
*
* This call is non-blocking.
*
* @param key
* To read
* @return Data as String
*/
public Try<Upload, Throwable> put(String key, Object value) {
return createObjectRequest(key, value).map(por -> {
Upload upload = manager.upload(por);
return upload;
});
}
private Try<PutObjectRequest, Throwable> createObjectRequest(String key, Object value) {
return writeToTmpFile(value).map(FluentFunctions.ofChecked(f -> {
byte[] ba = FileUtils.readFileToByteArray(f);
InputStream is = new ByteArrayInputStream(
ba);
ObjectMetadata md = createMetadata(ba.length);
PutObjectRequest pr = new PutObjectRequest(
bucket, key, is, md);
return pr;
}));
}
private Try<File, Throwable> writeToTmpFile(Object value) {
String fileName = "" + System.currentTimeMillis() + "_" + r.nextLong();
File file = new File(
dir, fileName);
return Try.of(1, Throwable.class)
.map(FluentFunctions.ofChecked(i -> {
FileOutputStream fs = new FileOutputStream(
file);
ObjectOutputStream oos = new ObjectOutputStream(
fs);
oos.writeObject(value);
oos.flush();
oos.close();
return file;
}));
}
/**
* Metadata object creation
* @param length
*
* @return Metadata with AES_256 encryption if enabled
*/
private ObjectMetadata createMetadata(int length) {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(length);
if (aes256Encryption)
metadata.setSSEAlgorithm(ObjectMetadata.AES_256_SERVER_SIDE_ENCRYPTION);
return metadata;
}
/**
* Blocking call
*
* @param key
* with which to store data
* @param value
* Data value
* @return Try with completed result of operation
*/
public Try<UploadResult, Throwable> putSync(String key, Object value) {
return put(key, value).map(FluentFunctions.ofChecked(i -> i.waitForUploadResult()));
}
/**
* Non-blocking call that will throw any Exceptions in the traditional
* manner on access
*
* @param key
* @param value
* @return
*/
public Eval<UploadResult> putAsync(String key, Object value) {
return Eval.later(() -> put(key, value))
.map(t -> t.get())
.map(FluentFunctions.ofChecked(up -> up.waitForUploadResult()));
}
}