Issue 35: moved more common logic one layer up

git-svn-id: http://jclouds.googlecode.com/svn/trunk@844 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-05-24 19:54:30 +00:00
parent 4eced672f1
commit 8cc04bc588
31 changed files with 967 additions and 968 deletions

View File

@ -0,0 +1,81 @@
/**
*
* Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.aws;
import org.jclouds.aws.domain.AWSError;
import org.jclouds.http.HttpFutureCommand;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
/**
* Encapsulates an AWS Error from Amazon.
*
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingRESTError.html" />
* @see AWSError
* @see org.jclouds.aws.handlers.ParseAWSErrorFromXmlContent
* @author Adrian Cole
*
*/
public class AWSResponseException extends HttpResponseException {
private static final long serialVersionUID = 1L;
private AWSError error = new AWSError();
public AWSResponseException(HttpFutureCommand<?> command, HttpResponse response, AWSError error) {
super(error.toString(), command, response);
this.setError(error);
}
public AWSResponseException(HttpFutureCommand<?> command, HttpResponse response, AWSError error,
Throwable cause) {
super(error.toString(), command, response, cause);
this.setError(error);
}
public AWSResponseException(String message, HttpFutureCommand<?> command, HttpResponse response,
AWSError error) {
super(message, command, response);
this.setError(error);
}
public AWSResponseException(String message, HttpFutureCommand<?> command, HttpResponse response,
AWSError error, Throwable cause) {
super(message, command, response, cause);
this.setError(error);
}
public void setError(AWSError error) {
this.error = error;
}
public AWSError getError() {
return error;
}
}

View File

@ -21,7 +21,7 @@
* under the License. * under the License.
* ==================================================================== * ====================================================================
*/ */
package org.jclouds.aws.s3.domain; package org.jclouds.aws.domain;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -33,7 +33,7 @@ import java.util.Map;
* @author Adrian Cole * @author Adrian Cole
* *
*/ */
public class S3Error { public class AWSError {
private String code; private String code;
private String message; private String message;
private String requestId; private String requestId;

View File

@ -0,0 +1,39 @@
/**
*
* Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.aws.reference;
import org.jclouds.command.pool.PoolConstants;
import org.jclouds.http.HttpConstants;
/**
* Configuration properties and constants used in AWS connections.
*
* @author Adrian Cole
*/
public interface AWSConstants extends HttpConstants, PoolConstants {
public static final String PROPERTY_AWS_SECRETACCESSKEY = "jclouds.aws.secretaccesskey";
public static final String PROPERTY_AWS_ACCESSKEYID = "jclouds.aws.accesskeyid";
}

View File

@ -11,8 +11,10 @@ import java.security.NoSuchProviderException;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.MD5Digest; import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Base64;
@ -52,9 +54,14 @@ public class AWSUtils extends Utils {
return bytes; return bytes;
} }
public static String hmacSha1Base64(String toEncode, byte[] key) public static String hmacSha256Base64(String toEncode, byte[] key)
throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException { throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException {
HMac hmac = new HMac(new SHA1Digest()); Digest digest = new SHA256Digest();
return hmacBase64(toEncode, key, digest);
}
private static String hmacBase64(String toEncode, byte[] key, Digest digest) {
HMac hmac = new HMac(digest);
byte[] resBuf = new byte[hmac.getMacSize()]; byte[] resBuf = new byte[hmac.getMacSize()];
byte[] plainBytes = toEncode.getBytes(); byte[] plainBytes = toEncode.getBytes();
byte[] keyBytes = key; byte[] keyBytes = key;
@ -64,6 +71,12 @@ public class AWSUtils extends Utils {
return toBase64String(resBuf); return toBase64String(resBuf);
} }
public static String hmacSha1Base64(String toEncode, byte[] key)
throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException {
Digest digest = new SHA1Digest();
return hmacBase64(toEncode, key, digest);
}
public static String md5Hex(byte[] toEncode) throws NoSuchAlgorithmException, public static String md5Hex(byte[] toEncode) throws NoSuchAlgorithmException,
NoSuchProviderException, InvalidKeyException, UnsupportedEncodingException { NoSuchProviderException, InvalidKeyException, UnsupportedEncodingException {
byte[] resBuf = md5(toEncode); byte[] resBuf = md5(toEncode);

View File

@ -0,0 +1,63 @@
/**
*
* Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.aws.xml;
import org.jclouds.aws.domain.AWSError;
import org.jclouds.http.commands.callables.xml.ParseSax;
/**
* Parses the error from the Amazon S3 REST API.
*
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?UsingRESTError.html"
* />
* @author Adrian Cole
*/
public class ErrorHandler extends ParseSax.HandlerWithResult<AWSError> {
private AWSError error = new AWSError();
private StringBuilder currentText = new StringBuilder();
public AWSError getResult() {
return error;
}
public void endElement(String uri, String name, String qName) {
if (qName.equals("Code")) {
error.setCode(currentText.toString());
} else if (qName.equals("Message")) {
error.setMessage(currentText.toString());
} else if (qName.equalsIgnoreCase("RequestId")) {
error.setRequestId(currentText.toString());
} else if (!qName.equals("Error")) {
error.getDetails().put(qName, currentText.toString());
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -1,82 +0,0 @@
/**
*
* Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.aws.s3;
import org.jclouds.aws.s3.domain.S3Error;
import org.jclouds.http.HttpFutureCommand;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
/**
* Encapsulates an S3 Error from Amazon.
*
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingRESTError.html" />
* @see S3Error
* @see org.jclouds.aws.s3.handlers.ParseS3ErrorFromXmlContent
* @author Adrian Cole
*
*/
public class S3ResponseException extends HttpResponseException {
private static final long serialVersionUID = 1L;
private S3Error error = new S3Error();
public S3ResponseException(HttpFutureCommand<?> command,
HttpResponse response, S3Error error) {
super(error.toString(), command, response);
this.setError(error);
}
public S3ResponseException(HttpFutureCommand<?> command,
HttpResponse response, S3Error error, Throwable cause) {
super(error.toString(), command, response, cause);
this.setError(error);
}
public S3ResponseException(String message, HttpFutureCommand<?> command,
HttpResponse response, S3Error error) {
super(message, command, response);
this.setError(error);
}
public S3ResponseException(String message, HttpFutureCommand<?> command,
HttpResponse response, S3Error error, Throwable cause) {
super(message, command, response, cause);
this.setError(error);
}
public void setError(S3Error error) {
this.error = error;
}
public S3Error getError() {
return error;
}
}

View File

@ -27,7 +27,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import org.jclouds.aws.s3.S3ResponseException; import org.jclouds.aws.AWSResponseException;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
import org.jclouds.http.commands.callables.ReturnTrueIf2xx; import org.jclouds.http.commands.callables.ReturnTrueIf2xx;
@ -68,7 +68,7 @@ public class DeleteBucket extends S3FutureCommand<Boolean> {
Boolean attemptNotFound(ExecutionException e) throws ExecutionException { Boolean attemptNotFound(ExecutionException e) throws ExecutionException {
if (e.getCause() != null if (e.getCause() != null
&& e.getCause() instanceof HttpResponseException) { && e.getCause() instanceof HttpResponseException) {
S3ResponseException responseException = (S3ResponseException) e AWSResponseException responseException = (AWSResponseException) e
.getCause(); .getCause();
if (responseException.getResponse().getStatusCode() == 404) { if (responseException.getResponse().getStatusCode() == 404) {
return true; return true;

View File

@ -29,7 +29,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import org.jclouds.aws.s3.S3ResponseException; import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.s3.commands.callables.ParseObjectFromHeadersAndHttpContent; import org.jclouds.aws.s3.commands.callables.ParseObjectFromHeadersAndHttpContent;
import org.jclouds.aws.s3.commands.options.GetObjectOptions; import org.jclouds.aws.s3.commands.options.GetObjectOptions;
import org.jclouds.aws.s3.domain.S3Object; import org.jclouds.aws.s3.domain.S3Object;
@ -40,20 +40,16 @@ import com.google.inject.assistedinject.Assisted;
import com.google.inject.name.Named; import com.google.inject.name.Named;
/** /**
* Retrieves the S3Object associated with the Key or {@link S3Object#NOT_FOUND} * Retrieves the S3Object associated with the Key or {@link S3Object#NOT_FOUND} if not available;
* if not available;
* *
* <p/> * <p/>
* To use GET, you must have READ access to the object. If READ access is * To use GET, you must have READ access to the object. If READ access is granted to the anonymous
* granted to the anonymous user, you can request the object without an * user, you can request the object without an authorization header.
* authorization header.
* <p /> * <p />
* <p/> * <p/>
* This command allows you to specify {@link GetObjectOptions} to control * This command allows you to specify {@link GetObjectOptions} to control delivery of content.
* delivery of content.
* *
* <h2>Note</h2> If you specify any of the below options, you will receive * <h2>Note</h2> If you specify any of the below options, you will receive partial content:
* partial content:
* <ul> * <ul>
* <li>{@link GetObjectOptions#range}</li> * <li>{@link GetObjectOptions#range}</li>
* <li>{@link GetObjectOptions#startAt}</li> * <li>{@link GetObjectOptions#startAt}</li>
@ -61,49 +57,49 @@ import com.google.inject.name.Named;
* </ul> * </ul>
* *
* @see GetObjectOptions * @see GetObjectOptions
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTObjectGET.html" /> * @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTObjectGET.html"
* />
* @author Adrian Cole * @author Adrian Cole
*/ */
public class GetObject extends S3FutureCommand<S3Object> { public class GetObject extends S3FutureCommand<S3Object> {
@Inject @Inject
public GetObject(@Named("jclouds.http.address") String amazonHost, public GetObject(@Named("jclouds.http.address") String amazonHost,
ParseObjectFromHeadersAndHttpContent callable, ParseObjectFromHeadersAndHttpContent callable, @Assisted("bucketName") String s3Bucket,
@Assisted("bucketName") String s3Bucket, @Assisted("key") String key, @Assisted GetObjectOptions options) {
@Assisted("key") String key, @Assisted GetObjectOptions options) { super("GET", "/" + checkNotNull(key), callable, amazonHost, s3Bucket);
super("GET", "/" + checkNotNull(key), callable, amazonHost, s3Bucket); this.getRequest().getHeaders().putAll(options.buildRequestHeaders());
this.getRequest().getHeaders().putAll(options.buildRequestHeaders()); callable.setKey(key);
callable.setKey(key); }
}
@Override @Override
public S3Object get() throws InterruptedException, ExecutionException { public S3Object get() throws InterruptedException, ExecutionException {
try { try {
return super.get(); return super.get();
} catch (ExecutionException e) { } catch (ExecutionException e) {
return attemptNotFound(e); return attemptNotFound(e);
} }
} }
@VisibleForTesting @VisibleForTesting
S3Object attemptNotFound(ExecutionException e) throws ExecutionException { S3Object attemptNotFound(ExecutionException e) throws ExecutionException {
if (e.getCause() != null && e.getCause() instanceof S3ResponseException) { if (e.getCause() != null && e.getCause() instanceof AWSResponseException) {
S3ResponseException responseException = (S3ResponseException) e AWSResponseException responseException = (AWSResponseException) e.getCause();
.getCause(); if ("NoSuchKey".equals(responseException.getError().getCode())) {
if ("NoSuchKey".equals(responseException.getError().getCode())) { return S3Object.NOT_FOUND;
return S3Object.NOT_FOUND; }
} }
} throw e;
throw e; }
}
@Override @Override
public S3Object get(long l, TimeUnit timeUnit) throws InterruptedException, public S3Object get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException,
ExecutionException, TimeoutException { TimeoutException {
try { try {
return super.get(l, timeUnit); return super.get(l, timeUnit);
} catch (ExecutionException e) { } catch (ExecutionException e) {
return attemptNotFound(e); return attemptNotFound(e);
} }
} }
} }

View File

@ -27,7 +27,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import org.jclouds.aws.s3.S3ResponseException; import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.s3.commands.options.ListBucketOptions; import org.jclouds.aws.s3.commands.options.ListBucketOptions;
import org.jclouds.aws.s3.domain.S3Bucket; import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.aws.s3.xml.ListBucketHandler; import org.jclouds.aws.s3.xml.ListBucketHandler;
@ -40,61 +40,57 @@ import com.google.inject.assistedinject.Assisted;
import com.google.inject.name.Named; import com.google.inject.name.Named;
/** /**
* A GET request operation using a bucket URI lists information about the * A GET request operation using a bucket URI lists information about the objects in the bucket.
* objects in the bucket.
* <p /> * <p />
* To list the keys of a bucket, you must have READ access to the bucket. * To list the keys of a bucket, you must have READ access to the bucket.
* <p/> * <p/>
* List output is controllable via {@link ListBucketOptions} * List output is controllable via {@link ListBucketOptions}
* *
* @see ListBucketOptions * @see ListBucketOptions
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketGET.html" * @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketGET.html"
* /> * />
* @author Adrian Cole * @author Adrian Cole
* *
*/ */
public class ListBucket extends S3FutureCommand<S3Bucket> { public class ListBucket extends S3FutureCommand<S3Bucket> {
@Inject @Inject
public ListBucket(@Named("jclouds.http.address") String amazonHost, public ListBucket(@Named("jclouds.http.address") String amazonHost,
ParseSax<S3Bucket> bucketParser, @Assisted String bucket, ParseSax<S3Bucket> bucketParser, @Assisted String bucket,
@Assisted ListBucketOptions options) { @Assisted ListBucketOptions options) {
super("GET", "/" + options.buildQueryString(), bucketParser, super("GET", "/" + options.buildQueryString(), bucketParser, amazonHost, bucket);
amazonHost, bucket); ListBucketHandler handler = (ListBucketHandler) bucketParser.getHandler();
ListBucketHandler handler = (ListBucketHandler) bucketParser handler.setBucketName(bucket);
.getHandler(); }
handler.setBucketName(bucket);
}
@Override @Override
public S3Bucket get() throws InterruptedException, ExecutionException { public S3Bucket get() throws InterruptedException, ExecutionException {
try { try {
return super.get(); return super.get();
} catch (ExecutionException e) { } catch (ExecutionException e) {
return attemptNotFound(e); return attemptNotFound(e);
} }
} }
@VisibleForTesting @VisibleForTesting
S3Bucket attemptNotFound(ExecutionException e) throws ExecutionException { S3Bucket attemptNotFound(ExecutionException e) throws ExecutionException {
if (e.getCause() != null if (e.getCause() != null && e.getCause() instanceof HttpResponseException) {
&& e.getCause() instanceof HttpResponseException) { AWSResponseException responseException = (AWSResponseException) e.getCause();
S3ResponseException responseException = (S3ResponseException) e if ("NoSuchBucket".equals(responseException.getError().getCode())) {
.getCause(); return S3Bucket.NOT_FOUND;
if ("NoSuchBucket".equals(responseException.getError().getCode())) { }
return S3Bucket.NOT_FOUND; }
} throw e;
} }
throw e;
}
@Override @Override
public S3Bucket get(long l, TimeUnit timeUnit) throws InterruptedException, public S3Bucket get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException,
ExecutionException, TimeoutException { TimeoutException {
try { try {
return super.get(l, timeUnit); return super.get(l, timeUnit);
} catch (ExecutionException e) { } catch (ExecutionException e) {
return attemptNotFound(e); return attemptNotFound(e);
} }
} }
} }

View File

@ -30,7 +30,7 @@ import javax.annotation.Resource;
import org.jclouds.aws.s3.S3Connection; import org.jclouds.aws.s3.S3Connection;
import org.jclouds.aws.s3.filters.RequestAuthorizeSignature; import org.jclouds.aws.s3.filters.RequestAuthorizeSignature;
import org.jclouds.aws.s3.handlers.ParseS3ErrorFromXmlContent; import org.jclouds.aws.s3.handlers.ParseAWSErrorFromXmlContent;
import org.jclouds.aws.s3.internal.LiveS3Connection; import org.jclouds.aws.s3.internal.LiveS3Connection;
import org.jclouds.http.HttpConstants; import org.jclouds.http.HttpConstants;
import org.jclouds.http.HttpRequestFilter; import org.jclouds.http.HttpRequestFilter;
@ -74,9 +74,9 @@ public class LiveS3ConnectionModule extends AbstractModule {
bind(HttpResponseHandler.class).annotatedWith(RedirectHandler.class).to( bind(HttpResponseHandler.class).annotatedWith(RedirectHandler.class).to(
CloseContentAndSetExceptionHandler.class).in(Scopes.SINGLETON); CloseContentAndSetExceptionHandler.class).in(Scopes.SINGLETON);
bind(HttpResponseHandler.class).annotatedWith(ClientErrorHandler.class).to( bind(HttpResponseHandler.class).annotatedWith(ClientErrorHandler.class).to(
ParseS3ErrorFromXmlContent.class).in(Scopes.SINGLETON); ParseAWSErrorFromXmlContent.class).in(Scopes.SINGLETON);
bind(HttpResponseHandler.class).annotatedWith(ServerErrorHandler.class).to( bind(HttpResponseHandler.class).annotatedWith(ServerErrorHandler.class).to(
ParseS3ErrorFromXmlContent.class).in(Scopes.SINGLETON); ParseAWSErrorFromXmlContent.class).in(Scopes.SINGLETON);
requestInjection(this); requestInjection(this);
logger.info("S3 Context = %1$s://%2$s:%3$s", (isSecure ? "https" : "http"), address, port); logger.info("S3 Context = %1$s://%2$s:%3$s", (isSecure ? "https" : "http"), address, port);
} }

View File

@ -1,86 +0,0 @@
/**
*
* Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.aws.s3.handlers;
import java.io.InputStream;
import javax.annotation.Resource;
import org.apache.commons.io.IOUtils;
import org.jclouds.aws.s3.S3ResponseException;
import org.jclouds.aws.s3.domain.S3Error;
import org.jclouds.aws.s3.filters.RequestAuthorizeSignature;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.aws.s3.xml.S3ParserFactory;
import org.jclouds.http.HttpFutureCommand;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseHandler;
import org.jclouds.logging.Logger;
import com.google.inject.Inject;
/**
* This will parse and set an appropriate exception on the command object.
*
* @see S3Error
* @author Adrian Cole
*
*/
public class ParseS3ErrorFromXmlContent implements HttpResponseHandler {
@Resource
protected Logger logger = Logger.NULL;
private final S3ParserFactory parserFactory;
@Inject
public ParseS3ErrorFromXmlContent(S3ParserFactory parserFactory) {
this.parserFactory = parserFactory;
}
public void handle(HttpFutureCommand<?> command, HttpResponse response) {
S3Error error = new S3Error();
error.setRequestId(response.getFirstHeaderOrNull(S3Headers.REQUEST_ID));
error.setRequestToken(response
.getFirstHeaderOrNull(S3Headers.REQUEST_TOKEN));
InputStream errorStream = response.getContent();
try {
if (errorStream != null) {
error = parserFactory.createErrorParser().parse(errorStream);
if ("SignatureDoesNotMatch".equals(error.getCode()))
error.setStringSigned(RequestAuthorizeSignature
.createStringToSign(command.getRequest()));
error.setRequestToken(response
.getFirstHeaderOrNull(S3Headers.REQUEST_TOKEN));
}
} catch (Exception e) {
logger.warn(e, "error parsing XML reponse: %1$s", response);
} finally {
command.setException(new S3ResponseException(command, response,
error));
IOUtils.closeQuietly(errorStream);
}
}
}

View File

@ -23,18 +23,15 @@
*/ */
package org.jclouds.aws.s3.reference; package org.jclouds.aws.s3.reference;
import org.jclouds.command.pool.PoolConstants; import org.jclouds.aws.reference.AWSConstants;
import org.jclouds.http.HttpConstants;
/** /**
* Configuration properties and constants used in S3 connections. * Configuration properties and constants used in S3 connections.
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public interface S3Constants extends HttpConstants, PoolConstants, S3Headers { public interface S3Constants extends AWSConstants, S3Headers {
public static final String PROPERTY_AWS_SECRETACCESSKEY = "jclouds.aws.secretaccesskey";
public static final String PROPERTY_AWS_ACCESSKEYID = "jclouds.aws.accesskeyid";
/** /**
* longest time a single Map operation can take before throwing an exception. * longest time a single Map operation can take before throwing an exception.
*/ */

View File

@ -25,9 +25,10 @@ package org.jclouds.aws.s3.xml;
import java.util.List; import java.util.List;
import org.jclouds.aws.domain.AWSError;
import org.jclouds.aws.s3.domain.S3Bucket; import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.aws.s3.domain.S3Error;
import org.jclouds.aws.s3.domain.S3Object; import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.xml.ErrorHandler;
import org.jclouds.http.commands.callables.xml.ParseSax; import org.jclouds.http.commands.callables.xml.ParseSax;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
@ -88,7 +89,7 @@ public class S3ParserFactory {
} }
@Inject @Inject
private GenericParseFactory<S3Error> parseErrorFactory; private GenericParseFactory<AWSError> parseErrorFactory;
@Inject @Inject
Provider<ErrorHandler> errorHandlerProvider; Provider<ErrorHandler> errorHandlerProvider;
@ -96,7 +97,7 @@ public class S3ParserFactory {
/** /**
* @return a parser used to handle error conditions. * @return a parser used to handle error conditions.
*/ */
public ParseSax<S3Error> createErrorParser() { public ParseSax<AWSError> createErrorParser() {
return parseErrorFactory.create(errorHandlerProvider.get()); return parseErrorFactory.create(errorHandlerProvider.get());
} }

View File

@ -25,14 +25,14 @@ package org.jclouds.aws.s3.xml.config;
import java.util.List; import java.util.List;
import org.jclouds.aws.domain.AWSError;
import org.jclouds.aws.s3.domain.S3Bucket; import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.aws.s3.domain.S3Error;
import org.jclouds.aws.s3.domain.S3Object; import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.xml.CopyObjectHandler; import org.jclouds.aws.s3.xml.CopyObjectHandler;
import org.jclouds.aws.s3.xml.ErrorHandler;
import org.jclouds.aws.s3.xml.ListAllMyBucketsHandler; import org.jclouds.aws.s3.xml.ListAllMyBucketsHandler;
import org.jclouds.aws.s3.xml.ListBucketHandler; import org.jclouds.aws.s3.xml.ListBucketHandler;
import org.jclouds.aws.s3.xml.S3ParserFactory; import org.jclouds.aws.s3.xml.S3ParserFactory;
import org.jclouds.aws.xml.ErrorHandler;
import org.jclouds.http.commands.callables.xml.ParseSax; import org.jclouds.http.commands.callables.xml.ParseSax;
import org.jclouds.http.commands.callables.xml.config.SaxModule; import org.jclouds.http.commands.callables.xml.config.SaxModule;
@ -46,51 +46,48 @@ import com.google.inject.assistedinject.FactoryProvider;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class S3ParserModule extends AbstractModule { public class S3ParserModule extends AbstractModule {
private final TypeLiteral<S3ParserFactory.GenericParseFactory<List<S3Bucket.Metadata>>> listBucketsTypeLiteral = new TypeLiteral<S3ParserFactory.GenericParseFactory<List<S3Bucket.Metadata>>>() { private final TypeLiteral<S3ParserFactory.GenericParseFactory<List<S3Bucket.Metadata>>> listBucketsTypeLiteral = new TypeLiteral<S3ParserFactory.GenericParseFactory<List<S3Bucket.Metadata>>>() {
}; };
private final TypeLiteral<S3ParserFactory.GenericParseFactory<S3Bucket>> bucketTypeLiteral = new TypeLiteral<S3ParserFactory.GenericParseFactory<S3Bucket>>() { private final TypeLiteral<S3ParserFactory.GenericParseFactory<S3Bucket>> bucketTypeLiteral = new TypeLiteral<S3ParserFactory.GenericParseFactory<S3Bucket>>() {
}; };
private final TypeLiteral<S3ParserFactory.GenericParseFactory<S3Object.Metadata>> objectMetadataTypeLiteral = new TypeLiteral<S3ParserFactory.GenericParseFactory<S3Object.Metadata>>() { private final TypeLiteral<S3ParserFactory.GenericParseFactory<S3Object.Metadata>> objectMetadataTypeLiteral = new TypeLiteral<S3ParserFactory.GenericParseFactory<S3Object.Metadata>>() {
}; };
private final TypeLiteral<S3ParserFactory.GenericParseFactory<S3Error>> errorTypeLiteral = new TypeLiteral<S3ParserFactory.GenericParseFactory<S3Error>>() { private final TypeLiteral<S3ParserFactory.GenericParseFactory<AWSError>> errorTypeLiteral = new TypeLiteral<S3ParserFactory.GenericParseFactory<AWSError>>() {
}; };
@Override @Override
protected void configure() { protected void configure() {
install(new SaxModule()); install(new SaxModule());
bindCallablesThatReturnParseResults(); bindCallablesThatReturnParseResults();
bindParserImplementationsToReturnTypes(); bindParserImplementationsToReturnTypes();
} }
private void bindParserImplementationsToReturnTypes() { private void bindParserImplementationsToReturnTypes() {
bind( bind(new TypeLiteral<ParseSax.HandlerWithResult<List<S3Bucket.Metadata>>>() {
new TypeLiteral<ParseSax.HandlerWithResult<List<S3Bucket.Metadata>>>() { }).to(ListAllMyBucketsHandler.class);
}).to(ListAllMyBucketsHandler.class); bind(new TypeLiteral<ParseSax.HandlerWithResult<S3Bucket>>() {
bind(new TypeLiteral<ParseSax.HandlerWithResult<S3Bucket>>() { }).to(ListBucketHandler.class);
}).to(ListBucketHandler.class); bind(new TypeLiteral<ParseSax.HandlerWithResult<S3Object.Metadata>>() {
bind(new TypeLiteral<ParseSax.HandlerWithResult<S3Object.Metadata>>() { }).to(CopyObjectHandler.class);
}).to(CopyObjectHandler.class); bind(new TypeLiteral<ParseSax.HandlerWithResult<AWSError>>() {
bind(new TypeLiteral<ParseSax.HandlerWithResult<S3Error>>() { }).to(ErrorHandler.class);
}).to(ErrorHandler.class); }
}
private void bindCallablesThatReturnParseResults() { private void bindCallablesThatReturnParseResults() {
bind(listBucketsTypeLiteral).toProvider( bind(listBucketsTypeLiteral).toProvider(
FactoryProvider.newFactory(listBucketsTypeLiteral, FactoryProvider.newFactory(listBucketsTypeLiteral,
new TypeLiteral<ParseSax<List<S3Bucket.Metadata>>>() { new TypeLiteral<ParseSax<List<S3Bucket.Metadata>>>() {
})); }));
bind(bucketTypeLiteral).toProvider( bind(bucketTypeLiteral).toProvider(
FactoryProvider.newFactory(bucketTypeLiteral, FactoryProvider.newFactory(bucketTypeLiteral, new TypeLiteral<ParseSax<S3Bucket>>() {
new TypeLiteral<ParseSax<S3Bucket>>() { }));
})); bind(objectMetadataTypeLiteral).toProvider(
bind(objectMetadataTypeLiteral).toProvider( FactoryProvider.newFactory(objectMetadataTypeLiteral,
FactoryProvider.newFactory(objectMetadataTypeLiteral, new TypeLiteral<ParseSax<S3Object.Metadata>>() {
new TypeLiteral<ParseSax<S3Object.Metadata>>() { }));
})); bind(errorTypeLiteral).toProvider(
bind(errorTypeLiteral).toProvider( FactoryProvider.newFactory(errorTypeLiteral, new TypeLiteral<ParseSax<AWSError>>() {
FactoryProvider.newFactory(errorTypeLiteral, }));
new TypeLiteral<ParseSax<S3Error>>() { }
}));
}
} }

View File

@ -130,9 +130,9 @@ public class S3IntegrationTest {
protected String bucketPrefix = (System.getProperty("user.name") + "." + this.getClass() protected String bucketPrefix = (System.getProperty("user.name") + "." + this.getClass()
.getSimpleName()).toLowerCase(); .getSimpleName()).toLowerCase();
private static final String sysAWSAccessKeyId = System protected static final String sysAWSAccessKeyId = System
.getProperty(S3Constants.PROPERTY_AWS_ACCESSKEYID); .getProperty(S3Constants.PROPERTY_AWS_ACCESSKEYID);
private static final String sysAWSSecretAccessKey = System protected static final String sysAWSSecretAccessKey = System
.getProperty(S3Constants.PROPERTY_AWS_SECRETACCESSKEY); .getProperty(S3Constants.PROPERTY_AWS_SECRETACCESSKEY);
@BeforeClass(inheritGroups = false, groups = { "integration", "live" }) @BeforeClass(inheritGroups = false, groups = { "integration", "live" })

View File

@ -304,34 +304,43 @@ public class StubS3Connection implements S3Connection {
contents.remove(lastMarkerMetadata); contents.remove(lastMarkerMetadata);
returnVal.setMarker(marker); returnVal.setMarker(marker);
} }
try {
if (options.getPrefix() != null) { if (options.getPrefix() != null) {
contents = Sets.newTreeSet(Iterables.filter(contents, contents = Sets.newTreeSet(Iterables.filter(contents,
new Predicate<S3Object.Metadata>() { new Predicate<S3Object.Metadata>() {
public boolean apply(S3Object.Metadata o) {
try {
return (o != null && o.getKey().startsWith(
URLDecoder.decode(options.getPrefix(), "UTF-8")));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}));
returnVal.setPrefix(URLDecoder.decode(options.getPrefix(), "UTF-8"));
}
public boolean apply(S3Object.Metadata o) { if (options.getDelimiter() != null) {
return (o != null && o.getKey().startsWith( Iterable<String> iterable = Iterables.transform(contents, new CommonPrefixes(
URLDecoder.decode(options.getPrefix()))); options.getPrefix() != null ? URLDecoder.decode(options.getPrefix(),
} "UTF-8") : null, URLDecoder.decode(options.getDelimiter(),
})); "UTF-8")));
returnVal.setPrefix(URLDecoder.decode(options.getPrefix())); Set<String> commonPrefixes = iterable != null ? Sets.newTreeSet(iterable)
: new HashSet<String>();
commonPrefixes.remove(CommonPrefixes.NO_PREFIX);
contents = Sets.newTreeSet(Iterables.filter(contents, new DelimiterFilter(options
.getPrefix() != null ? URLDecoder.decode(options.getPrefix(), "UTF-8")
: null, URLDecoder.decode(options.getDelimiter(), "UTF-8"))));
returnVal.setCommonPrefixes(commonPrefixes);
returnVal.setDelimiter(URLDecoder.decode(options.getDelimiter(), "UTF-8"));
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
} }
if (options.getDelimiter() != null) {
Iterable<String> iterable = Iterables.transform(contents, new CommonPrefixes(options
.getPrefix() != null ? URLDecoder.decode(options.getPrefix()) : null,
URLDecoder.decode(options.getDelimiter())));
Set<String> commonPrefixes = iterable != null ? Sets.newTreeSet(iterable)
: new HashSet<String>();
commonPrefixes.remove(CommonPrefixes.NO_PREFIX);
contents = Sets.newTreeSet(Iterables.filter(contents, new DelimiterFilter(options
.getPrefix() != null ? URLDecoder.decode(options.getPrefix()) : null,
URLDecoder.decode(options.getDelimiter()))));
returnVal.setCommonPrefixes(commonPrefixes);
returnVal.setDelimiter(URLDecoder.decode(options.getDelimiter()));
}
if (options.getMaxKeys() != null) { if (options.getMaxKeys() != null) {
contents = firstSliceOfSize(contents, Integer.parseInt(options.getMaxKeys())); contents = firstSliceOfSize(contents, Integer.parseInt(options.getMaxKeys()));
returnVal.setMaxKeys(Integer.parseInt(options.getMaxKeys())); returnVal.setMaxKeys(Integer.parseInt(options.getMaxKeys()));
@ -344,7 +353,8 @@ public class StubS3Connection implements S3Connection {
}; };
} }
public static <T extends Comparable> SortedSet<T> firstSliceOfSize(Iterable<T> elements, int size) { public static <T extends Comparable<?>> SortedSet<T> firstSliceOfSize(Iterable<T> elements,
int size) {
List<List<T>> slices = Lists.partition(Lists.newArrayList(elements), size); List<List<T>> slices = Lists.partition(Lists.newArrayList(elements), size);
return Sets.newTreeSet(slices.get(0)); return Sets.newTreeSet(slices.get(0));
} }

View File

@ -23,35 +23,32 @@
*/ */
package org.jclouds.aws.s3.commands; package org.jclouds.aws.s3.commands;
import java.util.concurrent.TimeUnit;
import org.jclouds.aws.s3.S3IntegrationTest; import org.jclouds.aws.s3.S3IntegrationTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod;
import java.util.concurrent.TimeUnit;
/** /**
* Tests integrated functionality of all bucketExists commands. * Tests integrated functionality of all bucketExists commands.
* <p/> * <p/>
* Each test uses a different bucket name, so it should be perfectly fine to run * Each test uses a different bucket name, so it should be perfectly fine to run in parallel.
* in parallel. *
*
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = {"integration", "live"}, testName = "s3.BucketExistsIntegrationTest") @Test(groups = { "integration", "live" }, testName = "s3.BucketExistsIntegrationTest")
public class BucketExistsIntegrationTest extends S3IntegrationTest { public class BucketExistsIntegrationTest extends S3IntegrationTest {
@Test @Test
void bucketDoesntExist() throws Exception { void bucketDoesntExist() throws Exception {
String bucketName= bucketPrefix+"be"; String bucketName = bucketPrefix + "be";
assert !client.bucketExists(bucketName).get(10, TimeUnit.SECONDS); assert !client.bucketExists(bucketName).get(10, TimeUnit.SECONDS);
} }
@Test @Test
void bucketExists() throws Exception { void bucketExists() throws Exception {
String bucketName= bucketPrefix+"bde"; String bucketName = bucketPrefix + "bde";
assert client.putBucketIfNotExists(bucketName).get(10, assert client.putBucketIfNotExists(bucketName).get(10, TimeUnit.SECONDS);
TimeUnit.SECONDS); assert client.bucketExists(bucketName).get(10, TimeUnit.SECONDS);
assert client.bucketExists(bucketName).get(10, TimeUnit.SECONDS);
} }
} }

View File

@ -23,185 +23,176 @@
*/ */
package org.jclouds.aws.s3.commands; package org.jclouds.aws.s3.commands;
import com.google.common.collect.HashMultimap; import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.ifSourceMd5DoesntMatch;
import com.google.common.collect.Multimap; import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.ifSourceMd5Matches;
import org.jclouds.aws.s3.S3IntegrationTest; import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.ifSourceModifiedSince;
import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.*; import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.ifSourceUnmodifiedSince;
import org.jclouds.aws.s3.domain.S3Object; import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.overrideMetadataWith;
import org.jclouds.aws.s3.domain.acl.CannedAccessPolicy;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.http.HttpResponseException;
import org.joda.time.DateTime;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import org.testng.annotations.Test;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import org.jclouds.aws.s3.S3IntegrationTest;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.http.HttpResponseException;
import org.joda.time.DateTime;
import org.testng.annotations.Test;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
/** /**
* Tests integrated functionality of all copyObject commands. * Tests integrated functionality of all copyObject commands.
* <p/> * <p/>
* Each test uses a different bucket name, so it should be perfectly fine to run * Each test uses a different bucket name, so it should be perfectly fine to run in parallel.
* in parallel. *
*
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(testName = "s3.CopyObjectIntegrationTest") @Test(testName = "s3.CopyObjectIntegrationTest")
public class CopyObjectIntegrationTest extends S3IntegrationTest { public class CopyObjectIntegrationTest extends S3IntegrationTest {
String sourceKey = "apples"; String sourceKey = "apples";
String destinationKey = "pears"; String destinationKey = "pears";
@Test(groups = {"integration","live"}) @Test(groups = { "integration", "live" })
void testCopyObject() throws Exception { void testCopyObject() throws Exception {
String destinationBucket = bucketName + "dest"; String destinationBucket = bucketName + "dest";
addToBucketAndValidate(bucketName, sourceKey); addToBucketAndValidate(bucketName, sourceKey);
createBucketAndEnsureEmpty(destinationBucket); createBucketAndEnsureEmpty(destinationBucket);
client.copyObject(bucketName, sourceKey, destinationBucket, client.copyObject(bucketName, sourceKey, destinationBucket, destinationKey).get(10,
destinationKey).get(10, TimeUnit.SECONDS); TimeUnit.SECONDS);
validateContent(destinationBucket, destinationKey); validateContent(destinationBucket, destinationKey);
} }
private void addToBucketAndValidate(String bucketName, String sourceKey)
throws InterruptedException, ExecutionException, TimeoutException, IOException {
addObjectToBucket(bucketName, sourceKey);
validateContent(bucketName, sourceKey);
}
private void addToBucketAndValidate(String bucketName, String sourceKey) @Test(enabled = false, groups = { "integration", "live" })
throws InterruptedException, ExecutionException, TimeoutException, // TODO: fails on linux and windows
IOException { void testCopyIfModifiedSince() throws InterruptedException, ExecutionException,
addObjectToBucket(bucketName, sourceKey);
validateContent(bucketName, sourceKey);
}
@Test(enabled= false, groups = {"integration","live"})//TODO: fails on linux and windows
void testCopyIfModifiedSince() throws InterruptedException,
ExecutionException, TimeoutException, IOException {
String destinationBucket = bucketName + "dest";
DateTime before = new DateTime();
addToBucketAndValidate(bucketName, sourceKey);
DateTime after = new DateTime().plusSeconds(1);
createBucketAndEnsureEmpty(destinationBucket);
client.copyObject(bucketName, sourceKey, destinationBucket,
destinationKey, ifSourceModifiedSince(before)).get(10,
TimeUnit.SECONDS);
validateContent(destinationBucket, destinationKey);
try {
client.copyObject(bucketName, sourceKey, destinationBucket,
destinationKey, ifSourceModifiedSince(after)).get(10,
TimeUnit.SECONDS);
} catch (ExecutionException e) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 412);
}
}
@Test(enabled= false, groups = {"integration","live"})//TODO: fails on linux and windows
void testCopyIfUnmodifiedSince() throws InterruptedException,
ExecutionException, TimeoutException, IOException {
String destinationBucket = bucketName + "dest";
DateTime before = new DateTime();
addToBucketAndValidate(bucketName, sourceKey);
DateTime after = new DateTime().plusSeconds(1);
createBucketAndEnsureEmpty(destinationBucket);
client.copyObject(bucketName, sourceKey, destinationBucket,
destinationKey, ifSourceUnmodifiedSince(after)).get(10,
TimeUnit.SECONDS);
validateContent(destinationBucket, destinationKey);
try {
client.copyObject(bucketName, sourceKey, destinationBucket,
destinationKey, ifSourceModifiedSince(before)).get(10,
TimeUnit.SECONDS);
} catch (ExecutionException e) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 412);
}
}
@Test(groups = {"integration","live"})
void testCopyIfMatch() throws InterruptedException, ExecutionException,
TimeoutException, IOException { TimeoutException, IOException {
String destinationBucket = bucketName + "dest";
String destinationBucket = bucketName + "dest"; DateTime before = new DateTime();
addToBucketAndValidate(bucketName, sourceKey);
DateTime after = new DateTime().plusSeconds(1);
addToBucketAndValidate(bucketName, sourceKey); createBucketAndEnsureEmpty(destinationBucket);
client.copyObject(bucketName, sourceKey, destinationBucket, destinationKey,
ifSourceModifiedSince(before)).get(10, TimeUnit.SECONDS);
validateContent(destinationBucket, destinationKey);
createBucketAndEnsureEmpty(destinationBucket); try {
client.copyObject(bucketName, sourceKey, destinationBucket, client.copyObject(bucketName, sourceKey, destinationBucket, destinationKey,
destinationKey, ifSourceMd5Matches(goodMd5)).get(10, ifSourceModifiedSince(after)).get(10, TimeUnit.SECONDS);
TimeUnit.SECONDS); } catch (ExecutionException e) {
validateContent(destinationBucket, destinationKey); HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 412);
}
}
try { @Test(enabled = false, groups = { "integration", "live" })
client.copyObject(bucketName, sourceKey, destinationBucket, // TODO: fails on linux and windows
destinationKey, ifSourceMd5Matches(badMd5)).get(10, void testCopyIfUnmodifiedSince() throws InterruptedException, ExecutionException,
TimeUnit.SECONDS); TimeoutException, IOException {
} catch (ExecutionException e) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 412);
}
}
@Test(groups = {"integration","live"}) String destinationBucket = bucketName + "dest";
void testCopyIfNoneMatch() throws IOException, InterruptedException,
ExecutionException, TimeoutException {
DateTime before = new DateTime();
addToBucketAndValidate(bucketName, sourceKey);
DateTime after = new DateTime().plusSeconds(1);
String destinationBucket = bucketName + "dest"; createBucketAndEnsureEmpty(destinationBucket);
client.copyObject(bucketName, sourceKey, destinationBucket, destinationKey,
ifSourceUnmodifiedSince(after)).get(10, TimeUnit.SECONDS);
validateContent(destinationBucket, destinationKey);
addToBucketAndValidate(bucketName, sourceKey); try {
client.copyObject(bucketName, sourceKey, destinationBucket, destinationKey,
ifSourceModifiedSince(before)).get(10, TimeUnit.SECONDS);
} catch (ExecutionException e) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 412);
}
}
createBucketAndEnsureEmpty(destinationBucket); @Test(groups = { "integration", "live" })
client.copyObject(bucketName, sourceKey, destinationBucket, void testCopyIfMatch() throws InterruptedException, ExecutionException, TimeoutException,
destinationKey, ifSourceMd5DoesntMatch(badMd5)).get(10, IOException {
TimeUnit.SECONDS);
validateContent(destinationBucket, destinationKey);
try { String destinationBucket = bucketName + "dest";
client.copyObject(bucketName, sourceKey, destinationBucket,
destinationKey, ifSourceMd5DoesntMatch(goodMd5)).get(10,
TimeUnit.SECONDS);
} catch (ExecutionException e) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 412);
}
}
@Test(groups = {"integration","live"}) addToBucketAndValidate(bucketName, sourceKey);
void testCopyWithMetadata() throws InterruptedException,
ExecutionException, TimeoutException, IOException {
String destinationBucket = bucketName + "dest"; createBucketAndEnsureEmpty(destinationBucket);
client.copyObject(bucketName, sourceKey, destinationBucket, destinationKey,
ifSourceMd5Matches(goodMd5)).get(10, TimeUnit.SECONDS);
validateContent(destinationBucket, destinationKey);
addToBucketAndValidate(bucketName, sourceKey); try {
client.copyObject(bucketName, sourceKey, destinationBucket, destinationKey,
ifSourceMd5Matches(badMd5)).get(10, TimeUnit.SECONDS);
} catch (ExecutionException e) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 412);
}
}
Multimap<String, String> metadata = HashMultimap.create(); @Test(groups = { "integration", "live" })
metadata.put(S3Headers.USER_METADATA_PREFIX + "adrian", "cole"); void testCopyIfNoneMatch() throws IOException, InterruptedException, ExecutionException,
TimeoutException {
createBucketAndEnsureEmpty(destinationBucket); String destinationBucket = bucketName + "dest";
client.copyObject(bucketName, sourceKey, destinationBucket,
destinationKey, overrideMetadataWith(metadata)).get(10,
TimeUnit.SECONDS);
validateContent(destinationBucket, destinationKey); addToBucketAndValidate(bucketName, sourceKey);
S3Object.Metadata objectMeta = client.headObject(destinationBucket, createBucketAndEnsureEmpty(destinationBucket);
destinationKey).get(10, TimeUnit.SECONDS); client.copyObject(bucketName, sourceKey, destinationBucket, destinationKey,
ifSourceMd5DoesntMatch(badMd5)).get(10, TimeUnit.SECONDS);
validateContent(destinationBucket, destinationKey);
assertEquals(objectMeta.getUserMetadata(), metadata); try {
} client.copyObject(bucketName, sourceKey, destinationBucket, destinationKey,
ifSourceMd5DoesntMatch(goodMd5)).get(10, TimeUnit.SECONDS);
} catch (ExecutionException e) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 412);
}
}
@Test(groups = { "integration", "live" })
void testCopyWithMetadata() throws InterruptedException, ExecutionException, TimeoutException,
IOException {
String destinationBucket = bucketName + "dest";
addToBucketAndValidate(bucketName, sourceKey);
Multimap<String, String> metadata = HashMultimap.create();
metadata.put(S3Headers.USER_METADATA_PREFIX + "adrian", "cole");
createBucketAndEnsureEmpty(destinationBucket);
client.copyObject(bucketName, sourceKey, destinationBucket, destinationKey,
overrideMetadataWith(metadata)).get(10, TimeUnit.SECONDS);
validateContent(destinationBucket, destinationKey);
S3Object.Metadata objectMeta = client.headObject(destinationBucket, destinationKey).get(10,
TimeUnit.SECONDS);
assertEquals(objectMeta.getUserMetadata(), metadata);
}
} }

View File

@ -23,55 +23,52 @@
*/ */
package org.jclouds.aws.s3.commands; package org.jclouds.aws.s3.commands;
import org.jclouds.aws.s3.S3IntegrationTest;
import org.jclouds.aws.s3.S3ResponseException;
import org.jclouds.aws.s3.domain.S3Object;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import org.testng.annotations.Test;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.s3.S3IntegrationTest;
import org.jclouds.aws.s3.domain.S3Object;
import org.testng.annotations.Test;
/** /**
* Tests integrated functionality of all deleteObject commands. * Tests integrated functionality of all deleteObject commands.
* <p/> * <p/>
* Each test uses a different bucket name, so it should be perfectly fine to run * Each test uses a different bucket name, so it should be perfectly fine to run in parallel.
* in parallel. *
*
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = {"integration", "live"}, testName = "s3.DeleteObjectIntegrationTest") @Test(groups = { "integration", "live" }, testName = "s3.DeleteObjectIntegrationTest")
public class DeleteObjectIntegrationTest extends S3IntegrationTest { public class DeleteObjectIntegrationTest extends S3IntegrationTest {
@Test() @Test()
void deleteObjectNotFound() throws Exception { void deleteObjectNotFound() throws Exception {
String bucketName = bucketPrefix + "donf"; String bucketName = bucketPrefix + "donf";
createBucketAndEnsureEmpty(bucketName); createBucketAndEnsureEmpty(bucketName);
addObjectToBucket(bucketName, "test"); addObjectToBucket(bucketName, "test");
assert client.deleteObject(bucketName, "test") assert client.deleteObject(bucketName, "test").get(10, TimeUnit.SECONDS);
.get(10, TimeUnit.SECONDS); }
}
@Test @Test
void deleteObjectNoBucket() throws Exception { void deleteObjectNoBucket() throws Exception {
String bucketName = bucketPrefix + "donb"; String bucketName = bucketPrefix + "donb";
try { try {
client.deleteObject(bucketName, "test").get(10, TimeUnit.SECONDS); client.deleteObject(bucketName, "test").get(10, TimeUnit.SECONDS);
} catch (ExecutionException e) { } catch (ExecutionException e) {
assert e.getCause() instanceof S3ResponseException; assert e.getCause() instanceof AWSResponseException;
assertEquals(((S3ResponseException) e.getCause()).getResponse() assertEquals(((AWSResponseException) e.getCause()).getResponse().getStatusCode(), 404);
.getStatusCode(), 404); }
} }
}
@Test() @Test()
void deleteObject() throws Exception { void deleteObject() throws Exception {
String bucketName = bucketPrefix + "do"; String bucketName = bucketPrefix + "do";
createBucketAndEnsureEmpty(bucketName); createBucketAndEnsureEmpty(bucketName);
addObjectToBucket(bucketName, "test"); addObjectToBucket(bucketName, "test");
assert client.deleteObject(bucketName, "test") assert client.deleteObject(bucketName, "test").get(10, TimeUnit.SECONDS);
.get(10, TimeUnit.SECONDS); assert client.headObject(bucketName, "test").get(10, TimeUnit.SECONDS) == S3Object.Metadata.NOT_FOUND;
assert client.headObject(bucketName, "test").get(10, TimeUnit.SECONDS) == S3Object.Metadata.NOT_FOUND;
} }
} }

View File

@ -23,209 +23,202 @@
*/ */
package org.jclouds.aws.s3.commands; package org.jclouds.aws.s3.commands;
import org.jclouds.aws.s3.S3IntegrationTest; import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.ifMd5DoesntMatch;
import org.jclouds.aws.s3.S3ResponseException; import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.ifMd5Matches;
import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.*; import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.ifModifiedSince;
import org.jclouds.aws.s3.domain.S3Object; import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.ifUnmodifiedSince;
import org.jclouds.aws.s3.util.S3Utils; import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.range;
import org.jclouds.http.HttpResponseException; import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.startAt;
import org.joda.time.DateTime; import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.tail;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import org.testng.annotations.Test;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import org.jclouds.aws.s3.S3IntegrationTest;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.http.HttpResponseException;
import org.joda.time.DateTime;
import org.testng.annotations.Test;
/** /**
* Tests integrated functionality of all GetObject commands. * Tests integrated functionality of all GetObject commands.
* <p/> * <p/>
* Each test uses a different bucket name, so it should be perfectly fine to run * Each test uses a different bucket name, so it should be perfectly fine to run in parallel.
* in parallel. *
*
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = {"integration", "live"}, testName = "s3.GetObjectIntegrationTest") @Test(groups = { "integration", "live" }, testName = "s3.GetObjectIntegrationTest")
public class GetObjectIntegrationTest extends S3IntegrationTest { public class GetObjectIntegrationTest extends S3IntegrationTest {
@Test(enabled=false )//TODO: fails on linux and windows @Test(enabled = false)
void testGetIfModifiedSince() throws InterruptedException, // TODO: fails on linux and windows
ExecutionException, TimeoutException, IOException { void testGetIfModifiedSince() throws InterruptedException, ExecutionException, TimeoutException,
String key = "apples";
DateTime before = new DateTime();
addObjectAndValidateContent(bucketName, key);
DateTime after = new DateTime().plusSeconds(1);
client.getObject(bucketName, key, ifModifiedSince(before)).get(10,
TimeUnit.SECONDS);
validateContent(bucketName, key);
try {
client.getObject(bucketName, key, ifModifiedSince(after)).get(10,
TimeUnit.SECONDS);
validateContent(bucketName, key);
} catch (ExecutionException e) {
if (e.getCause() instanceof HttpResponseException) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 304);
} else {
throw e;
}
}
}
@Test(enabled=false )//TODO: fails on linux and windows
void testGetIfUnmodifiedSince() throws InterruptedException,
ExecutionException, TimeoutException, IOException {
String key = "apples";
DateTime before = new DateTime();
addObjectAndValidateContent(bucketName, key);
DateTime after = new DateTime().plusSeconds(1);
client.getObject(bucketName, key, ifUnmodifiedSince(after)).get(10,
TimeUnit.SECONDS);
validateContent(bucketName, key);
try {
client.getObject(bucketName, key, ifUnmodifiedSince(before)).get(10,
TimeUnit.SECONDS);
validateContent(bucketName, key);
} catch (ExecutionException e) {
if (e.getCause() instanceof HttpResponseException) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 412);
} else {
throw e;
}
}
}
@Test
void testGetIfMatch() throws InterruptedException, ExecutionException,
TimeoutException, IOException {
String key = "apples";
addObjectAndValidateContent(bucketName, key);
client.getObject(bucketName, key, ifMd5Matches(goodMd5)).get(10,
TimeUnit.SECONDS);
validateContent(bucketName, key);
try {
client.getObject(bucketName, key, ifMd5Matches(badMd5)).get(10,
TimeUnit.SECONDS);
validateContent(bucketName, key);
} catch (ExecutionException e) {
if (e.getCause() instanceof HttpResponseException) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 412);
} else {
throw e;
}
}
}
@Test
void testGetIfNoneMatch() throws InterruptedException, ExecutionException,
TimeoutException, IOException {
String key = "apples";
addObjectAndValidateContent(bucketName, key);
client.getObject(bucketName, key, ifMd5DoesntMatch(badMd5)).get(10,
TimeUnit.SECONDS);
validateContent(bucketName, key);
try {
client.getObject(bucketName, key, ifMd5DoesntMatch(goodMd5)).get(10,
TimeUnit.SECONDS);
validateContent(bucketName, key);
} catch (ExecutionException e) {
if (e.getCause() instanceof HttpResponseException) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 304);
} else {
throw e;
}
}
}
@Test
void testGetRange() throws InterruptedException, ExecutionException,
TimeoutException, IOException {
String key = "apples";
addObjectAndValidateContent(bucketName, key);
S3Object object1 = client.getObject(bucketName, key, range(0, 5)).get(10,
TimeUnit.SECONDS);
assertEquals(S3Utils.getContentAsStringAndClose(object1), TEST_STRING
.substring(0, 6));
S3Object object2 = client.getObject(bucketName, key,
range(6, TEST_STRING.length())).get(10, TimeUnit.SECONDS);
assertEquals(S3Utils.getContentAsStringAndClose(object2), TEST_STRING
.substring(6, TEST_STRING.length()));
}
@Test
void testGetTwoRanges() throws InterruptedException, ExecutionException,
TimeoutException, IOException {
String key = "apples";
addObjectAndValidateContent(bucketName, key);
S3Object object = client.getObject(bucketName, key,
range(0, 5).range(6, TEST_STRING.length())).get(10,
TimeUnit.SECONDS);
assertEquals(S3Utils.getContentAsStringAndClose(object), TEST_STRING);
}
@Test
void testGetTail() throws InterruptedException, ExecutionException,
TimeoutException, IOException {
String key = "apples";
addObjectAndValidateContent(bucketName, key);
S3Object object = client.getObject(bucketName, key, tail(5)).get(10,
TimeUnit.SECONDS);
assertEquals(S3Utils.getContentAsStringAndClose(object), TEST_STRING
.substring(TEST_STRING.length() - 5));
assertEquals(object.getContentLength(), 5);
assertEquals(object.getMetadata().getSize(), TEST_STRING.length());
}
@Test
void testGetStartAt() throws InterruptedException, ExecutionException,
TimeoutException, IOException {
String key = "apples";
addObjectAndValidateContent(bucketName, key);
S3Object object = client.getObject(bucketName, key, startAt(5)).get(10,
TimeUnit.SECONDS);
assertEquals(S3Utils.getContentAsStringAndClose(object), TEST_STRING
.substring(5, TEST_STRING.length()));
assertEquals(object.getContentLength(), TEST_STRING.length() - 5);
assertEquals(object.getMetadata().getSize(), TEST_STRING.length());
}
private void addObjectAndValidateContent(String sourcebucketName, String sourceKey)
throws InterruptedException, ExecutionException, TimeoutException,
IOException { IOException {
addObjectToBucket(sourcebucketName, sourceKey);
validateContent(sourcebucketName, sourceKey); String key = "apples";
}
DateTime before = new DateTime();
addObjectAndValidateContent(bucketName, key);
DateTime after = new DateTime().plusSeconds(1);
client.getObject(bucketName, key, ifModifiedSince(before)).get(10, TimeUnit.SECONDS);
validateContent(bucketName, key);
try {
client.getObject(bucketName, key, ifModifiedSince(after)).get(10, TimeUnit.SECONDS);
validateContent(bucketName, key);
} catch (ExecutionException e) {
if (e.getCause() instanceof HttpResponseException) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 304);
} else {
throw e;
}
}
}
@Test(enabled = false)
// TODO: fails on linux and windows
void testGetIfUnmodifiedSince() throws InterruptedException, ExecutionException,
TimeoutException, IOException {
String key = "apples";
DateTime before = new DateTime();
addObjectAndValidateContent(bucketName, key);
DateTime after = new DateTime().plusSeconds(1);
client.getObject(bucketName, key, ifUnmodifiedSince(after)).get(10, TimeUnit.SECONDS);
validateContent(bucketName, key);
try {
client.getObject(bucketName, key, ifUnmodifiedSince(before)).get(10, TimeUnit.SECONDS);
validateContent(bucketName, key);
} catch (ExecutionException e) {
if (e.getCause() instanceof HttpResponseException) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 412);
} else {
throw e;
}
}
}
@Test
void testGetIfMatch() throws InterruptedException, ExecutionException, TimeoutException,
IOException {
String key = "apples";
addObjectAndValidateContent(bucketName, key);
client.getObject(bucketName, key, ifMd5Matches(goodMd5)).get(10, TimeUnit.SECONDS);
validateContent(bucketName, key);
try {
client.getObject(bucketName, key, ifMd5Matches(badMd5)).get(10, TimeUnit.SECONDS);
validateContent(bucketName, key);
} catch (ExecutionException e) {
if (e.getCause() instanceof HttpResponseException) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 412);
} else {
throw e;
}
}
}
@Test
void testGetIfNoneMatch() throws InterruptedException, ExecutionException, TimeoutException,
IOException {
String key = "apples";
addObjectAndValidateContent(bucketName, key);
client.getObject(bucketName, key, ifMd5DoesntMatch(badMd5)).get(10, TimeUnit.SECONDS);
validateContent(bucketName, key);
try {
client.getObject(bucketName, key, ifMd5DoesntMatch(goodMd5)).get(10, TimeUnit.SECONDS);
validateContent(bucketName, key);
} catch (ExecutionException e) {
if (e.getCause() instanceof HttpResponseException) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 304);
} else {
throw e;
}
}
}
@Test
void testGetRange() throws InterruptedException, ExecutionException, TimeoutException,
IOException {
String key = "apples";
addObjectAndValidateContent(bucketName, key);
S3Object object1 = client.getObject(bucketName, key, range(0, 5)).get(10, TimeUnit.SECONDS);
assertEquals(S3Utils.getContentAsStringAndClose(object1), TEST_STRING.substring(0, 6));
S3Object object2 = client.getObject(bucketName, key, range(6, TEST_STRING.length())).get(10,
TimeUnit.SECONDS);
assertEquals(S3Utils.getContentAsStringAndClose(object2), TEST_STRING.substring(6,
TEST_STRING.length()));
}
@Test
void testGetTwoRanges() throws InterruptedException, ExecutionException, TimeoutException,
IOException {
String key = "apples";
addObjectAndValidateContent(bucketName, key);
S3Object object = client.getObject(bucketName, key,
range(0, 5).range(6, TEST_STRING.length())).get(10, TimeUnit.SECONDS);
assertEquals(S3Utils.getContentAsStringAndClose(object), TEST_STRING);
}
@Test
void testGetTail() throws InterruptedException, ExecutionException, TimeoutException,
IOException {
String key = "apples";
addObjectAndValidateContent(bucketName, key);
S3Object object = client.getObject(bucketName, key, tail(5)).get(10, TimeUnit.SECONDS);
assertEquals(S3Utils.getContentAsStringAndClose(object), TEST_STRING.substring(TEST_STRING
.length() - 5));
assertEquals(object.getContentLength(), 5);
assertEquals(object.getMetadata().getSize(), TEST_STRING.length());
}
@Test
void testGetStartAt() throws InterruptedException, ExecutionException, TimeoutException,
IOException {
String key = "apples";
addObjectAndValidateContent(bucketName, key);
S3Object object = client.getObject(bucketName, key, startAt(5)).get(10, TimeUnit.SECONDS);
assertEquals(S3Utils.getContentAsStringAndClose(object), TEST_STRING.substring(5, TEST_STRING
.length()));
assertEquals(object.getContentLength(), TEST_STRING.length() - 5);
assertEquals(object.getMetadata().getSize(), TEST_STRING.length());
}
private void addObjectAndValidateContent(String sourcebucketName, String sourceKey)
throws InterruptedException, ExecutionException, TimeoutException, IOException {
addObjectToBucket(sourcebucketName, sourceKey);
validateContent(sourcebucketName, sourceKey);
}
} }

View File

@ -23,105 +23,90 @@
*/ */
package org.jclouds.aws.s3.commands; package org.jclouds.aws.s3.commands;
import org.apache.commons.io.IOUtils;
import org.jclouds.aws.s3.S3IntegrationTest;
import static org.jclouds.aws.s3.commands.options.PutBucketOptions.Builder.withBucketAcl;
import static org.jclouds.aws.s3.commands.options.PutObjectOptions.Builder.withAcl;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.domain.acl.CannedAccessPolicy;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.aws.s3.util.S3Utils;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNotNull;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.jclouds.aws.s3.S3IntegrationTest;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.aws.s3.util.S3Utils;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/** /**
* Tests integrated functionality of all PutObject commands. * Tests integrated functionality of all PutObject commands.
* <p/> * <p/>
* Each test uses a different bucket name, so it should be perfectly fine to run * Each test uses a different bucket name, so it should be perfectly fine to run in parallel.
* in parallel. *
*
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(testName = "s3.PutObjectIntegrationTest") @Test(testName = "s3.PutObjectIntegrationTest")
public class PutObjectIntegrationTest extends S3IntegrationTest { public class PutObjectIntegrationTest extends S3IntegrationTest {
@DataProvider(name = "putTests") @DataProvider(name = "putTests")
public Object[][] createData1() throws IOException { public Object[][] createData1() throws IOException {
String realObject = IOUtils.toString(new FileInputStream("pom.xml")); String realObject = IOUtils.toString(new FileInputStream("pom.xml"));
return new Object[][]{ return new Object[][] { { "file", "text/xml", new File("pom.xml"), realObject },
{"file", "text/xml", new File("pom.xml"), realObject}, { "string", "text/xml", realObject, realObject },
{"string", "text/xml", realObject, realObject}, { "bytes", "application/octet-stream", realObject.getBytes(), realObject } };
{"bytes", "application/octet-stream", realObject.getBytes(), }
realObject}};
}
@Test(dataProvider = "putTests", groups = {"integration", "live"}) @Test(dataProvider = "putTests", groups = { "integration", "live" })
void testPutObject(String key, String type, Object content, void testPutObject(String key, String type, Object content, Object realObject) throws Exception {
Object realObject) throws Exception { String bucketName = bucketPrefix + "tpo";
String bucketName = bucketPrefix + "tpo"; client.putBucketIfNotExists(bucketName).get(10, TimeUnit.SECONDS);
client.putBucketIfNotExists(bucketName).get(10, TimeUnit.SECONDS); context.createS3ObjectMap(bucketName).clear();
context.createS3ObjectMap(bucketName).clear(); assertEquals(client.listBucket(bucketName).get(10, TimeUnit.SECONDS).getContents().size(), 0);
assertEquals(client.listBucket(bucketName).get(10, TimeUnit.SECONDS) S3Object object = new S3Object(key);
.getContents().size(), 0); object.getMetadata().setContentType(type);
S3Object object = new S3Object(key); object.setData(content);
object.getMetadata().setContentType(type); if (content instanceof InputStream) {
object.setData(content); object.generateMd5();
if (content instanceof InputStream) { }
object.generateMd5(); assertNotNull(client.putObject(bucketName, object).get(10, TimeUnit.SECONDS));
} object = client.getObject(bucketName, object.getKey()).get(10, TimeUnit.SECONDS);
assertNotNull(client.putObject(bucketName, object).get(10, String returnedString = S3Utils.getContentAsStringAndClose(object);
TimeUnit.SECONDS)); assertEquals(returnedString, realObject);
object = client.getObject(bucketName, object.getKey()).get(10, assertEquals(client.listBucket(bucketName).get(10, TimeUnit.SECONDS).getContents().size(), 1);
TimeUnit.SECONDS); }
String returnedString = S3Utils.getContentAsStringAndClose(object);
assertEquals(returnedString, realObject);
assertEquals(client.listBucket(bucketName).get(10, TimeUnit.SECONDS)
.getContents().size(), 1);
}
@Test(groups = {"integration", "live"}) @Test(groups = { "integration", "live" })
void testMetadata() throws Exception { void testMetadata() throws Exception {
String bucketName = bucketPrefix + "tmd"; String bucketName = bucketPrefix + "tmd";
createBucketAndEnsureEmpty(bucketName); createBucketAndEnsureEmpty(bucketName);
String key = "hello"; String key = "hello";
S3Object object = new S3Object(key, TEST_STRING); S3Object object = new S3Object(key, TEST_STRING);
object.getMetadata().setCacheControl("no-cache"); object.getMetadata().setCacheControl("no-cache");
object.getMetadata().setContentType("text/plain"); object.getMetadata().setContentType("text/plain");
object.getMetadata().setContentEncoding("x-compress"); object.getMetadata().setContentEncoding("x-compress");
object.getMetadata().setSize(TEST_STRING.length()); object.getMetadata().setSize(TEST_STRING.length());
object.getMetadata().setContentDisposition( object.getMetadata().setContentDisposition("attachment; filename=hello.txt");
"attachment; filename=hello.txt"); object.getMetadata().getUserMetadata().put(S3Headers.USER_METADATA_PREFIX + "adrian",
object.getMetadata().getUserMetadata().put( "powderpuff");
S3Headers.USER_METADATA_PREFIX + "adrian", "powderpuff"); object.getMetadata().setMd5(S3Utils.md5(TEST_STRING.getBytes()));
object.getMetadata().setMd5(S3Utils.md5(TEST_STRING.getBytes()));
addObjectToBucket(bucketName, object); addObjectToBucket(bucketName, object);
S3Object newObject = validateContent(bucketName, key); S3Object newObject = validateContent(bucketName, key);
// TODO.. why does this come back as binary/octetstring // TODO.. why does this come back as binary/octetstring
assertEquals(newObject.getMetadata().getContentType(), assertEquals(newObject.getMetadata().getContentType(), "binary/octet-stream");
"binary/octet-stream"); assertEquals(newObject.getMetadata().getContentEncoding(), "x-compress");
assertEquals(newObject.getMetadata().getContentEncoding(), "x-compress"); assertEquals(newObject.getMetadata().getContentDisposition(),
assertEquals(newObject.getMetadata().getContentDisposition(), "attachment; filename=hello.txt");
"attachment; filename=hello.txt"); assertEquals(newObject.getMetadata().getCacheControl(), "no-cache");
assertEquals(newObject.getMetadata().getCacheControl(), "no-cache"); assertEquals(newObject.getMetadata().getSize(), TEST_STRING.length());
assertEquals(newObject.getMetadata().getSize(), TEST_STRING.length()); assertEquals(newObject.getMetadata().getUserMetadata().values().iterator().next(),
assertEquals(newObject.getMetadata().getUserMetadata().values() "powderpuff");
.iterator().next(), "powderpuff"); assertEquals(newObject.getMetadata().getMd5(), S3Utils.md5(TEST_STRING.getBytes()));
assertEquals(newObject.getMetadata().getMd5(), S3Utils.md5(TEST_STRING }
.getBytes()));
}
} }

View File

@ -27,7 +27,7 @@ import com.google.inject.Guice;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.name.Names; import com.google.inject.name.Names;
import org.jclouds.aws.s3.handlers.ParseS3ErrorFromXmlContent; import org.jclouds.aws.s3.handlers.ParseAWSErrorFromXmlContent;
import org.jclouds.aws.s3.reference.S3Constants; import org.jclouds.aws.s3.reference.S3Constants;
import org.jclouds.http.HttpResponseHandler; import org.jclouds.http.HttpResponseHandler;
import org.jclouds.http.annotation.ClientErrorHandler; import org.jclouds.http.annotation.ClientErrorHandler;
@ -46,77 +46,57 @@ import org.testng.annotations.Test;
@Test(groups = "unit", testName = "s3.S3ContextModuleTest") @Test(groups = "unit", testName = "s3.S3ContextModuleTest")
public class S3ContextModuleTest { public class S3ContextModuleTest {
Injector injector = null; Injector createInjector() {
return Guice.createInjector(new LiveS3ConnectionModule(), new S3ContextModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(Names.named(S3Constants.PROPERTY_AWS_ACCESSKEYID)).to(
"localhost");
bindConstant().annotatedWith(Names.named(S3Constants.PROPERTY_AWS_SECRETACCESSKEY)).to(
"localhost");
bindConstant().annotatedWith(Names.named(S3Constants.PROPERTY_HTTP_ADDRESS)).to(
"localhost");
bindConstant().annotatedWith(Names.named(S3Constants.PROPERTY_HTTP_PORT)).to("1000");
bindConstant().annotatedWith(Names.named(S3Constants.PROPERTY_HTTP_SECURE)).to("false");
super.configure();
}
}, new JavaUrlHttpFutureCommandClientModule());
}
@BeforeMethod private static class ClientErrorHandlerTest {
void setUpInjector() { @Inject
injector = Guice.createInjector(new LiveS3ConnectionModule(), new S3ContextModule() { @ClientErrorHandler
@Override HttpResponseHandler errorHandler;
protected void configure() { }
bindConstant().annotatedWith(
Names.named(S3Constants.PROPERTY_AWS_ACCESSKEYID)).to(
"localhost");
bindConstant().annotatedWith(
Names.named(S3Constants.PROPERTY_AWS_SECRETACCESSKEY))
.to("localhost");
bindConstant().annotatedWith(
Names.named(S3Constants.PROPERTY_HTTP_ADDRESS)).to(
"localhost");
bindConstant().annotatedWith(
Names.named(S3Constants.PROPERTY_HTTP_PORT)).to("1000");
bindConstant().annotatedWith(
Names.named(S3Constants.PROPERTY_HTTP_SECURE)).to(
"false");
super.configure();
}
}, new JavaUrlHttpFutureCommandClientModule());
}
@AfterMethod @Test
void tearDownInjector() { void testClientErrorHandler() {
injector = null; ClientErrorHandlerTest error = createInjector().getInstance(ClientErrorHandlerTest.class);
} assertEquals(error.errorHandler.getClass(), ParseAWSErrorFromXmlContent.class);
}
private static class ClientErrorHandlerTest { private static class ServerErrorHandlerTest {
@Inject @Inject
@ClientErrorHandler @ServerErrorHandler
HttpResponseHandler errorHandler; HttpResponseHandler errorHandler;
} }
@Test @Test
void testClientErrorHandler() { void testServerErrorHandler() {
ClientErrorHandlerTest error = injector ServerErrorHandlerTest error = createInjector().getInstance(ServerErrorHandlerTest.class);
.getInstance(ClientErrorHandlerTest.class); assertEquals(error.errorHandler.getClass(), ParseAWSErrorFromXmlContent.class);
assertEquals(error.errorHandler.getClass(), }
ParseS3ErrorFromXmlContent.class);
}
private static class ServerErrorHandlerTest { private static class RedirectHandlerTest {
@Inject @Inject
@ServerErrorHandler @RedirectHandler
HttpResponseHandler errorHandler; HttpResponseHandler errorHandler;
} }
@Test @Test
void testServerErrorHandler() { void testRedirectHandler() {
ServerErrorHandlerTest error = injector RedirectHandlerTest error = createInjector().getInstance(RedirectHandlerTest.class);
.getInstance(ServerErrorHandlerTest.class); assertEquals(error.errorHandler.getClass(), CloseContentAndSetExceptionHandler.class);
assertEquals(error.errorHandler.getClass(), }
ParseS3ErrorFromXmlContent.class);
}
private static class RedirectHandlerTest {
@Inject
@RedirectHandler
HttpResponseHandler errorHandler;
}
@Test
void testRedirectHandler() {
RedirectHandlerTest error = injector
.getInstance(RedirectHandlerTest.class);
assertEquals(error.errorHandler.getClass(),
CloseContentAndSetExceptionHandler.class);
}
} }

View File

@ -82,6 +82,7 @@ public class BaseS3MapTest {
} }
@SuppressWarnings("unchecked")
public void testIfNotFoundRetryOtherwiseAddToSet() throws InterruptedException, public void testIfNotFoundRetryOtherwiseAddToSet() throws InterruptedException,
ExecutionException, TimeoutException { ExecutionException, TimeoutException {
BaseS3Map<String> map = new MockBaseS3Map(); BaseS3Map<String> map = new MockBaseS3Map();
@ -101,6 +102,7 @@ public class BaseS3MapTest {
assert !objects.contains(S3Object.NOT_FOUND); assert !objects.contains(S3Object.NOT_FOUND);
} }
@SuppressWarnings("unchecked")
public void testIfNotFoundRetryOtherwiseAddToSetButNeverGetsIt() throws InterruptedException, public void testIfNotFoundRetryOtherwiseAddToSetButNeverGetsIt() throws InterruptedException,
ExecutionException, TimeoutException { ExecutionException, TimeoutException {
BaseS3Map<String> map = new MockBaseS3Map(); BaseS3Map<String> map = new MockBaseS3Map();

View File

@ -24,7 +24,7 @@
package org.jclouds.aws.s3.xml; package org.jclouds.aws.s3.xml;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.jclouds.aws.s3.domain.S3Error; import org.jclouds.aws.domain.AWSError;
import org.jclouds.http.HttpException; import org.jclouds.http.HttpException;
import org.jclouds.http.commands.callables.xml.ParseSax; import org.jclouds.http.commands.callables.xml.ParseSax;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
@ -37,8 +37,8 @@ public class ErrorHandlerTest extends BaseHandlerTest {
@Test @Test
public void testErrorFromAmazonIfYouDontRemoveTransferEncodingHeader() public void testErrorFromAmazonIfYouDontRemoveTransferEncodingHeader()
throws HttpException { throws HttpException {
ParseSax<S3Error> parser = parserFactory.createErrorParser(); ParseSax<AWSError> parser = parserFactory.createErrorParser();
S3Error error = parser AWSError error = parser
.parse(IOUtils .parse(IOUtils
.toInputStream(errorFromAmazonIfYouDontRemoveTransferEncodingHeader)); .toInputStream(errorFromAmazonIfYouDontRemoveTransferEncodingHeader));
assertEquals(error.getCode(), "NotImplemented"); assertEquals(error.getCode(), "NotImplemented");

View File

@ -23,46 +23,45 @@
*/ */
package org.jclouds.aws.s3.xml; package org.jclouds.aws.s3.xml;
import static org.testng.Assert.assertEquals;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.jclouds.aws.s3.domain.S3Bucket; import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.http.HttpException; import org.jclouds.http.HttpException;
import org.jclouds.http.commands.callables.xml.ParseSax; import org.jclouds.http.commands.callables.xml.ParseSax;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@Test(groups = "unit", testName = "s3.ListBucketHandlerTest") @Test(groups = "unit", testName = "s3.ListBucketHandlerTest")
public class ListBucketHandlerTest extends BaseHandlerTest { public class ListBucketHandlerTest extends BaseHandlerTest {
public static final String listBucketWithPrefixAppsSlash = "<ListBucketResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Name>adriancole.org.jclouds.aws.s3.amazons3testdelimiter</Name><Prefix>apps/</Prefix><Marker></Marker><MaxKeys>1000</MaxKeys><IsTruncated>false</IsTruncated><Contents><Key>apps/0</Key><LastModified>2009-05-07T18:27:08.000Z</LastModified><ETag>&quot;c82e6a0025c31c5de5947fda62ac51ab&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/1</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;944fab2c5a9a6bacf07db5e688310d7a&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/2</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;a227b8888045c8fd159fb495214000f0&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/3</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;c9caa76c3dec53e2a192608ce73eef03&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/4</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;1ce5d0dcc6154a647ea90c7bdf82a224&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/5</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;79433524d87462ee05708a8ef894ed55&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/6</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;dd00a060b28ddca8bc5a21a49e306f67&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/7</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;8cd06eca6e819a927b07a285d750b100&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/8</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;174495094d0633b92cbe46603eee6bad&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/9</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;cd8a19b26fea8a827276df0ad11c580d&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents></ListBucketResult>"; public static final String listBucketWithPrefixAppsSlash = "<ListBucketResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Name>adriancole.org.jclouds.aws.s3.amazons3testdelimiter</Name><Prefix>apps/</Prefix><Marker></Marker><MaxKeys>1000</MaxKeys><IsTruncated>false</IsTruncated><Contents><Key>apps/0</Key><LastModified>2009-05-07T18:27:08.000Z</LastModified><ETag>&quot;c82e6a0025c31c5de5947fda62ac51ab&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/1</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;944fab2c5a9a6bacf07db5e688310d7a&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/2</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;a227b8888045c8fd159fb495214000f0&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/3</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;c9caa76c3dec53e2a192608ce73eef03&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/4</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;1ce5d0dcc6154a647ea90c7bdf82a224&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/5</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;79433524d87462ee05708a8ef894ed55&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/6</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;dd00a060b28ddca8bc5a21a49e306f67&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/7</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;8cd06eca6e819a927b07a285d750b100&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/8</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;174495094d0633b92cbe46603eee6bad&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/9</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;cd8a19b26fea8a827276df0ad11c580d&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents></ListBucketResult>";
public static final String listBucketWithSlashDelimiterAndCommonPrefixApps = "<ListBucketResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"> <Delimiter>/</Delimiter> <CommonPrefixes><Prefix>apps/</Prefix></CommonPrefixes></ListBucketResult>"; public static final String listBucketWithSlashDelimiterAndCommonPrefixApps = "<ListBucketResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"> <Delimiter>/</Delimiter> <CommonPrefixes><Prefix>apps/</Prefix></CommonPrefixes></ListBucketResult>";
ParseSax<S3Bucket> parser;
@BeforeMethod @BeforeMethod
void setUpParser() { ParseSax<S3Bucket> createParser() {
parser = parserFactory.createListBucketParser(); ParseSax<S3Bucket> parser = parserFactory.createListBucketParser();
((ListBucketHandler) parser.getHandler()).setBucketName("test"); ((ListBucketHandler) parser.getHandler()).setBucketName("test");
} return parser;
}
@Test @Test
public void testListMyBucketsWithDelimiterSlashAndCommonPrefixesAppsSlash() public void testListMyBucketsWithDelimiterSlashAndCommonPrefixesAppsSlash() throws HttpException {
throws HttpException {
S3Bucket bucket = parser.parse(IOUtils S3Bucket bucket = createParser().parse(
.toInputStream(listBucketWithSlashDelimiterAndCommonPrefixApps)); IOUtils.toInputStream(listBucketWithSlashDelimiterAndCommonPrefixApps));
assertEquals(bucket.getCommonPrefixes().iterator().next(), "apps/"); assertEquals(bucket.getCommonPrefixes().iterator().next(), "apps/");
assertEquals(bucket.getDelimiter(), "/"); assertEquals(bucket.getDelimiter(), "/");
assert bucket.getMarker() == null; assert bucket.getMarker() == null;
} }
@Test @Test
public void testListMyBucketsWithPrefixAppsSlash() throws HttpException { public void testListMyBucketsWithPrefixAppsSlash() throws HttpException {
S3Bucket bucket = parser.parse(IOUtils S3Bucket bucket = createParser().parse(IOUtils.toInputStream(listBucketWithPrefixAppsSlash));
.toInputStream(listBucketWithPrefixAppsSlash)); assertEquals(bucket.getPrefix(), "apps/");
assertEquals(bucket.getPrefix(), "apps/"); assertEquals(bucket.getMaxKeys(), 1000);
assertEquals(bucket.getMaxKeys(), 1000); assert bucket.getMarker() == null;
assert bucket.getMarker() == null;
} }
} }

View File

@ -85,7 +85,6 @@
<url>http://jclouds.googlecode.com/svn/trunk/s3core/perftest</url> <url>http://jclouds.googlecode.com/svn/trunk/s3core/perftest</url>
</scm> </scm>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>

View File

@ -23,6 +23,8 @@
*/ */
package org.jclouds.aws.s3; package org.jclouds.aws.s3;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.File; import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.util.Arrays; import java.util.Arrays;
@ -32,8 +34,8 @@ import java.util.TreeMap;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import org.jclouds.aws.s3.reference.S3Constants; import org.jclouds.aws.s3.reference.S3Constants;
import org.testng.ITestContext; import org.jets3t.service.S3ServiceException;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Optional; import org.testng.annotations.Optional;
import org.testng.annotations.Parameters; import org.testng.annotations.Parameters;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -49,13 +51,14 @@ import com.amazon.s3.AWSAuthConnection;
public class AmazonPerformanceLiveTest extends BasePerformance { public class AmazonPerformanceLiveTest extends BasePerformance {
private AWSAuthConnection amzClient; private AWSAuthConnection amzClient;
@Override @BeforeClass(inheritGroups = false, groups = { "live" })
@BeforeTest
@Parameters( { S3Constants.PROPERTY_AWS_ACCESSKEYID, S3Constants.PROPERTY_AWS_SECRETACCESSKEY }) @Parameters( { S3Constants.PROPERTY_AWS_ACCESSKEYID, S3Constants.PROPERTY_AWS_SECRETACCESSKEY })
protected void setUpCredentials(@Optional String AWSAccessKeyId, public void setUpJetS3t(@Optional String AWSAccessKeyId, @Optional String AWSSecretAccessKey)
@Optional String AWSSecretAccessKey, ITestContext context) throws Exception { throws S3ServiceException {
super.setUpCredentials(AWSAccessKeyId, AWSSecretAccessKey, context); AWSAccessKeyId = AWSAccessKeyId != null ? AWSAccessKeyId : sysAWSAccessKeyId;
amzClient = new AWSAuthConnection(AWSAccessKeyId, AWSSecretAccessKey, false); AWSSecretAccessKey = AWSSecretAccessKey != null ? AWSSecretAccessKey : sysAWSSecretAccessKey;
amzClient = new AWSAuthConnection(checkNotNull(AWSAccessKeyId, "AWSAccessKeyId"),
checkNotNull(AWSSecretAccessKey, "AWSSecretAccessKey"), false);
} }
@Override @Override

View File

@ -23,6 +23,8 @@ package org.jclouds.aws.s3;
* under the License. * under the License.
* ==================================================================== * ====================================================================
*/ */
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.File; import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -32,8 +34,9 @@ import org.jets3t.service.S3Service;
import org.jets3t.service.S3ServiceException; import org.jets3t.service.S3ServiceException;
import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.impl.rest.httpclient.RestS3Service;
import org.jets3t.service.security.AWSCredentials; import org.jets3t.service.security.AWSCredentials;
import org.testng.ITestContext; import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeTest; import org.testng.annotations.Optional;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test; import org.testng.annotations.Test;
/** /**
@ -45,13 +48,14 @@ import org.testng.annotations.Test;
public class Jets3tPerformanceLiveTest extends BasePerformance { public class Jets3tPerformanceLiveTest extends BasePerformance {
private S3Service jetClient; private S3Service jetClient;
@BeforeTest @BeforeClass(inheritGroups = false, groups = { "live" })
public void setUpJetS3t(ITestContext testContext) throws S3ServiceException { @Parameters( { S3Constants.PROPERTY_AWS_ACCESSKEYID, S3Constants.PROPERTY_AWS_SECRETACCESSKEY })
String AWSAccessKeyId = (String) testContext public void setUpJetS3t(@Optional String AWSAccessKeyId, @Optional String AWSSecretAccessKey)
.getAttribute(S3Constants.PROPERTY_AWS_ACCESSKEYID); throws S3ServiceException {
String AWSSecretAccessKey = (String) testContext AWSAccessKeyId = AWSAccessKeyId != null ? AWSAccessKeyId : sysAWSAccessKeyId;
.getAttribute(S3Constants.PROPERTY_AWS_SECRETACCESSKEY); AWSSecretAccessKey = AWSSecretAccessKey != null ? AWSSecretAccessKey : sysAWSSecretAccessKey;
jetClient = new RestS3Service(new AWSCredentials(AWSAccessKeyId, AWSSecretAccessKey)); jetClient = new RestS3Service(new AWSCredentials(checkNotNull(AWSAccessKeyId,
"AWSAccessKeyId"), checkNotNull(AWSSecretAccessKey, "AWSSecretAccessKey")));
} }
@Override @Override

View File

@ -21,9 +21,9 @@
under the License. under the License.
==================================================================== ====================================================================
==== ====
This samples uses the Google App Engine for Java SDK located at http://googleappengine.googlecode.com/files/appengine-java-sdk-1.2.0.zip This samples uses the Google App Engine for Java SDK located at http://googleappengine.googlecode.com/files/appengine-java-sdk-1.2.1.zip
Please unzip the above file and modify your maven settings.xml like below before attempting to run 'mvn install' Please unzip the above file and modify your maven settings.xml like below before attempting to run 'mvn -Plive install'
<profile> <profile>
<id>appengine</id> <id>appengine</id>
@ -31,7 +31,7 @@ Please unzip the above file and modify your maven settings.xml like below before
<activeByDefault>true</activeByDefault> <activeByDefault>true</activeByDefault>
</activation> </activation>
<properties> <properties>
<appengine.home>/path/to/appengine-java-sdk-1.2.0</appengine.home> <appengine.home>/path/to/appengine-java-sdk-1.2.1</appengine.home>
</properties> </properties>
</profile> </profile>

View File

@ -23,66 +23,78 @@
*/ */
package org.jclouds.samples.googleappengine; package org.jclouds.samples.googleappengine;
import com.google.inject.Inject; import java.io.IOException;
import com.google.inject.Singleton; import java.io.Writer;
import org.jclouds.aws.s3.S3Context; import java.util.List;
import org.jclouds.aws.s3.S3ResponseException; import java.util.concurrent.TimeUnit;
import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.logging.Logger;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Writer; import org.jclouds.aws.s3.S3Context;
import java.util.List; import org.jclouds.aws.s3.AWSResponseException;
import java.util.concurrent.TimeUnit; import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.logging.Logger;
import com.google.inject.Inject;
import com.google.inject.Singleton;
/** /**
* Shows an example of how to use @{link S3Connection} injected with Guice. * Shows an example of how to use @{link S3Connection} injected with Guice.
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class JCloudsServlet extends HttpServlet { public class JCloudsServlet extends HttpServlet {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Inject private final static String className;
S3Context context;
@Resource /**
protected Logger logger = Logger.NULL; * Tests google's behaviour in static context
*/
static {
StackTraceElement[] sTrace = new Exception().getStackTrace();
// sTrace[0] will be always there
className = sTrace[0].getClassName();
}
@Override @Inject
protected void doGet(HttpServletRequest httpServletRequest, S3Context context;
HttpServletResponse httpServletResponse) throws ServletException,
IOException {
httpServletResponse.setContentType("text/plain");
Writer writer = httpServletResponse.getWriter();
try {
List<S3Bucket.Metadata> myBuckets = context.getConnection()
.listOwnedBuckets().get(10, TimeUnit.SECONDS);
writer.write("List:\n");
for (S3Bucket.Metadata bucket : myBuckets) {
writer.write(String.format(" %1$s", bucket));
try {
writer.write(String.format(": %1$s entries%n", context
.createInputStreamMap(bucket.getName()).size()));
} catch (S3ResponseException e) {
String message = String.format(
": unable to list entries due to: %1$s%n", e
.getError().getCode());
writer.write(message);
logger.warn(e, "message");
}
@Resource
protected Logger logger = Logger.NULL;
@Override
protected void doGet(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws ServletException, IOException {
httpServletResponse.setContentType("text/plain");
Writer writer = httpServletResponse.getWriter();
writer.write(className + "\n");
try {
List<S3Bucket.Metadata> myBuckets = context.getConnection().listOwnedBuckets().get(10,
TimeUnit.SECONDS);
writer.write("List:\n");
for (S3Bucket.Metadata bucket : myBuckets) {
writer.write(String.format(" %1$s", bucket));
try {
writer.write(String.format(": %1$s entries%n", context.createInputStreamMap(
bucket.getName()).size()));
} catch (AWSResponseException e) {
String message = String.format(": unable to list entries due to: %1$s%n", e
.getError().getCode());
writer.write(message);
logger.warn(e, "message");
} }
} catch (Exception e) {
throw new ServletException(e); }
} } catch (Exception e) {
writer.flush(); throw new ServletException(e);
writer.close(); }
} writer.flush();
writer.close();
}
} }

View File

@ -23,6 +23,10 @@
*/ */
package org.jclouds.http.options; package org.jclouds.http.options;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.SortedMap; import java.util.SortedMap;
@ -58,6 +62,14 @@ public class BaseHttpRequestOptions implements HttpRequestOptions {
headers.put(key, value); headers.put(key, value);
} }
protected void encodeAndReplaceParameter(String parameter, String value) {
try {
parameters.put(parameter, URLEncoder.encode(checkNotNull(value, parameter), "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("bad encoding on " + parameter + ": " + value, e);
}
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */