mirror of https://github.com/apache/jclouds.git
Issue 116: rolled s3 into aws
git-svn-id: http://jclouds.googlecode.com/svn/trunk@2235 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
99ba4498ec
commit
870becd3f1
|
@ -34,7 +34,7 @@
|
|||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-aws-core</artifactId>
|
||||
<artifactId>jclouds-aws</artifactId>
|
||||
<name>jclouds Amazon AWS Components Core</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>jclouds Core components to access Amazon AWS</description>
|
||||
|
|
|
@ -44,7 +44,7 @@ public class AWSResponseException extends HttpResponseException {
|
|||
private AWSError error = new AWSError();
|
||||
|
||||
public AWSResponseException(HttpCommand command, HttpResponse response, AWSError error) {
|
||||
super(String.format("command %s failed with code %s, error: %s", command.toString(), response
|
||||
super(String.format("request %s failed with code %s, error: %s", command.getRequest().getRequestLine(), response
|
||||
.getStatusCode(), error.toString()), command, response);
|
||||
this.setError(error);
|
||||
|
||||
|
@ -52,7 +52,7 @@ public class AWSResponseException extends HttpResponseException {
|
|||
|
||||
public AWSResponseException(HttpCommand command, HttpResponse response, AWSError error,
|
||||
Throwable cause) {
|
||||
super(String.format("command %1$s failed with error: %2$s", command.toString(), error
|
||||
super(String.format("request %1$s failed with error: %2$s", command.getRequest().getRequestLine(), error
|
||||
.toString()), command, response, cause);
|
||||
this.setError(error);
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.jclouds.http.pool.PoolConstants;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
public interface AWSConstants extends HttpConstants, PoolConstants {
|
||||
|
||||
public static final String ENDPOINT = "Endpoint";
|
||||
public static final String PROPERTY_AWS_SECRETACCESSKEY = "jclouds.aws.secretaccesskey";
|
||||
public static final String PROPERTY_AWS_ACCESSKEYID = "jclouds.aws.accesskeyid";
|
||||
|
||||
|
|
|
@ -29,13 +29,14 @@ import java.util.concurrent.TimeUnit;
|
|||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.aws.handlers.AWSClientErrorRetryHandler;
|
||||
import org.jclouds.aws.handlers.AWSRedirectionRetryHandler;
|
||||
import org.jclouds.aws.handlers.ParseAWSErrorFromXmlContent;
|
||||
import org.jclouds.aws.s3.S3;
|
||||
import org.jclouds.aws.s3.S3Client;
|
||||
import org.jclouds.aws.s3.filters.RequestAuthorizeSignature;
|
||||
import org.jclouds.aws.s3.handlers.AWSClientErrorRetryHandler;
|
||||
import org.jclouds.aws.s3.handlers.AWSRedirectionRetryHandler;
|
||||
import org.jclouds.aws.s3.handlers.ParseAWSErrorFromXmlContent;
|
||||
import org.jclouds.aws.s3.reference.S3Constants;
|
||||
import org.jclouds.aws.util.RequestSigner;
|
||||
import org.jclouds.concurrent.ExpirableSupplier;
|
||||
import org.jclouds.http.HttpErrorHandler;
|
||||
import org.jclouds.http.HttpRetryHandler;
|
||||
|
@ -67,6 +68,13 @@ public class S3RestClientModule extends AbstractModule {
|
|||
protected String provideTimeStamp(@TimeStamp Supplier<String> cache) {
|
||||
return cache.get();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
RequestSigner provideRequestSigner(RequestAuthorizeSignature in){
|
||||
return in;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* borrowing concurrency code to ensure that caching takes place properly
|
|
@ -38,7 +38,7 @@ import org.jclouds.blobstore.functions.CalculateSize;
|
|||
import org.jclouds.blobstore.functions.GenerateMD5;
|
||||
import org.jclouds.blobstore.functions.GenerateMD5Result;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
|
@ -52,7 +52,7 @@ public class S3ObjectImpl implements S3Object, Comparable<S3Object> {
|
|||
private final CalculateSize calculateSize;
|
||||
private final MutableObjectMetadata metadata;
|
||||
private Object data;
|
||||
private Multimap<String, String> allHeaders = HashMultimap.create();
|
||||
private Multimap<String, String> allHeaders = LinkedHashMultimap.create();
|
||||
private Long contentLength;
|
||||
|
||||
@Inject
|
|
@ -39,6 +39,7 @@ import javax.ws.rs.core.HttpHeaders;
|
|||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jclouds.aws.s3.reference.S3Constants;
|
||||
import org.jclouds.aws.util.RequestSigner;
|
||||
import org.jclouds.http.HttpConstants;
|
||||
import org.jclouds.http.HttpException;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
|
@ -58,7 +59,7 @@ import com.google.common.annotations.VisibleForTesting;
|
|||
*
|
||||
*/
|
||||
@Singleton
|
||||
public class RequestAuthorizeSignature implements HttpRequestFilter {
|
||||
public class RequestAuthorizeSignature implements HttpRequestFilter, RequestSigner {
|
||||
private final String[] firstHeadersToSign = new String[] { "Content-MD5",
|
||||
HttpHeaders.CONTENT_TYPE, HttpHeaders.DATE };
|
||||
|
|
@ -40,7 +40,7 @@ import org.jclouds.util.DateService;
|
|||
import org.joda.time.DateTime;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
|
@ -55,7 +55,7 @@ import com.google.common.collect.Multimap;
|
|||
* <p/>
|
||||
* S3Client connection = // get connection
|
||||
* <p/>
|
||||
* Multimap<String,String> metadata = HashMultimap.create();
|
||||
* Multimap<String,String> metadata = LinkedHashMultimap.create();
|
||||
* metadata.put("x-amz-meta-adrian", "foo");
|
||||
* <p/>
|
||||
* // this will copy the object, provided it wasn't modified since yesterday.
|
||||
|
@ -256,7 +256,7 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
|
|||
@Override
|
||||
public Multimap<String, String> buildRequestHeaders() {
|
||||
checkState(metadataPrefix != null, "metadataPrefix should have been injected!");
|
||||
Multimap<String, String> returnVal = HashMultimap.create();
|
||||
Multimap<String, String> returnVal = LinkedHashMultimap.create();
|
||||
returnVal.putAll(headers);
|
||||
if (metadata != null) {
|
||||
for (String key : metadata.keySet()) {
|
0
aws/s3/core/src/main/java/org/jclouds/aws/s3/package-info.java → aws/core/src/main/java/org/jclouds/aws/s3/package-info.java
Normal file → Executable file
0
aws/s3/core/src/main/java/org/jclouds/aws/s3/package-info.java → aws/core/src/main/java/org/jclouds/aws/s3/package-info.java
Normal file → Executable file
|
@ -36,7 +36,6 @@ public interface S3Constants extends AWSConstants, S3Headers {
|
|||
* S3 service's XML Namespace, as used in XML request and response documents.
|
||||
*/
|
||||
public static final String S3_REST_API_XML_NAMESPACE = "http://s3.amazonaws.com/doc/2006-03-01/";
|
||||
public static final String ENDPOINT = "Endpoint";
|
||||
public static final String PREFIX = "prefix";
|
||||
public static final String MARKER = "marker";
|
||||
public static final String MAX_KEYS = "max-keys";
|
19
aws/s3/core/src/main/java/org/jclouds/aws/s3/util/S3Utils.java → aws/core/src/main/java/org/jclouds/aws/s3/util/S3Utils.java
Normal file → Executable file
19
aws/s3/core/src/main/java/org/jclouds/aws/s3/util/S3Utils.java → aws/core/src/main/java/org/jclouds/aws/s3/util/S3Utils.java
Normal file → Executable file
|
@ -30,18 +30,15 @@ import java.io.ByteArrayInputStream;
|
|||
import java.io.InputStream;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.jclouds.aws.domain.AWSError;
|
||||
import org.jclouds.aws.s3.filters.RequestAuthorizeSignature;
|
||||
import org.jclouds.aws.s3.reference.S3Headers;
|
||||
import org.jclouds.aws.xml.ErrorHandler;
|
||||
import org.jclouds.aws.util.AWSUtils;
|
||||
import org.jclouds.blobstore.util.BlobStoreUtils;
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpException;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
|
||||
/**
|
||||
* Encryption, Hashing, and IO Utilities needed to sign and verify S3 requests and responses.
|
||||
|
@ -51,24 +48,14 @@ import org.jclouds.http.functions.ParseSax;
|
|||
public class S3Utils extends BlobStoreUtils {
|
||||
|
||||
@Inject
|
||||
RequestAuthorizeSignature signer;
|
||||
|
||||
@Inject
|
||||
ParseSax.Factory factory;
|
||||
|
||||
@Inject
|
||||
Provider<ErrorHandler> errorHandlerProvider;
|
||||
AWSUtils util;
|
||||
|
||||
public AWSError parseAWSErrorFromContent(HttpCommand command, HttpResponse response,
|
||||
InputStream content) throws HttpException {
|
||||
AWSError error = (AWSError) factory.create(errorHandlerProvider.get()).parse(content);
|
||||
AWSError error = util.parseAWSErrorFromContent(command, response, content);
|
||||
if (error.getRequestId() == null)
|
||||
error.setRequestId(response.getFirstHeaderOrNull(S3Headers.REQUEST_ID));
|
||||
error.setRequestToken(response.getFirstHeaderOrNull(S3Headers.REQUEST_TOKEN));
|
||||
if ("SignatureDoesNotMatch".equals(error.getCode())) {
|
||||
error.setStringSigned(signer.createStringToSign(command.getRequest()));
|
||||
error.setSignature(signer.signString(error.getStringSigned()));
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package org.jclouds.aws.util;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.jclouds.aws.domain.AWSError;
|
||||
import org.jclouds.aws.xml.ErrorHandler;
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpException;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
|
||||
/**
|
||||
* Needed to sign and verify requests and responses.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AWSUtils {
|
||||
|
||||
@Inject
|
||||
RequestSigner signer;
|
||||
|
||||
@Inject
|
||||
ParseSax.Factory factory;
|
||||
|
||||
@Inject
|
||||
Provider<ErrorHandler> errorHandlerProvider;
|
||||
|
||||
public AWSError parseAWSErrorFromContent(HttpCommand command, HttpResponse response,
|
||||
InputStream content) throws HttpException {
|
||||
AWSError error = (AWSError) factory.create(errorHandlerProvider.get()).parse(content);
|
||||
if ("SignatureDoesNotMatch".equals(error.getCode())) {
|
||||
error.setStringSigned(signer.createStringToSign(command.getRequest()));
|
||||
error.setSignature(signer.signString(error.getStringSigned()));
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
public AWSError parseAWSErrorFromContent(HttpCommand command, HttpResponse response,
|
||||
String content) throws HttpException {
|
||||
return parseAWSErrorFromContent(command, response, new ByteArrayInputStream(content
|
||||
.getBytes()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package org.jclouds.aws.util;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public interface RequestSigner {
|
||||
|
||||
String createStringToSign(HttpRequest input);
|
||||
|
||||
String signString(String toSign);
|
||||
|
||||
}
|
|
@ -73,6 +73,7 @@ import org.testng.annotations.Test;
|
|||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
|
@ -119,8 +120,8 @@ public class S3ClientTest extends RestClientTest<S3Client> {
|
|||
Method method = S3Client.class
|
||||
.getMethod("copyObject", String.class, String.class, String.class, String.class,
|
||||
Array.newInstance(CopyObjectOptions.class, 0).getClass());
|
||||
GeneratedHttpRequest<S3Client> httpMethod = processor.createRequest(method,
|
||||
"sourceBucket", "sourceObject", "destinationBucket", "destinationObject");
|
||||
GeneratedHttpRequest<S3Client> httpMethod = processor.createRequest(method, "sourceBucket",
|
||||
"sourceObject", "destinationBucket", "destinationObject");
|
||||
|
||||
assertRequestLineEquals(httpMethod,
|
||||
"PUT http://destinationBucket.stub:8080/destinationObject HTTP/1.1");
|
||||
|
@ -316,8 +317,8 @@ public class S3ClientTest extends RestClientTest<S3Client> {
|
|||
public void testPutObjectACL() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = S3Client.class.getMethod("putObjectACL", String.class, String.class,
|
||||
AccessControlList.class);
|
||||
GeneratedHttpRequest<S3Client> httpMethod = processor.createRequest(method, "bucket",
|
||||
"key", AccessControlList.fromCannedAccessPolicy(CannedAccessPolicy.PRIVATE, "1234"));
|
||||
GeneratedHttpRequest<S3Client> httpMethod = processor.createRequest(method, "bucket", "key",
|
||||
AccessControlList.fromCannedAccessPolicy(CannedAccessPolicy.PRIVATE, "1234"));
|
||||
|
||||
assertRequestLineEquals(httpMethod, "PUT http://bucket.stub:8080/key?acl HTTP/1.1");
|
||||
assertHeadersEqual(httpMethod,
|
||||
|
@ -368,15 +369,19 @@ public class S3ClientTest extends RestClientTest<S3Client> {
|
|||
.to("key");
|
||||
bindConstant().annotatedWith(
|
||||
Jsr330.named(BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX)).to("prefix");
|
||||
bindConstant().annotatedWith(TimeStamp.class).to("timestamp");
|
||||
bind(Logger.LoggerFactory.class).toInstance(new LoggerFactory() {
|
||||
public Logger getLogger(String category) {
|
||||
return Logger.NULL;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Provides
|
||||
@TimeStamp
|
||||
String provide() {
|
||||
return "timestamp";
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -26,9 +26,9 @@ package org.jclouds.aws.s3.config;
|
|||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
|
||||
import org.jclouds.aws.s3.handlers.AWSClientErrorRetryHandler;
|
||||
import org.jclouds.aws.s3.handlers.AWSRedirectionRetryHandler;
|
||||
import org.jclouds.aws.s3.handlers.ParseAWSErrorFromXmlContent;
|
||||
import org.jclouds.aws.handlers.AWSClientErrorRetryHandler;
|
||||
import org.jclouds.aws.handlers.AWSRedirectionRetryHandler;
|
||||
import org.jclouds.aws.handlers.ParseAWSErrorFromXmlContent;
|
||||
import org.jclouds.aws.s3.reference.S3Constants;
|
||||
import org.jclouds.concurrent.WithinThreadExecutorService;
|
||||
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
|
@ -53,7 +53,7 @@ public class CopyObjectHandlerTest extends BaseHandlerTest {
|
|||
}
|
||||
|
||||
public void testApplyInputStream() {
|
||||
InputStream is = getClass().getResourceAsStream("/copy_object.xml");
|
||||
InputStream is = getClass().getResourceAsStream("/s3/copy_object.xml");
|
||||
ObjectMetadata expected = new CopyObjectResult(new DateService()
|
||||
.iso8601DateParse("2009-03-19T13:23:27.000Z"), "\"92836a3ea45a6984d1b4d23a747d46bb\"");
|
||||
|
|
@ -60,7 +60,7 @@ public class ListBucketHandlerTest extends BaseHandlerTest {
|
|||
}
|
||||
|
||||
public void testApplyInputStream() {
|
||||
InputStream is = getClass().getResourceAsStream("/list_bucket.xml");
|
||||
InputStream is = getClass().getResourceAsStream("/s3/list_bucket.xml");
|
||||
CanonicalUser owner = new CanonicalUser(
|
||||
"e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0", "ferncam");
|
||||
ListBucketResponse expected = new TreeSetListBucketResponse(
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue