added implementation of file storage service

This commit is contained in:
Fredrik Teschke
2015-01-23 11:15:28 +01:00
parent 72a9d6890e
commit 16f35c1b24
15 changed files with 314 additions and 85 deletions
@@ -5,3 +5,8 @@ Bundle-SymbolicName: com.sap.sse.filestorage
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Export-Package: com.sap.sse.filestorage,
com.sap.sse.filestorage.impl
Import-Package: org.osgi.framework;version="1.8.0"
Bundle-Activator: com.sap.sse.filestorage.impl.Activator
Require-Bundle: org.apache.servicemix.bundles.aws-java-sdk;bundle-version="1.9.8"
@@ -0,0 +1,30 @@
package com.sap.sse.filestorage;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
/**
* Service for storing files. The interface is intentionally agnostic of the underlying implementation,
* which may be provided e.g. by using Amazon's S3 or simply saving the files to a statically reachable
* directory on one of our servers.
* Implementations of this service are announced via the OSGi service registry.
*
* TODO The storage service to use should be configured via the AdminConsole. Upon auto-discovering the
* available services, the AdminConsole should allow to edit properties for each service (e.g. access
* credentials for AWS S3). We probably need a generic property discovery mechanism (key-value based?),
* and to survive server restarts these properties should be saved to the MongoDB.
* @author Fredrik Teschke
*
*/
public interface FileStorageService {
/**
* @param originalFileName may be {@code null}
*/
URI storeFile(InputStream is, String originalFileName, long lengthInBytes) throws IOException;
/**
* From the given {@code uri} it should be possible to determine the file to remove.
*/
void removeFile(URI uri);
}
@@ -0,0 +1,20 @@
package com.sap.sse.filestorage.impl;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import com.sap.sse.filestorage.FileStorageService;
public class Activator implements BundleActivator {
@Override
public void start(BundleContext context) throws Exception {
context.registerService(FileStorageService.class, new AmazonS3FileStorageServiceImpl(), null);
}
@Override
public void stop(BundleContext context) throws Exception {
}
}
@@ -0,0 +1,96 @@
package com.sap.sse.filestorage.impl;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.amazonaws.AmazonClientException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.DeleteObjectRequest;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.sap.sse.filestorage.FileStorageService;
/**
* For testing purposes configure the access credentials as follows:
* To link this service to an AWS account, create the following file: ~/.aws/credentials
* and add credentials to it (get the access id and secret key from
* https://console.aws.amazon.com/iam/home?#security_credential).
*
* TODO configure credentials in AdminConsole
* TODO configure bucket name in AdminConsole
*
* @author Fredrik Teschke
*
*/
public class AmazonS3FileStorageServiceImpl implements FileStorageService {
private static final Logger logger = Logger.getLogger(AmazonS3FileStorageServiceImpl.class.getName());
private static final String baseUrl = "s3.amazonaws.com";
private static final String retrievalProtocol = "http";
private static final String bucketName = "ftes-sap-sailing";
private final AmazonS3 s3;
public AmazonS3FileStorageServiceImpl() {
/*
* The ProfileCredentialsProvider will return your [default]
* credential profile by reading from the credentials file located at
* (~/.aws/credentials).
*/
AWSCredentials credentials = null;
try {
credentials = new ProfileCredentialsProvider().getCredentials();
} catch (Exception e) {
throw new AmazonClientException(
"Cannot load the credentials from the credential profiles file. " +
"Please make sure that your credentials file is at the correct " +
"location (~/.aws/credentials), and is in valid format.",
e);
}
s3 = new AmazonS3Client(credentials);
}
private static String getKey(String originalFileName) {
String key = UUID.randomUUID().toString();
if (originalFileName != null) {
key += "/" + originalFileName;
}
return key;
}
private static URI getUri(String key) {
try {
return new URI(retrievalProtocol, bucketName + "." + baseUrl, key, null);
} catch (URISyntaxException e) {
logger.log(Level.WARNING, "Could not create URI for uploaded file with key " + key, e);
return null;
}
}
@Override
public URI storeFile(InputStream is, String originalFileName, long lengthInBytes) {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(lengthInBytes);
String key = getKey(originalFileName);
PutObjectRequest request = new PutObjectRequest(bucketName, key, is, metadata)
.withCannedAcl(CannedAccessControlList.PublicRead);
s3.putObject(request);
return getUri(key);
}
@Override
public void removeFile(URI uri) {
String key = uri.getPath();
s3.deleteObject(new DeleteObjectRequest(bucketName, key));
}
}