Issue 76: restructured to jaxrs annotations and created new ones where functionality was lacking. added resteasy client apis to our repository, as there is no dep-free dist available from source. introduced TransformingHttpCommandExecutorService, which processes http independently of extracting results.

This uses an ExecutorService.  In google app engine, there is now a WithinThreadExecutorService which is automatically selected via CloudContext as per the annotation SingleThreaded.  All command classes have been converted to annotation definitions in S3Connection.

git-svn-id: http://jclouds.googlecode.com/svn/trunk@1608 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-07-11 22:36:51 +00:00
parent 8c49965f3d
commit e9aee711d3
257 changed files with 10019 additions and 6296 deletions

View File

@ -46,16 +46,6 @@
</scm>
<dependencies>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>bouncycastle</groupId>
<artifactId>bcprov-jdk15</artifactId>
<version>140</version>
</dependency>
<dependency>
<groupId>xstream</groupId>
<artifactId>xstream</artifactId>

View File

@ -24,7 +24,7 @@
package org.jclouds.aws;
import org.jclouds.aws.domain.AWSError;
import org.jclouds.http.HttpFutureCommand;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
@ -43,14 +43,14 @@ public class AWSResponseException extends HttpResponseException {
private AWSError error = new AWSError();
public AWSResponseException(HttpFutureCommand<?> command, HttpResponse response, AWSError error) {
public AWSResponseException(HttpCommand command, HttpResponse response, AWSError error) {
super(String.format("command %s failed with code %s, error: %s", command.toString(), response
.getStatusCode(), error.toString()), command, response);
this.setError(error);
}
public AWSResponseException(HttpFutureCommand<?> command, HttpResponse response, AWSError error,
public AWSResponseException(HttpCommand command, HttpResponse response, AWSError error,
Throwable cause) {
super(String.format("command %1$s failed with error: %2$s", command.toString(), error
.toString()), command, response, cause);
@ -58,14 +58,14 @@ public class AWSResponseException extends HttpResponseException {
}
public AWSResponseException(String message, HttpFutureCommand<?> command, HttpResponse response,
public AWSResponseException(String message, HttpCommand command, HttpResponse response,
AWSError error) {
super(message, command, response);
this.setError(error);
}
public AWSResponseException(String message, HttpFutureCommand<?> command, HttpResponse response,
public AWSResponseException(String message, HttpCommand command, HttpResponse response,
AWSError error, Throwable cause) {
super(message, command, response, cause);
this.setError(error);

View File

@ -23,8 +23,8 @@
*/
package org.jclouds.aws.reference;
import org.jclouds.command.pool.PoolConstants;
import org.jclouds.http.HttpConstants;
import org.jclouds.http.pool.PoolConstants;
/**
* Configuration properties and constants used in AWS connections.

View File

@ -24,7 +24,7 @@
package org.jclouds.aws.xml;
import org.jclouds.aws.domain.AWSError;
import org.jclouds.http.commands.callables.xml.ParseSax;
import org.jclouds.http.functions.ParseSax;
/**
* Parses the error from the Amazon S3 REST API.

View File

@ -1,46 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
====================================================================
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.
====================================================================
-->
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!--
For more configuration infromation and examples see the Apache Log4j website: http://logging.apache.org/log4j/
-->
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
<!--
For more configuration infromation and examples see the Apache Log4j
website: http://logging.apache.org/log4j/
-->
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
debug="false">
<!-- A time/date based rolling appender -->
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds.log"/>
<param name="Append" value="true"/>
<!-- A time/date based rolling appender -->
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd"/>
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE"/>
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n"/>
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!-- The full pattern: Date MS Priority [Category] (Thread:NDC) Message\n
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<!--
The full pattern: Date MS Priority [Category] (Thread:NDC) Message\n
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x)
%m%n"/>
-->
</layout>
</appender>
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
<!-- ================ -->
<!-- Limit categories -->
<!-- ================ -->
<!-- ================ -->
<!-- Limit categories -->
<!-- ================ -->
<category name="org.jclouds">
<priority value="TRACE" />
</category>
<category name="org.jclouds">
<priority value="TRACE"/>
</category>
<!-- ======================= -->
<!-- Setup the Root category -->
<!-- ======================= -->
<!-- ======================= -->
<!-- Setup the Root category -->
<!-- ======================= -->
<root>
<priority value="WARN"/>
<appender-ref ref="FILE"/>
</root>
<root>
<priority value="WARN" />
<appender-ref ref="ASYNC" />
</root>
</log4j:configuration>

View File

@ -1,69 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
$HeadURL$ $Revision$ $Date$ Copyright (C) 2009 Adrian Cole
<adrian@jclouds.org>
<!--
$HeadURL$ $Revision$ $Date$ 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
====================================================================
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.html 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.
====================================================================
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-s3-project</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-s3</artifactId>
<name>jclouds Amazon S3 Components Core</name>
<packaging>jar</packaging>
<description>jclouds Core components to access Amazon S3</description>
http://www.apache.org/licenses/LICENSE-2.0.html 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.
====================================================================
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-s3-project</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-s3</artifactId>
<name>jclouds Amazon S3 Components Core</name>
<packaging>jar</packaging>
<description>jclouds Core components to access Amazon S3</description>
<scm>
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk</connection>
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk</developerConnection>
<url>http://jclouds.googlecode.com/svn/trunk</url>
</scm>
<scm>
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk</connection>
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk</developerConnection>
<url>http://jclouds.googlecode.com/svn/trunk</url>
</scm>
<properties>
<jclouds.s3.httpstream.url>http://apache.rediris.es/maven/binaries/apache-maven-2.1.0-bin.tar.bz2
<properties>
<jclouds.s3.httpstream.url>http://apache.rediris.es/maven/binaries/apache-maven-2.1.0-bin.tar.bz2
</jclouds.s3.httpstream.url>
<jclouds.s3.httpstream.md5>9268c9de2cccfd0d8fbcdbcfaf517a87</jclouds.s3.httpstream.md5>
</properties>
<repositories>
<repository>
<id>googlecode.java-xmlbuilder</id>
<url>http://java-xmlbuilder.googlecode.com/svn/repo</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jamesmurty.utils</groupId>
<artifactId>java-xmlbuilder</artifactId>
<version>0.3</version>
</dependency>
</dependencies>
<jclouds.s3.httpstream.eTag>9268c9de2cccfd0d8fbcdbcfaf517a87</jclouds.s3.httpstream.eTag>
</properties>
<repositories>
<repository>
<id>googlecode.java-xmlbuilder</id>
<url>http://java-xmlbuilder.googlecode.com/svn/repo</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jamesmurty.utils</groupId>
<artifactId>java-xmlbuilder</artifactId>
<version>0.3</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-httpnio</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -23,238 +23,465 @@
*/
package org.jclouds.aws.s3;
import org.jclouds.aws.s3.commands.options.*;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.aws.s3.domain.S3Object;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jclouds.aws.s3.binders.AccessControlListBinder;
import org.jclouds.aws.s3.binders.S3ObjectBinder;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.functions.ParseETagHeader;
import org.jclouds.aws.s3.functions.ParseMetadataFromHeaders;
import org.jclouds.aws.s3.functions.ParseObjectFromHeadersAndHttpContent;
import org.jclouds.aws.s3.functions.ReturnFalseOn404;
import org.jclouds.aws.s3.functions.ReturnNotFoundIfBucketDoesntExist;
import org.jclouds.aws.s3.functions.ReturnNotFoundIfObjectDoesntExist;
import org.jclouds.aws.s3.functions.ReturnS3BucketNotFoundOn404;
import org.jclouds.aws.s3.functions.ReturnS3ObjectMetadataNotFoundOn404;
import org.jclouds.aws.s3.functions.ReturnS3ObjectNotFoundOn404;
import org.jclouds.aws.s3.functions.ReturnTrueIfBucketAlreadyOwnedByYou;
import org.jclouds.aws.s3.functions.ReturnTrueOn404FalseIfNotEmpty;
import org.jclouds.aws.s3.functions.S3ObjectKey;
import org.jclouds.aws.s3.options.CopyObjectOptions;
import org.jclouds.aws.s3.options.ListBucketOptions;
import org.jclouds.aws.s3.options.PutBucketOptions;
import org.jclouds.aws.s3.options.PutObjectOptions;
import org.jclouds.aws.s3.xml.AccessControlListHandler;
import org.jclouds.aws.s3.xml.CopyObjectHandler;
import org.jclouds.aws.s3.xml.ListAllMyBucketsHandler;
import org.jclouds.aws.s3.xml.ListBucketHandler;
import org.jclouds.http.options.GetOptions;
import org.jclouds.rest.EntityParam;
import org.jclouds.rest.ExceptionParser;
import org.jclouds.rest.Header;
import org.jclouds.rest.HostPrefixParam;
import org.jclouds.rest.HttpRequestOptionsBinder;
import org.jclouds.rest.PathParamParser;
import org.jclouds.rest.Query;
import org.jclouds.rest.ResponseParser;
import org.jclouds.rest.SkipEncoding;
import org.jclouds.rest.VirtualHost;
import org.jclouds.rest.XMLResponseParser;
/**
* Provides access to S3 via their REST API.
* <p/>
* All commands return a Future of the result from S3. Any exceptions incurred
* during processing will be wrapped in an {@link ExecutionException} as
* documented in {@link Future#get()}.
*
* All commands return a Future of the result from S3. Any exceptions incurred during processing
* will be wrapped in an {@link ExecutionException} as documented in {@link Future#get()}.
*
* @author Adrian Cole
* @author James Murty
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAPI.html" />
*/
@VirtualHost
@SkipEncoding('/')
public interface S3Connection {
/**
* Retrieve a complete <code>S3Object</code>.
*
* @param bucketName namespace of the object you are retrieving
* @param key unique key in the s3Bucket identifying the object
* @return Future reference to a fully populated S3Object including data
* stored in S3 or {@link S3Object#NOT_FOUND} if not present.
* @see org.jclouds.aws.s3.commands.GetObject
*/
Future<S3Object> getObject(String bucketName, String key);
/**
* Retrieves the S3Object associated with the Key or {@link S3Object#NOT_FOUND} if not available;
*
* <p/>
* To use GET, you must have READ access to the object. If READ access is granted to the
* anonymous user, you can request the object without an authorization header.
*
* @param bucketName
* namespace of the object you are retrieving
* @param key
* unique key in the s3Bucket identifying the object
* @return Future reference to a fully populated S3Object including data stored in S3 or
* {@link S3Object#NOT_FOUND} if not present.
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTObjectGET.html"
* />
*/
@GET
@Path("{key}")
@ExceptionParser(ReturnS3ObjectNotFoundOn404.class)
@ResponseParser(ParseObjectFromHeadersAndHttpContent.class)
Future<S3Object> getObject(@HostPrefixParam String bucketName, @PathParam("key") String key);
/**
* Like {@link #getObject(String, String)} except you can use
* {@link GetObjectOptions} to control delivery.
*
* @return S3Object containing data relevant to the
* <code>options</options> specified or {@link S3Object#NOT_FOUND} if not present.
* @throws org.jclouds.http.HttpResponseException
* if the conditions requested set were not satisfied by the
* object on the server.
* @see #getObject(String, String)
* @see GetObjectOptions
*/
Future<S3Object> getObject(String bucketName, String key,
GetObjectOptions options);
/**
* Like {@link #getObject(String, String)} except you can use {@link GetObjectOptions} to control
* delivery.
* <p />
* This command allows you to specify {@link GetObjectOptions} to control delivery of content.
*
* <h2>Note</h2> If you specify any of the below options, you will receive partial content:
* <ul>
* <li>{@link GetObjectOptions#range}</li>
* <li>{@link GetObjectOptions#startAt}</li>
* <li>{@link GetObjectOptions#tail}</li>
* </ul>
*
* @return S3Object containing data relevant to the <code>options</options> specified or
* {@link S3Object#NOT_FOUND} if not present.
* @throws org.jclouds.http.HttpResponseException
* if the conditions requested set were not satisfied by the object on the server.
* @see #getObject(String, String)
* @see GetObjectOptions
*/
@GET
@Path("{key}")
@ExceptionParser(ReturnS3ObjectNotFoundOn404.class)
@ResponseParser(ParseObjectFromHeadersAndHttpContent.class)
Future<S3Object> getObject(@HostPrefixParam String bucketName, @PathParam("key") String key,
GetOptions options);
/**
* Retrieves the {@link org.jclouds.aws.s3.domain.S3Object.Metadata metadata} of the object associated
* with the key.
*
* @param bucketName namespace of the metadata you are retrieving
* @param key unique key in the s3Bucket identifying the object
* @return metadata associated with the key or
* {@link org.jclouds.aws.s3.domain.S3Object.Metadata#NOT_FOUND} if not present;
* @see org.jclouds.aws.s3.commands.HeadObject
*/
Future<S3Object.Metadata> headObject(String bucketName, String key);
/**
* Retrieves the {@link org.jclouds.aws.s3.domain.S3Object.Metadata metadata} of the object
* associated with the key or {@link org.jclouds.aws.s3.domain.S3Object.Metadata#NOT_FOUND} if
* not available.
*
* <p/>
* The HEAD operation is used to retrieve information about a specific object or object size,
* without actually fetching the object itself. This is useful if you're only interested in the
* object metadata, and don't want to waste bandwidth on the object data.
*
*
* @param bucketName
* namespace of the metadata you are retrieving
* @param key
* unique key in the s3Bucket identifying the object
* @return metadata associated with the key or
* {@link org.jclouds.aws.s3.domain.S3Object.Metadata#NOT_FOUND} if not present;
* @see #getObject(String, String)
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTObjectHEAD.html"
* />
*/
@HEAD
@Path("{key}")
@ExceptionParser(ReturnS3ObjectMetadataNotFoundOn404.class)
@ResponseParser(ParseMetadataFromHeaders.class)
S3Object.Metadata headObject(@HostPrefixParam String bucketName, @PathParam("key") String key);
/**
* Removes the object and metadata associated with the key.
*
* @param bucketName namespace of the object you are deleting
* @param key unique key in the s3Bucket identifying the object
* @return true if deleted
* @throws org.jclouds.http.HttpResponseException
* if the bucket is not available
* @see org.jclouds.aws.s3.commands.DeleteObject
*/
Future<Boolean> deleteObject(String bucketName, String key);
/**
* Removes the object and metadata associated with the key.
* <p/>
* The DELETE request operation removes the specified object from Amazon S3. Once deleted, there
* is no method to restore or undelete an object.
*
*
* @param bucketName
* namespace of the object you are deleting
* @param key
* unique key in the s3Bucket identifying the object
* @return true if deleted
* @throws org.jclouds.http.HttpResponseException
* if the bucket is not available
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?
* RESTObjectDELETE.html" />
*/
@DELETE
@Path("{key}")
Future<Boolean> deleteObject(@HostPrefixParam String bucketName, @PathParam("key") String key);
/**
* Store data by creating or overwriting an object.
* <p/>
* This method will store the object with the default <code>private</code>
* acl.
*
* @param bucketName namespace of the object you are storing
* @param object contains the data and metadata to create or overwrite
* @return MD5 hash of the content uploaded
* @see org.jclouds.aws.s3.domain.acl.CannedAccessPolicy#PRIVATE
* @see org.jclouds.aws.s3.commands.PutObject
*/
Future<byte[]> putObject(String bucketName, S3Object object);
/**
* Store data by creating or overwriting an object.
* <p/>
* This method will store the object with the default <code>private</code> acl.
*
* <p/>
* This returns a byte[] of the eTag hash of what Amazon S3 received
* <p />
*
* @param bucketName
* namespace of the object you are storing
* @param object
* contains the data and metadata to create or overwrite
* @return MD5 hash of the content uploaded
* @see org.jclouds.aws.s3.domain.CannedAccessPolicy#PRIVATE
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTObjectPUT.html"
* />
*/
@PUT
@Path("{key}")
@ResponseParser(ParseETagHeader.class)
Future<byte[]> putObject(
@HostPrefixParam String bucketName,
@PathParam("key") @PathParamParser(S3ObjectKey.class) @EntityParam(S3ObjectBinder.class) S3Object object);
/**
* Like {@link #putObject(String, S3Object)} except you can use
* {@link CopyObjectOptions} to specify an alternate
* {@link org.jclouds.aws.s3.domain.acl.CannedAccessPolicy acl}, override
* {@link org.jclouds.aws.s3.domain.S3Object.Metadata#getUserMetadata() userMetadata}, or specify
* conditions for copying the object.
*
* @param options options for creating the object
* @throws org.jclouds.http.HttpResponseException
* if the conditions requested set are not satisfied by the
* object on the server.
* @see S3Connection#putObject(String, S3Object)
* @see PutObjectOptions
*/
Future<byte[]> putObject(String bucketName, S3Object object,
PutObjectOptions options);
/**
* Like {@link #putObject(String, S3Object)} except you can use {@link PutObjectOptions} to
* control delivery of content.
*
*
* @param options
* options for creating the object
* @throws org.jclouds.http.HttpResponseException
* if the conditions requested set are not satisfied by the object on the server.
* @see S3Connection#putObject(String, S3Object)
* @see PutObjectOptions
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTObjectPUT.html"
* />
*/
@PUT
@Path("{key}")
@ResponseParser(ParseETagHeader.class)
Future<byte[]> putObject(
@HostPrefixParam String bucketName,
@PathParam("key") @PathParamParser(S3ObjectKey.class) @EntityParam(S3ObjectBinder.class) S3Object object,
PutObjectOptions options);
/**
* Create and name your own bucket in which to store your objects.
*
* @return true, if the bucket was created or already exists
* @see org.jclouds.aws.s3.commands.PutBucket
*/
Future<Boolean> putBucketIfNotExists(String name);
/**
* Create and name your own bucket in which to store your objects.
*
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketPUT.html"
* />
* @return true, if the bucket was created or already exists
* @see org.jclouds.aws.s3.commands.PutBucket
*/
@PUT
@Path("/")
@ExceptionParser(ReturnTrueIfBucketAlreadyOwnedByYou.class)
Future<Boolean> putBucketIfNotExists(@HostPrefixParam String bucketName);
/**
* Like {@link #putBucketIfNotExists(String)} except that you can use
* {@link PutBucketOptions} to create the bucket in EU. Create and name your
*
* @param options for creating your bucket
* @see PutBucketOptions
*/
Future<Boolean> putBucketIfNotExists(String name, PutBucketOptions options);
/**
* Like {@link #putBucketIfNotExists(String)} except that you can use {@link PutBucketOptions} to
* create the bucket in EU.
* <p/>
* The PUT request operation with a bucket URI creates a new bucket. Depending on your latency
* and legal requirements, you can specify a location constraint that will affect where your data
* physically resides. You can currently specify a Europe (EU) location constraint via
* {@link PutBucketOptions}.
*
* @param options
* for creating your bucket
* @see PutBucketOptions
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketPUT.html"
* />
*
*/
@PUT
@Path("/")
@ExceptionParser(ReturnTrueIfBucketAlreadyOwnedByYou.class)
Future<Boolean> putBucketIfNotExists(@HostPrefixParam String bucketName,
@EntityParam(HttpRequestOptionsBinder.class) PutBucketOptions options);
/**
* Deletes the bucket, if it is empty.
*
* @param s3Bucket what to delete
* @return false, if the bucket was not empty and therefore not deleted
* @see org.jclouds.aws.s3.commands.DeleteBucket
*/
Future<Boolean> deleteBucketIfEmpty(String s3Bucket);
/**
* Deletes the bucket, if it is empty.
* <p/>
* The DELETE request operation deletes the bucket named in the URI. All objects in the bucket
* must be deleted before the bucket itself can be deleted.
* <p />
* Only the owner of a bucket can delete it, regardless of the bucket's access control policy.
*
*
* @param bucketName
* what to delete
* @return false, if the bucket was not empty and therefore not deleted
* @see org.jclouds.aws.s3.commands.DeleteBucket
* @see <a href=
* "http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketDELETE.html"
* />
*/
@DELETE
@Path("/")
@ExceptionParser(ReturnTrueOn404FalseIfNotEmpty.class)
boolean deleteBucketIfEmpty(@HostPrefixParam String bucketName);
/**
* Copies one object to another bucket, retaining UserMetadata from the
* source. The destination will have a private acl.
*
* @return metadata populated with lastModified and md5 of the new object
* @see org.jclouds.aws.s3.commands.CopyObject
*/
Future<S3Object.Metadata> copyObject(String sourceBucket,
String sourceObject, String destinationBucket,
String destinationObject);
/**
* Copies one object to another bucket, retaining UserMetadata from the source. The destination
* will have a private acl. The copy operation creates a copy of an object that is already stored
* in Amazon S3.
* <p/>
* When copying an object, you can preserve all metadata (default) or
* {@link CopyObjectOptions#overrideMetadataWith(com.google.common.collect.Multimap) specify new
* metadata}. However, the ACL is not preserved and is set to private for the user making the
* request. To override the default ACL setting,
* {@link CopyObjectOptions#overrideAcl(org.jclouds.aws.s3.domain.CannedAccessPolicy) specify a
* new ACL} when generating a copy request.
*
* @return metadata populated with lastModified and eTag of the new object
* @see org.jclouds.aws.s3.commands.CopyObject
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTObjectCOPY.html"
* />
* @see CopyObjectOptions
* @see org.jclouds.aws.s3.domain.CannedAccessPolicy
*/
@PUT
@Path("{destinationObject}")
@Header(key = "x-amz-copy-source", value = "/{sourceBucket}/{sourceObject}")
@XMLResponseParser(CopyObjectHandler.class)
Future<S3Object.Metadata> copyObject(@PathParam("sourceBucket") String sourceBucket,
@PathParam("sourceObject") String sourceObject,
@HostPrefixParam String destinationBucket,
@PathParam("destinationObject") String destinationObject);
/**
* Like {@link #putObject(String, S3Object)} except you can use
* {@link PutObjectOptions} to specify an alternate
* {@link org.jclouds.aws.s3.domain.acl.CannedAccessPolicy acl}.
*
* @param options options for creating the object
* @throws org.jclouds.http.HttpResponseException
* if the conditions requested set are not satisfied by the
* object on the server.
* @see S3Connection#putObject(String, S3Object)
* @see PutObjectOptions
*/
Future<S3Object.Metadata> copyObject(String sourceBucket,
String sourceObject, String destinationBucket,
String destinationObject, CopyObjectOptions options);
/**
* Like {@link #putObject(String, S3Object)} except you can use {@link PutObjectOptions} to
* specify an alternate {@link org.jclouds.aws.s3.domain.CannedAccessPolicy acl}.
*
* @param options
* options for creating the object
* @throws org.jclouds.http.HttpResponseException
* if the conditions requested set are not satisfied by the object on the server.
* @see S3Connection#putObject(String, S3Object)
* @see PutObjectOptions
*/
@PUT
@Path("{destinationObject}")
@Header(key = "x-amz-copy-source", value = "/{sourceBucket}/{sourceObject}")
@XMLResponseParser(CopyObjectHandler.class)
Future<S3Object.Metadata> copyObject(@PathParam("sourceBucket") String sourceBucket,
@PathParam("sourceObject") String sourceObject,
@HostPrefixParam String destinationBucket,
@PathParam("destinationObject") String destinationObject, CopyObjectOptions options);
/**
* @see org.jclouds.aws.s3.commands.BucketExists
*/
Future<Boolean> bucketExists(String name);
/**
* Issues a HEAD command to determine if the bucket exists or not.
*/
@HEAD
@Path("/")
@Query(key = "max-keys", value = "0")
@ExceptionParser(ReturnFalseOn404.class)
boolean bucketExists(@HostPrefixParam String bucketName);
/**
* Retrieve a complete <code>S3Bucket</code> listing.
*
* @param bucketName namespace of the objects you wish to list
* @return Future reference to a fully populated S3Bucket including metadata
* of the S3Objects it contains or {@link S3Bucket#NOT_FOUND} if not
* present.
* @see org.jclouds.aws.s3.commands.ListBucket
*/
Future<S3Bucket> listBucket(String bucketName);
/**
* Retrieve a complete <code>S3Bucket</code> listing. A GET request operation using a bucket URI
* lists information about the objects in the bucket.
* <p />
* To list the keys of a bucket, you must have READ access to the bucket.
* <p/>
*
* @param bucketName
* namespace of the objects you wish to list
* @return Future reference to a fully populated S3Bucket including metadata of the S3Objects it
* contains or {@link S3Bucket#NOT_FOUND} if not present.
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketGET.html"
* />
*/
@GET
@Path("/")
@XMLResponseParser(ListBucketHandler.class)
@ExceptionParser(ReturnS3BucketNotFoundOn404.class)
Future<S3Bucket> listBucket(@HostPrefixParam String bucketName);
/**
* Like {@link #listBucket(String)} except you can use
* {@link ListBucketOptions} to control the amount of S3Objects to return.
*
* @return S3Bucket containing a subset of {@link org.jclouds.aws.s3.domain.S3Object.Metadata}
* depending on
* <code>options</options> specified or {@link S3Bucket#NOT_FOUND} if not present.
* @see #listBucket(String)
* @see ListBucketOptions
*/
Future<S3Bucket> listBucket(String name, ListBucketOptions options);
/**
* Like {@link #listBucket(String)} except you can use {@link ListBucketOptions} to control the
* amount of S3Objects to return.
*
* @return S3Bucket containing a subset of {@link org.jclouds.aws.s3.domain.S3Object.Metadata}
* depending on
* <code>options</options> specified or {@link S3Bucket#NOT_FOUND} if not present.
* @see #listBucket(String)
* @see ListBucketOptions
*/
@GET
@Path("/")
@XMLResponseParser(ListBucketHandler.class)
Future<S3Bucket> listBucket(@HostPrefixParam String bucketName, ListBucketOptions options);
/**
* @return list of all of the buckets owned by the authenticated sender of
* the request.
* @see org.jclouds.aws.s3.commands.ListOwnedBuckets
*/
Future<List<S3Bucket.Metadata>> listOwnedBuckets();
/**
* Returns a list of all of the buckets owned by the authenticated sender of the request.
*
* @return list of all of the buckets owned by the authenticated sender of the request.
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTServiceGET.html"
* />
*
*/
@GET
@XMLResponseParser(ListAllMyBucketsHandler.class)
@Path("/")
List<S3Bucket.Metadata> listOwnedBuckets();
/**
* @return access permissions of the bucket
*
* @see org.jclouds.aws.s3.commands.GetAccessControlList
*/
Future<AccessControlList> getBucketACL(String bucket);
/**
*
* A GET request operation directed at an object or bucket URI with the "acl" parameter retrieves
* the Access Control List (ACL) settings for that S3 item.
* <p />
* To list a bucket's ACL, you must have READ_ACP access to the item.
*
* @return access permissions of the bucket
*
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html"/>
*/
@GET
@Query(key = "acl")
@XMLResponseParser(AccessControlListHandler.class)
@ExceptionParser(ReturnNotFoundIfBucketDoesntExist.class)
Future<AccessControlList> getBucketACL(@HostPrefixParam String bucketName);
/**
* Update a bucket's Access Control List settings.
* @param bucket
* the bucket whose Access Control List settings will be updated.
* @param acl
* the ACL to apply to the bucket. This acl object <strong>must</strong>
* include a valid owner identifier string in {@link AccessControlList#getOwner()}.
* @return
* true if the bucket's Access Control List was updated successfully.
*
* @see org.jclouds.aws.s3.commands.PutBucketAccessControlList
*/
Future<Boolean> putBucketACL(String bucket, AccessControlList acl);
/**
* Update a bucket's Access Control List settings.
* <p/>
* A PUT request operation directed at a bucket URI with the "acl" parameter sets the Access
* Control List (ACL) settings for that S3 item.
* <p />
* To set a bucket or object's ACL, you must have WRITE_ACP or FULL_CONTROL access to the item.
*
* @param bucketName
* the bucket whose Access Control List settings will be updated.
* @param acl
* the ACL to apply to the bucket. This acl object <strong>must</strong> include a
* valid owner identifier string in {@link AccessControlList#getOwner()}.
* @return true if the bucket's Access Control List was updated successfully.
*
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html"/>
*/
@PUT
@Path("/")
@Query(key = "acl")
Future<Boolean> putBucketACL(@HostPrefixParam String bucketName,
@EntityParam(AccessControlListBinder.class) AccessControlList acl);
/**
* @return access permissions of the object
*
* @see org.jclouds.aws.s3.commands.GetAccessControlList
*/
Future<AccessControlList> getObjectACL(String bucket, String objectKey);
/**
* A GET request operation directed at an object or bucket URI with the "acl" parameter retrieves
* the Access Control List (ACL) settings for that S3 item.
* <p />
* To list a object's ACL, you must have READ_ACP access to the item.
*
* @return access permissions of the object
*
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html"/>
*/
@GET
@Query(key = "acl")
@Path("{key}")
@XMLResponseParser(AccessControlListHandler.class)
@ExceptionParser(ReturnNotFoundIfObjectDoesntExist.class)
Future<AccessControlList> getObjectACL(@HostPrefixParam String bucketName,
@PathParam("key") String key);
/**
* Update an object's Access Control List settings.
* @param bucket
* the bucket containing the object to be updated
* @param objectKey
* the key of the object whose Access Control List settings will be updated.
* @param acl
* the ACL to apply to the object. This acl object <strong>must</strong>
* include a valid owner identifier string in {@link AccessControlList#getOwner()}.
* @return
* true if the object's Access Control List was updated successfully.
*
* @see org.jclouds.aws.s3.commands.PutBucketAccessControlList
*/
Future<Boolean> putObjectACL(String bucket, String objectKey, AccessControlList acl);
/**
* Update an object's Access Control List settings.
* <p/>
* A PUT request operation directed at an object URI with the "acl" parameter sets the Access
* Control List (ACL) settings for that S3 item.
* <p />
* To set a bucket or object's ACL, you must have WRITE_ACP or FULL_CONTROL access to the item.
*
* @param bucket
* the bucket containing the object to be updated
* @param objectKey
* the key of the object whose Access Control List settings will be updated.
* @param acl
* the ACL to apply to the object. This acl object <strong>must</strong> include a
* valid owner identifier string in {@link AccessControlList#getOwner()}.
* @return true if the object's Access Control List was updated successfully.
*
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html"/>
*/
@PUT
@Query(key = "acl")
@Path("{key}")
Future<Boolean> putObjectACL(@HostPrefixParam String bucketName, @PathParam("key") String key,
@EntityParam(AccessControlListBinder.class) AccessControlList acl);
}

View File

@ -26,25 +26,25 @@ package org.jclouds.aws.s3;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AWS_ACCESSKEYID;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AWS_SECRETACCESSKEY;
import static org.jclouds.command.pool.PoolConstants.PROPERTY_POOL_IO_WORKER_THREADS;
import static org.jclouds.command.pool.PoolConstants.PROPERTY_POOL_MAX_CONNECTIONS;
import static org.jclouds.command.pool.PoolConstants.PROPERTY_POOL_MAX_CONNECTION_REUSE;
import static org.jclouds.command.pool.PoolConstants.PROPERTY_POOL_MAX_SESSION_FAILURES;
import static org.jclouds.command.pool.PoolConstants.PROPERTY_POOL_REQUEST_INVOKER_THREADS;
import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_ADDRESS;
import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_MAX_REDIRECTS;
import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_MAX_RETRIES;
import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_SECURE;
import static org.jclouds.http.HttpConstants.PROPERTY_SAX_DEBUG;
import static org.jclouds.http.pool.PoolConstants.PROPERTY_POOL_IO_WORKER_THREADS;
import static org.jclouds.http.pool.PoolConstants.PROPERTY_POOL_MAX_CONNECTIONS;
import static org.jclouds.http.pool.PoolConstants.PROPERTY_POOL_MAX_CONNECTION_REUSE;
import static org.jclouds.http.pool.PoolConstants.PROPERTY_POOL_MAX_SESSION_FAILURES;
import static org.jclouds.http.pool.PoolConstants.PROPERTY_POOL_REQUEST_INVOKER_THREADS;
import java.util.List;
import java.util.Properties;
import org.jclouds.aws.s3.config.LiveS3ConnectionModule;
import org.jclouds.aws.s3.config.RestS3ConnectionModule;
import org.jclouds.aws.s3.config.S3ContextModule;
import org.jclouds.aws.s3.xml.config.S3ParserModule;
import org.jclouds.cloud.CloudContextBuilder;
import org.jclouds.http.config.JavaUrlHttpFutureCommandClientModule;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import com.google.inject.Injector;
@ -58,7 +58,7 @@ import com.google.inject.Module;
* <p/>
* <p/>
* If no <code>Module</code>s are specified, the default {@link JDKLoggingModule logging} and
* {@link JavaUrlHttpFutureCommandClientModule http transports} will be installed.
* {@link JavaUrlHttpCommandExecutorServiceModule http transports} will be installed.
*
* @author Adrian Cole, Andrew Newdigate
* @see S3Context
@ -107,7 +107,7 @@ public class S3ContextBuilder extends CloudContextBuilder<S3Connection, S3Contex
}
protected void addConnectionModule(List<Module> modules) {
modules.add(new LiveS3ConnectionModule());
modules.add(new RestS3ConnectionModule());
}
}

View File

@ -23,20 +23,19 @@
*/
package org.jclouds.aws.s3;
import org.jclouds.http.config.JavaUrlHttpFutureCommandClientModule;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import com.google.inject.Module;
/**
* Creates {@link S3Context} instances based on the most commonly requested
* arguments.
* Creates {@link S3Context} instances based on the most commonly requested arguments.
* <p/>
* Note that Threadsafe objects will be bound as singletons to the Injector or Context provided.
* <p/>
* <p/>
* If no <code>Module</code>s are specified, the default {@link JDKLoggingModule logging} and
* {@link JavaUrlHttpFutureCommandClientModule http transports} will be installed.
* {@link JavaUrlHttpCommandExecutorServiceModule http transports} will be installed.
*
* @author Adrian Cole, Andrew Newdigate
* @see S3Context

View File

@ -32,7 +32,7 @@ import java.util.Map;
* common object types.
* <p/>
* <h2>Note</h2> All <code>put</code> operations will invoke
* {@link org.jclouds.aws.s3.domain.S3Object#generateMd5}. By extension, {@link #put(Object, Object)}
* {@link org.jclouds.aws.s3.domain.S3Object#generateETag}. By extension, {@link #put(Object, Object)}
* will result in the InputStream being converted to a byte array. For this
* reason, do not use {@link #put(Object, Object)} to store files. Use
* {@link #putFile(String, File)} or {@link S3ObjectMap} instead.

View File

@ -31,7 +31,7 @@ import org.jclouds.aws.s3.domain.S3Object;
*
* <p/>
* This allows you to acces the underlying {@link S3Object} so that you can
* manually set metadata such as length, content-type, or md5 hash.
* manually set metadata such as length, content-type, or eTag hash.
*
* @author Adrian Cole
*

View File

@ -0,0 +1,97 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.binders;
import java.util.Properties;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.AccessControlList.CanonicalUserGrantee;
import org.jclouds.aws.s3.domain.AccessControlList.EmailAddressGrantee;
import org.jclouds.aws.s3.domain.AccessControlList.Grant;
import org.jclouds.aws.s3.domain.AccessControlList.GroupGrantee;
import org.jclouds.aws.s3.reference.S3Constants;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.EntityBinder;
import org.jclouds.util.Utils;
import com.jamesmurty.utils.XMLBuilder;
public class AccessControlListBinder implements EntityBinder {
public void addEntityToRequest(Object entity, HttpRequest request) {
AccessControlList from = (AccessControlList) entity;
Properties outputProperties = new Properties();
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
try {
String stringEntity = generateBuilder(from).asString(outputProperties);
request.getHeaders().put(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_XML);
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, stringEntity.getBytes().length + "");
request.setEntity(stringEntity);
} catch (Exception e) {
Utils.rethrowIfRuntime(e);
throw new RuntimeException("error transforming acl: " + from, e);
}
}
protected XMLBuilder generateBuilder(AccessControlList acl) throws ParserConfigurationException,
FactoryConfigurationError {
XMLBuilder ownerBuilder = XMLBuilder.create("AccessControlPolicy").attr("xmlns",
S3Constants.S3_REST_API_XML_NAMESPACE).elem("Owner");
if (acl.getOwner() != null) {
ownerBuilder.elem("ID").text(acl.getOwner().getId()).up();
if (acl.getOwner().getDisplayName() != null) {
ownerBuilder.elem("DisplayName").text(acl.getOwner().getDisplayName()).up();
}
}
XMLBuilder grantsBuilder = ownerBuilder.root().elem("AccessControlList");
for (Grant grant : acl.getGrants()) {
XMLBuilder grantBuilder = grantsBuilder.elem("Grant");
XMLBuilder granteeBuilder = grantBuilder.elem("Grantee").attr("xmlns:xsi",
"http://www.w3.org/2001/XMLSchema-instance");
if (grant.getGrantee() instanceof GroupGrantee) {
granteeBuilder.attr("xsi:type", "Group").elem("URI").text(
grant.getGrantee().getIdentifier());
} else if (grant.getGrantee() instanceof CanonicalUserGrantee) {
CanonicalUserGrantee grantee = (CanonicalUserGrantee) grant.getGrantee();
granteeBuilder.attr("xsi:type", "CanonicalUser").elem("ID").text(
grantee.getIdentifier()).up();
if (grantee.getDisplayName() != null) {
granteeBuilder.elem("DisplayName").text(grantee.getDisplayName());
}
} else if (grant.getGrantee() instanceof EmailAddressGrantee) {
granteeBuilder.attr("xsi:type", "AmazonCustomerByEmail").elem("EmailAddress").text(
grant.getGrantee().getIdentifier());
}
grantBuilder.elem("Permission").text(grant.getPermission().toString());
}
return grantsBuilder;
}
}

View File

@ -0,0 +1,72 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.binders;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpUtils;
import org.jclouds.rest.EntityBinder;
public class S3ObjectBinder implements EntityBinder {
public void addEntityToRequest(Object entity, HttpRequest request) {
S3Object object = (S3Object) entity;
checkArgument(object.getMetadata().getSize() >= 0, "size must be set");
request.setEntity(checkNotNull(object.getData(), "object.getContent()"));
request.getHeaders()
.put(
HttpHeaders.CONTENT_TYPE,
checkNotNull(object.getMetadata().getContentType(),
"object.metadata.contentType()"));
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, object.getMetadata().getSize() + "");
if (object.getMetadata().getCacheControl() != null) {
request.getHeaders()
.put(HttpHeaders.CACHE_CONTROL, object.getMetadata().getCacheControl());
}
if (object.getMetadata().getContentDisposition() != null) {
request.getHeaders().put("Content-Disposition",
object.getMetadata().getContentDisposition());
}
if (object.getMetadata().getContentEncoding() != null) {
request.getHeaders().put(HttpHeaders.CONTENT_ENCODING,
object.getMetadata().getContentEncoding());
}
if (object.getMetadata().getETag() != null)
request.getHeaders().put(HttpHeaders.ETAG,
HttpUtils.toBase64String(object.getMetadata().getETag()));
request.getHeaders().putAll(object.getMetadata().getUserMetadata());
}
}

View File

@ -1,83 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.commands;
import static org.jclouds.aws.s3.commands.options.ListBucketOptions.Builder.maxResults;
import java.net.URI;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.http.HttpMethod;
import org.jclouds.http.HttpResponseException;
import org.jclouds.http.commands.callables.ReturnTrueIf2xx;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/**
* Issues a HEAD command to determine if the bucket exists or not.
*
* @author Adrian Cole
*
*/
public class BucketExists extends S3FutureCommand<Boolean> {
@Inject
public BucketExists(URI endPoint, ReturnTrueIf2xx callable, @Assisted String s3Bucket) {
super(endPoint, HttpMethod.HEAD, "/" + maxResults(0).buildQueryString(), callable, s3Bucket);
}
@Override
public Boolean get() throws InterruptedException, ExecutionException {
try {
return super.get();
} catch (ExecutionException e) {
return attemptNotFound(e);
}
}
@VisibleForTesting
Boolean attemptNotFound(ExecutionException e) throws ExecutionException {
if (e.getCause() != null && e.getCause() instanceof HttpResponseException) {
HttpResponseException responseException = (HttpResponseException) e.getCause();
if (responseException.getResponse().getStatusCode() == 404) {
return false;
}
}
throw e;
}
@Override
public Boolean get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException,
TimeoutException {
try {
return super.get(l, timeUnit);
} catch (ExecutionException e) {
return attemptNotFound(e);
}
}
}

View File

@ -1,78 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.commands;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.util.Utils.urlEncode;
import java.net.URI;
import org.jclouds.aws.s3.commands.options.CopyObjectOptions;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.xml.CopyObjectHandler;
import org.jclouds.http.HttpMethod;
import org.jclouds.http.commands.callables.xml.ParseSax;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/**
* The copy operation creates a copy of an object that is already storedin Amazon S3.
* <p/>
* When copying an object, you can preserve all metadata (default) or
* {@link CopyObjectOptions#overrideMetadataWith(com.google.common.collect.Multimap) specify new
* metadata}. However, the ACL is not preserved and is set to private for the user making the
* request. To override the default ACL setting,
* {@link CopyObjectOptions#overrideAcl(org.jclouds.aws.s3.domain.acl.CannedAccessPolicy) specify a
* new ACL} when generating a copy request.
*
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTObjectCOPY.html"
* />
* @see CopyObjectOptions
* @see org.jclouds.aws.s3.domain.acl.CannedAccessPolicy
* @author Adrian Cole
*
*/
public class CopyObject extends S3FutureCommand<S3Object.Metadata> {
@Inject
public CopyObject(URI endPoint, ParseSax<S3Object.Metadata> callable,
@Assisted("sourceBucket") String sourceBucket,
@Assisted("sourceObject") String sourceObject,
@Assisted("destinationBucket") String destinationBucket,
@Assisted("destinationObject") String destinationObject,
@Assisted CopyObjectOptions options) {
super(endPoint, HttpMethod.PUT, "/"
+ urlEncode(checkNotNull(destinationObject, "destinationObject")), callable,
destinationBucket);
CopyObjectHandler handler = (CopyObjectHandler) callable.getHandler();
handler.setKey(destinationObject);
getRequest().getHeaders().put(
"x-amz-copy-source",
String.format("/%1$s/%2$s", checkNotNull(sourceBucket, "sourceBucket"),
urlEncode(checkNotNull(sourceObject, "sourceObject"))));
getRequest().getHeaders().putAll(options.buildRequestHeaders());
}
}

View File

@ -1,89 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.commands;
import java.net.URI;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.http.HttpMethod;
import org.jclouds.http.commands.callables.ReturnTrueIf2xx;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/**
* The DELETE request operation deletes the bucket named in the URI. All objects in the bucket must
* be deleted before the bucket itself can be deleted.
* <p />
* Only the owner of a bucket can delete it, regardless of the bucket's access control policy.
*
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketDELETE.html"
* />
* @author Adrian Cole
*/
public class DeleteBucket extends S3FutureCommand<Boolean> {
@Inject
public DeleteBucket(URI endPoint, ReturnTrueIf2xx callable, @Assisted String s3Bucket) {
super(endPoint, HttpMethod.DELETE, "/", callable, s3Bucket);
}
@Override
public Boolean get() throws InterruptedException, ExecutionException {
try {
return super.get();
} catch (ExecutionException e) {
return attemptNotFound(e);
}
}
@VisibleForTesting
Boolean attemptNotFound(ExecutionException e) throws ExecutionException {
if (e.getCause() != null && e.getCause() instanceof AWSResponseException) {
AWSResponseException responseException = (AWSResponseException) e.getCause();
if (responseException.getResponse().getStatusCode() == 404) {
return true;
} else if ("BucketNotEmpty".equals(responseException.getError().getCode())
|| responseException.getResponse().getStatusCode() == 409) {
return false;
}
}
throw e;
}
@Override
public Boolean get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException,
TimeoutException {
try {
return super.get(l, timeUnit);
} catch (ExecutionException e) {
return attemptNotFound(e);
}
}
}

View File

@ -1,97 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.commands;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.util.Utils.urlEncode;
import java.net.URI;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.http.HttpMethod;
import org.jclouds.http.commands.callables.xml.ParseSax;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/**
* A GET request operation directed at an object or bucket URI with the "acl" parameter retrieves
* the Access Control List (ACL) settings for that S3 item.
* <p />
* To list a bucket or object's ACL, you must have READ_ACP access to the item.
*
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html"/>
* @author James Murty
*/
public class GetAccessControlList extends S3FutureCommand<AccessControlList> {
@Inject
public GetAccessControlList(URI endPoint, ParseSax<AccessControlList> accessControlListParser,
@Assisted("bucketName") String bucket) {
super(endPoint, HttpMethod.GET, "/?acl", accessControlListParser, bucket);
}
@Inject
public GetAccessControlList(URI endPoint, ParseSax<AccessControlList> accessControlListParser,
@Assisted("bucketName") String bucket, @Assisted("objectKey") String objectKey) {
super(endPoint, HttpMethod.GET, "/" + urlEncode(checkNotNull(objectKey)) + "?acl",
accessControlListParser, bucket);
}
@Override
public AccessControlList get() throws InterruptedException, ExecutionException {
try {
return super.get();
} catch (ExecutionException e) {
return attemptNotFound(e);
}
}
@VisibleForTesting
AccessControlList attemptNotFound(ExecutionException e) throws ExecutionException {
if (e.getCause() != null && e.getCause() instanceof AWSResponseException) {
AWSResponseException responseException = (AWSResponseException) e.getCause();
if ("NoSuchBucket".equals(responseException.getError().getCode())
|| "NoSuchObject".equals(responseException.getError().getCode())) {
return AccessControlList.NOT_FOUND;
}
}
throw e;
}
@Override
public AccessControlList get(long l, TimeUnit timeUnit) throws InterruptedException,
ExecutionException, TimeoutException {
try {
return super.get(l, timeUnit);
} catch (ExecutionException e) {
return attemptNotFound(e);
}
}
}

View File

@ -1,107 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.commands;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.util.Utils.urlEncode;
import java.net.URI;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.aws.s3.commands.callables.ParseObjectFromHeadersAndHttpContent;
import org.jclouds.aws.s3.commands.options.GetObjectOptions;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.http.HttpMethod;
import org.jclouds.http.HttpResponseException;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/**
* Retrieves the S3Object associated with the Key or {@link S3Object#NOT_FOUND} if not available;
*
* <p/>
* To use GET, you must have READ access to the object. If READ access is granted to the anonymous
* user, you can request the object without an authorization header.
* <p />
* <p/>
* This command allows you to specify {@link GetObjectOptions} to control delivery of content.
*
* <h2>Note</h2> If you specify any of the below options, you will receive partial content:
* <ul>
* <li>{@link GetObjectOptions#range}</li>
* <li>{@link GetObjectOptions#startAt}</li>
* <li>{@link GetObjectOptions#tail}</li>
* </ul>
*
* @see GetObjectOptions
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTObjectGET.html"
* />
* @author Adrian Cole
*/
public class GetObject extends S3FutureCommand<S3Object> {
@Inject
public GetObject(URI endPoint, ParseObjectFromHeadersAndHttpContent callable,
@Assisted("bucketName") String s3Bucket, @Assisted("key") String key,
@Assisted GetObjectOptions options) {
super(endPoint, HttpMethod.GET, "/" + urlEncode(checkNotNull(key)), callable, s3Bucket);
this.getRequest().getHeaders().putAll(options.buildRequestHeaders());
callable.setKey(key);
}
@Override
public S3Object get() throws InterruptedException, ExecutionException {
try {
return super.get();
} catch (ExecutionException e) {
return attemptNotFound(e);
}
}
@VisibleForTesting
S3Object attemptNotFound(ExecutionException e) throws ExecutionException {
if (e.getCause() != null && e.getCause() instanceof HttpResponseException) {
HttpResponseException responseException = (HttpResponseException) e.getCause();
if (responseException.getResponse().getStatusCode() == 404) {
return S3Object.NOT_FOUND;
}
}
throw e;
}
@Override
public S3Object get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException,
TimeoutException {
try {
return super.get(l, timeUnit);
} catch (ExecutionException e) {
return attemptNotFound(e);
}
}
}

View File

@ -1,97 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.commands;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.util.Utils.urlEncode;
import java.net.URI;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.aws.s3.commands.callables.ParseMetadataFromHeaders;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.http.HttpMethod;
import org.jclouds.http.HttpResponseException;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/**
* Retrieves the metadata associated with the Key or
* {@link org.jclouds.aws.s3.domain.S3Object.Metadata#NOT_FOUND} if not available.
*
* <p/>
* The HEAD operation is used to retrieve information about a specific object or object size,
* without actually fetching the object itself. This is useful if you're only interested in the
* object metadata, and don't want to waste bandwidth on the object data.
*
* @see GetObject
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTObjectHEAD.html"
* />
* @author Adrian Cole
*
*/
public class HeadObject extends S3FutureCommand<S3Object.Metadata> {
@Inject
public HeadObject(URI endPoint, ParseMetadataFromHeaders callable,
@Assisted("bucketName") String bucket, @Assisted("key") String key) {
super(endPoint, HttpMethod.HEAD, "/" + urlEncode(checkNotNull(key)), callable, bucket);
callable.setKey(key);
}
@Override
public S3Object.Metadata get() throws InterruptedException, ExecutionException {
try {
return super.get();
} catch (ExecutionException e) {
return attemptNotFound(e);
}
}
@VisibleForTesting
S3Object.Metadata attemptNotFound(ExecutionException e) throws ExecutionException {
if (e.getCause() != null && e.getCause() instanceof HttpResponseException) {
HttpResponseException responseException = (HttpResponseException) e.getCause();
if (responseException.getResponse().getStatusCode() == 404) {
return S3Object.Metadata.NOT_FOUND;
}
}
throw e;
}
@Override
public S3Object.Metadata get(long l, TimeUnit timeUnit) throws InterruptedException,
ExecutionException, TimeoutException {
try {
return super.get(l, timeUnit);
} catch (ExecutionException e) {
return attemptNotFound(e);
}
}
}

View File

@ -1,101 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.commands;
import java.net.URI;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.aws.s3.commands.options.ListBucketOptions;
import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.aws.s3.xml.ListBucketHandler;
import org.jclouds.http.HttpMethod;
import org.jclouds.http.HttpResponseException;
import org.jclouds.http.commands.callables.xml.ParseSax;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/**
* A GET request operation using a bucket URI lists information about the objects in the bucket.
* <p />
* To list the keys of a bucket, you must have READ access to the bucket.
* <p/>
* List output is controllable via {@link ListBucketOptions}
*
* @see ListBucketOptions
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketGET.html"
* />
* @author Adrian Cole
*
*/
public class ListBucket extends S3FutureCommand<S3Bucket> {
@Inject
public ListBucket(URI endPoint, ParseSax<S3Bucket> bucketParser, @Assisted String bucket,
@Assisted ListBucketOptions options) {
super(endPoint, HttpMethod.GET, "/" + options.buildQueryString(), bucketParser, bucket);
ListBucketHandler handler = (ListBucketHandler) bucketParser.getHandler();
handler.setBucketName(bucket);
}
@Override
public S3Bucket get() throws InterruptedException, ExecutionException {
try {
return super.get();
} catch (ExecutionException e) {
return attemptNotFound(e);
}
}
/**
* {@code bucketParser} is only enacted when the http status code is 2xx. Amazon treats
* NoSuchBucket as an exception, while we regard this as a valid response. Accordingly, we check
* for this {@code NoSuchBucket} message and return {@code S3Bucket#NOT_FOUND} if present.
*
*/
@VisibleForTesting
S3Bucket attemptNotFound(ExecutionException e) throws ExecutionException {
if (e.getCause() != null && e.getCause() instanceof HttpResponseException) {
HttpResponseException responseException = (HttpResponseException) e.getCause();
if (responseException.getResponse().getStatusCode() == 404) {
return S3Bucket.NOT_FOUND;
}
}
throw e;
}
@Override
public S3Bucket get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException,
TimeoutException {
try {
return super.get(l, timeUnit);
} catch (ExecutionException e) {
return attemptNotFound(e);
}
}
}

View File

@ -1,101 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.commands;
import java.net.URI;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.s3.commands.options.PutBucketOptions;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.http.HttpHeaders;
import org.jclouds.http.HttpMethod;
import org.jclouds.http.commands.callables.ReturnTrueIf2xx;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/**
* Create and name your own bucket in which to store your objects.
* <p/>
* The PUT request operation with a bucket URI creates a new bucket. Depending on your latency and
* legal requirements, you can specify a location constraint that will affect where your data
* physically resides. You can currently specify a Europe (EU) location constraint via
* {@link PutBucketOptions}.
*
* @see PutBucketOptions
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketPUT.html"
* />
* @author Adrian Cole
*
*/
public class PutBucket extends S3FutureCommand<Boolean> {
@Inject
public PutBucket(URI endPoint, ReturnTrueIf2xx callable, @Assisted String bucketName,
@Assisted PutBucketOptions options) {
super(endPoint, HttpMethod.PUT, "/", callable, S3Utils.validateBucketName(bucketName));
getRequest().getHeaders().putAll(options.buildRequestHeaders());
String payload = options.buildPayload();
if (payload != null) {
getRequest().setPayload(payload);
getRequest().getHeaders().put(HttpHeaders.CONTENT_LENGTH, payload.getBytes().length + "");
}
}
@Override
public Boolean get() throws InterruptedException, ExecutionException {
try {
return super.get();
} catch (ExecutionException e) {
return eventualConsistencyAlreadyOwnedIsOk(e);
}
}
@VisibleForTesting
static Boolean eventualConsistencyAlreadyOwnedIsOk(ExecutionException e)
throws ExecutionException {
if (e.getCause() != null && e.getCause() instanceof AWSResponseException) {
AWSResponseException responseException = (AWSResponseException) e.getCause();
if ("BucketAlreadyOwnedByYou".equals(responseException.getError().getCode())) {
return true;
}
}
throw e;
}
@Override
public Boolean get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException,
TimeoutException {
try {
return super.get(l, timeUnit);
} catch (ExecutionException e) {
return eventualConsistencyAlreadyOwnedIsOk(e);
}
}
}

View File

@ -1,69 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.commands;
import java.net.URI;
import javax.annotation.Resource;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.xml.AccessControlListBuilder;
import org.jclouds.http.HttpHeaders;
import org.jclouds.http.HttpMethod;
import org.jclouds.http.commands.callables.ReturnTrueIf2xx;
import org.jclouds.logging.Logger;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/**
* A PUT request operation directed at a bucket URI with the "acl" parameter sets the Access Control
* List (ACL) settings for that S3 item.
* <p />
* To set a bucket or object's ACL, you must have WRITE_ACP or FULL_CONTROL access to the item.
*
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html"/>
* @author James Murty
*/
public class PutBucketAccessControlList extends S3FutureCommand<Boolean> {
@Resource
protected Logger logger = Logger.NULL;
@Inject
public PutBucketAccessControlList(URI endPoint, ReturnTrueIf2xx callable,
@Assisted("bucketName") String bucket, @Assisted AccessControlList acl) {
super(endPoint, HttpMethod.PUT, "/?acl", callable, bucket);
String aclPayload = "";
try {
aclPayload = (new AccessControlListBuilder(acl)).getXmlString();
} catch (Exception e) {
// TODO: How do we handle this sanely?
logger.error(e, "Unable to build XML document for Access Control List: " + acl);
}
getRequest().setPayload(aclPayload);
getRequest().getHeaders().put(HttpHeaders.CONTENT_LENGTH, aclPayload.getBytes().length + "");
}
}

View File

@ -1,99 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.commands;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.util.Utils.urlEncode;
import java.net.URI;
import org.jclouds.aws.s3.commands.callables.ParseMd5FromETagHeader;
import org.jclouds.aws.s3.commands.options.PutObjectOptions;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.http.HttpHeaders;
import org.jclouds.http.HttpMethod;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/**
* Store data by creating or overwriting an object.
*
* <p/>
* This returns a byte[] of the md5 hash of what Amazon S3 received
* <p />
* <p/>
* This command allows you to specify {@link PutObjectOptions} to control delivery of content.
*
*
* @see PutObjectOptions
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTObjectPUT.html"
* />
* @author Adrian Cole
*/
public class PutObject extends S3FutureCommand<byte[]> {
@Inject
public PutObject(URI endPoint, ParseMd5FromETagHeader callable, @Assisted String s3Bucket,
@Assisted S3Object object, @Assisted PutObjectOptions options) {
super(endPoint, HttpMethod.PUT, "/" + urlEncode(checkNotNull(object.getKey())), callable,
s3Bucket);
checkArgument(object.getMetadata().getSize() >= 0, "size must be set");
getRequest().setPayload(checkNotNull(object.getData(), "object.getContent()"));
getRequest().getHeaders()
.put(
HttpHeaders.CONTENT_TYPE,
checkNotNull(object.getMetadata().getContentType(),
"object.metadata.contentType()"));
getRequest().getHeaders()
.put(HttpHeaders.CONTENT_LENGTH, object.getMetadata().getSize() + "");
if (object.getMetadata().getCacheControl() != null) {
getRequest().getHeaders().put(HttpHeaders.CACHE_CONTROL,
object.getMetadata().getCacheControl());
}
if (object.getMetadata().getContentDisposition() != null) {
getRequest().getHeaders().put(HttpHeaders.CONTENT_DISPOSITION,
object.getMetadata().getContentDisposition());
}
if (object.getMetadata().getContentEncoding() != null) {
getRequest().getHeaders().put(HttpHeaders.CONTENT_ENCODING,
object.getMetadata().getContentEncoding());
}
if (object.getMetadata().getMd5() != null)
getRequest().getHeaders().put(HttpHeaders.CONTENT_MD5,
S3Utils.toBase64String(object.getMetadata().getMd5()));
getRequest().getHeaders().putAll(object.getMetadata().getUserMetadata());
getRequest().getHeaders().putAll(options.buildRequestHeaders());
}
}

View File

@ -1,73 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.commands;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.util.Utils.urlEncode;
import java.net.URI;
import javax.annotation.Resource;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.xml.AccessControlListBuilder;
import org.jclouds.http.HttpHeaders;
import org.jclouds.http.HttpMethod;
import org.jclouds.http.commands.callables.ReturnTrueIf2xx;
import org.jclouds.logging.Logger;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/**
* A PUT request operation directed at an object URI with the "acl" parameter sets the Access
* Control List (ACL) settings for that S3 item.
* <p />
* To set a bucket or object's ACL, you must have WRITE_ACP or FULL_CONTROL access to the item.
*
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html"/>
* @author James Murty
*/
public class PutObjectAccessControlList extends S3FutureCommand<Boolean> {
@Resource
protected Logger logger = Logger.NULL;
@Inject
public PutObjectAccessControlList(URI endPoint, ReturnTrueIf2xx callable,
@Assisted("bucketName") String bucket, @Assisted("key") String objectKey,
@Assisted AccessControlList acl) {
super(endPoint, HttpMethod.PUT, "/" + urlEncode(checkNotNull(objectKey)) + "?acl", callable, bucket);
String aclPayload = "";
try {
aclPayload = (new AccessControlListBuilder(acl)).getXmlString();
} catch (Exception e) {
// TODO: How do we handle this sanely?
logger.error(e, "Unable to build XML document for Access Control List: " + acl);
}
getRequest().setPayload(aclPayload);
getRequest().getHeaders().put(HttpHeaders.CONTENT_LENGTH, aclPayload.getBytes().length + "");
}
}

View File

@ -1,178 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.commands;
import java.net.URI;
import org.jclouds.aws.s3.commands.options.CopyObjectOptions;
import org.jclouds.aws.s3.commands.options.GetObjectOptions;
import org.jclouds.aws.s3.commands.options.ListBucketOptions;
import org.jclouds.aws.s3.commands.options.PutBucketOptions;
import org.jclouds.aws.s3.commands.options.PutObjectOptions;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.xml.S3ParserFactory;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/**
* Assembles the command objects for S3.
*
* @author Adrian Cole
*/
public class S3CommandFactory {
@Inject
private S3ParserFactory parserFactory;
@Inject
private DeleteBucketFactory deleteBucketFactory;
public static interface DeleteBucketFactory {
DeleteBucket create(String bucket);
}
public DeleteBucket createDeleteBucket(String bucket) {
return deleteBucketFactory.create(bucket);
}
@Inject
private DeleteObjectFactory deleteObjectFactory;
public static interface DeleteObjectFactory {
DeleteObject create(@Assisted("bucketName") String bucket, @Assisted("key") String key);
}
public DeleteObject createDeleteObject(String bucket, String key) {
return deleteObjectFactory.create(bucket, key);
}
@Inject
private BucketExistsFactory headBucketFactory;
public static interface BucketExistsFactory {
BucketExists create(String bucket);
}
public BucketExists createHeadBucket(String bucket) {
return headBucketFactory.create(bucket);
}
@Inject
private PutBucketFactory putBucketFactoryOptions;
public static interface PutBucketFactory {
PutBucket create(String bucket, PutBucketOptions options);
}
public PutBucket createPutBucket(String bucket, PutBucketOptions options) {
return putBucketFactoryOptions.create(bucket, options);
}
@Inject
private PutObjectFactory putObjectFactory;
public static interface PutObjectFactory {
PutObject create(String bucket, S3Object object, PutObjectOptions options);
}
public PutObject createPutObject(String bucket, S3Object s3Object, PutObjectOptions options) {
return putObjectFactory.create(bucket, s3Object, options);
}
@Inject
private GetObjectFactory getObjectFactory;
public static interface GetObjectFactory {
GetObject create(@Assisted("bucketName") String bucket, @Assisted("key") String key,
GetObjectOptions options);
}
public GetObject createGetObject(String bucket, String key, GetObjectOptions options) {
return getObjectFactory.create(bucket, key, options);
}
@Inject
private HeadMetadataFactory headMetadataFactory;
public static interface HeadMetadataFactory {
HeadObject create(@Assisted("bucketName") String bucket, @Assisted("key") String key);
}
public HeadObject createHeadMetadata(String bucket, String key) {
return headMetadataFactory.create(bucket, key);
}
@Inject
URI endPoint;
public ListOwnedBuckets createGetMetadataForOwnedBuckets() {
return new ListOwnedBuckets(endPoint, parserFactory.createListBucketsParser());
}
public ListBucket createListBucket(String bucket, ListBucketOptions options) {
return new ListBucket(endPoint, parserFactory.createListBucketParser(), bucket, options);
}
public CopyObject createCopyObject(String sourceBucket, String sourceObject,
String destinationBucket, String destinationObject, CopyObjectOptions options) {
return new CopyObject(endPoint, parserFactory.createCopyObjectParser(), sourceBucket,
sourceObject, destinationBucket, destinationObject, options);
}
public GetAccessControlList createGetBucketACL(String bucket) {
return new GetAccessControlList(endPoint, parserFactory.createAccessControlListParser(),
bucket);
}
public GetAccessControlList createGetObjectACL(String bucket, String objectKey) {
return new GetAccessControlList(endPoint, parserFactory.createAccessControlListParser(),
bucket, objectKey);
}
@Inject
private PutBucketAccessControlListFactory putBucketAccessControlListFactory;
public static interface PutBucketAccessControlListFactory {
PutBucketAccessControlList create(@Assisted("bucketName") String bucket, AccessControlList acl);
}
public PutBucketAccessControlList createPutBucketACL(String bucket, AccessControlList acl) {
return putBucketAccessControlListFactory.create(bucket, acl);
}
@Inject
private PutObjectAccessControlListFactory putObjectAccessControlListFactory;
public static interface PutObjectAccessControlListFactory {
PutObjectAccessControlList create(@Assisted("bucketName") String bucket,
@Assisted("key") String objectKey, AccessControlList acl);
}
public PutObjectAccessControlList createPutObjectACL(String bucket, String objectKey,
AccessControlList acl) {
return putObjectAccessControlListFactory.create(bucket, objectKey, acl);
}
}

View File

@ -1,95 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.commands.callables;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpFutureCommand;
import org.jclouds.http.HttpHeaders;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
/**
* Parses response headers and creates a new S3Object from them and the HTTP
* content.
*
* @see ParseMetadataFromHeaders
* @author Adrian Cole
*/
public class ParseObjectFromHeadersAndHttpContent extends
HttpFutureCommand.ResponseCallable<S3Object> {
private final ParseMetadataFromHeaders metadataParser;
@Inject
public ParseObjectFromHeadersAndHttpContent(
ParseMetadataFromHeaders metadataParser) {
this.metadataParser = metadataParser;
}
/**
* First, calls {@link ParseMetadataFromHeaders}.
*
* Then, sets the object size based on the Content-Length header and adds
* the content to the {@link S3Object} result.
*
* @throws org.jclouds.http.HttpException
*/
public S3Object call() throws HttpException {
checkCode();
metadataParser.setResponse(getResponse());
S3Object.Metadata metadata = metadataParser.call();
S3Object object = new S3Object(metadata, getResponse().getContent());
parseContentLengthOrThrowException(object);
return object;
}
@VisibleForTesting
void parseContentLengthOrThrowException(S3Object object)
throws HttpException {
String contentLength = getResponse().getFirstHeaderOrNull(
HttpHeaders.CONTENT_LENGTH);
String contentRange = getResponse().getFirstHeaderOrNull(
HttpHeaders.CONTENT_RANGE);
if (contentLength == null)
throw new HttpException(HttpHeaders.CONTENT_LENGTH
+ " header not present in headers: "
+ getResponse().getHeaders());
object.setContentLength(Long.parseLong(contentLength));
if (contentRange == null) {
object.getMetadata().setSize(object.getContentLength());
} else {
object.setContentRange(contentRange);
object.getMetadata().setSize(
Long.parseLong(contentRange.substring(contentRange
.lastIndexOf('/') + 1)));
}
}
public void setKey(String key) {
this.metadataParser.setKey(key);
}
}

View File

@ -1,89 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.commands.config;
import org.jclouds.aws.s3.commands.BucketExists;
import org.jclouds.aws.s3.commands.DeleteBucket;
import org.jclouds.aws.s3.commands.DeleteObject;
import org.jclouds.aws.s3.commands.GetObject;
import org.jclouds.aws.s3.commands.HeadObject;
import org.jclouds.aws.s3.commands.PutBucketAccessControlList;
import org.jclouds.aws.s3.commands.PutBucket;
import org.jclouds.aws.s3.commands.PutObject;
import org.jclouds.aws.s3.commands.PutObjectAccessControlList;
import org.jclouds.aws.s3.commands.S3CommandFactory;
import com.google.inject.AbstractModule;
import com.google.inject.assistedinject.FactoryProvider;
/**
* Creates the factories needed to produce S3 commands
*
* @author Adrian Cole
*/
public class S3CommandsModule extends AbstractModule {
@Override
protected void configure() {
bind(S3CommandFactory.DeleteBucketFactory.class).toProvider(
FactoryProvider.newFactory(S3CommandFactory.DeleteBucketFactory.class,
DeleteBucket.class));
bind(S3CommandFactory.DeleteObjectFactory.class).toProvider(
FactoryProvider.newFactory(S3CommandFactory.DeleteObjectFactory.class,
DeleteObject.class));
bind(S3CommandFactory.BucketExistsFactory.class).toProvider(
FactoryProvider.newFactory(S3CommandFactory.BucketExistsFactory.class,
BucketExists.class));
bind(S3CommandFactory.PutBucketFactory.class)
.toProvider(
FactoryProvider.newFactory(S3CommandFactory.PutBucketFactory.class,
PutBucket.class));
bind(S3CommandFactory.PutObjectFactory.class)
.toProvider(
FactoryProvider.newFactory(S3CommandFactory.PutObjectFactory.class,
PutObject.class));
bind(S3CommandFactory.GetObjectFactory.class)
.toProvider(
FactoryProvider.newFactory(S3CommandFactory.GetObjectFactory.class,
GetObject.class));
bind(S3CommandFactory.HeadMetadataFactory.class).toProvider(
FactoryProvider.newFactory(S3CommandFactory.HeadMetadataFactory.class,
HeadObject.class));
bind(S3CommandFactory.PutBucketAccessControlListFactory.class).toProvider(
FactoryProvider.newFactory(S3CommandFactory.PutBucketAccessControlListFactory.class,
PutBucketAccessControlList.class));
bind(S3CommandFactory.PutObjectAccessControlListFactory.class).toProvider(
FactoryProvider.newFactory(S3CommandFactory.PutObjectAccessControlListFactory.class,
PutObjectAccessControlList.class));
}
}

View File

@ -1,28 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.
* ====================================================================
*/
/**
* This package contains modules who manage the dependencies of S3 command objects.
* @author Adrian Cole
*/
package org.jclouds.aws.s3.commands.config;

View File

@ -1,29 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.
* ====================================================================
*/
/**
* This package contains all currently supported commands in the Amazon S3 REST Api.
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/latest/RESTAPI.html" />
* @author Adrian Cole
*/
package org.jclouds.aws.s3.commands;

View File

@ -35,7 +35,6 @@ import org.jclouds.aws.s3.filters.RequestAuthorizeSignature;
import org.jclouds.aws.s3.handlers.AWSClientErrorRetryHandler;
import org.jclouds.aws.s3.handlers.AWSRedirectionRetryHandler;
import org.jclouds.aws.s3.handlers.ParseAWSErrorFromXmlContent;
import org.jclouds.aws.s3.internal.LiveS3Connection;
import org.jclouds.cloud.ConfiguresCloudConnection;
import org.jclouds.http.HttpConstants;
import org.jclouds.http.HttpErrorHandler;
@ -46,11 +45,12 @@ import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.logging.Logger;
import org.jclouds.rest.RestClientFactory;
import org.jclouds.rest.config.JaxrsModule;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
@ -61,7 +61,7 @@ import com.google.inject.name.Named;
*/
@ConfiguresCloudConnection
@RequiresHttp
public class LiveS3ConnectionModule extends AbstractModule {
public class RestS3ConnectionModule extends AbstractModule {
@Resource
protected Logger logger = Logger.NULL;
@ -77,12 +77,17 @@ public class LiveS3ConnectionModule extends AbstractModule {
@Override
protected void configure() {
bind(S3Connection.class).to(LiveS3Connection.class).in(Scopes.SINGLETON);
install(new JaxrsModule());
bindErrorHandlers();
bindRetryHandlers();
requestInjection(this);
logger.info("S3 Context = %1$s://%2$s:%3$s", (isSecure ? "https" : "http"), address, port);
logger.info("S3 Context = %s://%s:%s", (isSecure ? "https" : "http"), address, port);
}
@Provides
@Singleton
protected S3Connection provideS3Connection(RestClientFactory factory) {
return factory.create(S3Connection.class);
}
protected void bindErrorHandlers() {

View File

@ -25,7 +25,6 @@ package org.jclouds.aws.s3.config;
import org.jclouds.aws.s3.S3Connection;
import org.jclouds.aws.s3.S3Context;
import org.jclouds.aws.s3.commands.config.S3CommandsModule;
import org.jclouds.aws.s3.internal.GuiceS3Context;
import org.jclouds.aws.s3.internal.LiveS3InputStreamMap;
import org.jclouds.aws.s3.internal.LiveS3ObjectMap;
@ -43,7 +42,6 @@ public class S3ContextModule extends AbstractModule {
@Override
protected void configure() {
this.requireBinding(S3Connection.class);
install(new S3CommandsModule());
bind(GuiceS3Context.S3ObjectMapFactory.class).toProvider(
FactoryProvider.newFactory(GuiceS3Context.S3ObjectMapFactory.class,
LiveS3ObjectMap.class));

View File

@ -31,7 +31,6 @@ import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.jclouds.aws.s3.domain.acl.CannedAccessPolicy;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
@ -87,7 +86,6 @@ public class AccessControlList {
*
* @param grantee
* @param permission
* @return
*/
public AccessControlList addPermission(Grantee grantee, Permission permission) {
Grant grant = new Grant(grantee, permission);
@ -100,7 +98,6 @@ public class AccessControlList {
*
* @param groupGranteeURI
* @param permission
* @return
*/
public AccessControlList addPermission(GroupGranteeURI groupGranteeURI, Permission permission) {
return addPermission(new GroupGrantee(groupGranteeURI), permission);
@ -119,7 +116,6 @@ public class AccessControlList {
*
* @param grantee
* @param permission
* @return
*/
public AccessControlList revokePermission(Grantee grantee, Permission permission) {
Collection<Grant> grantsForGrantee = findGrantsForGrantee(grantee.getIdentifier());
@ -144,7 +140,6 @@ public class AccessControlList {
*
* @param groupGranteeURI
* @param permission
* @return
*/
public AccessControlList revokePermission(GroupGranteeURI groupGranteeURI, Permission permission) {
return revokePermission(new GroupGrantee(groupGranteeURI), permission);
@ -154,7 +149,6 @@ public class AccessControlList {
* Revoke all the permissions granted to the given grantee.
*
* @param grantee
* @return
*/
public AccessControlList revokeAllPermissions(Grantee grantee) {
Collection<Grant> grantsForGrantee = findGrantsForGrantee(grantee.getIdentifier());
@ -224,7 +218,6 @@ public class AccessControlList {
*
* @param granteeId
* identifier of a canonical user, email address user, or group.
* @return
*/
protected Collection<Grant> findGrantsForGrantee(final String granteeId) {
return Collections2.filter(grants, new Predicate<Grant>() {
@ -239,7 +232,6 @@ public class AccessControlList {
*
* @param cannedAP
* @param ownerId
* @return
*/
public static AccessControlList fromCannedAccessPolicy(CannedAccessPolicy cannedAP,
String ownerId) {

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.aws.s3.domain.acl;
package org.jclouds.aws.s3.domain;
/**
* Description from Amazon's documentation:

View File

@ -142,7 +142,7 @@ public class S3Bucket {
EU
}
private final String name;
private String name;
private DateTime creationDate;
private CanonicalUser canonicalUser;
@ -153,6 +153,10 @@ public class S3Bucket {
this.name = checkNotNull(name, "name");
}
public Metadata() {
super();
}
/**
* To comply with Amazon S3 requirements, bucket names must:
* <p/>
@ -164,6 +168,10 @@ public class S3Bucket {
* <p/>
* Not be in an IP address style (e.g., "192.168.5.4")
*/
public void setName(String name) {
this.name = checkNotNull(name, "name");
}
public String getName() {
return name;
}
@ -203,6 +211,10 @@ public class S3Bucket {
private boolean isTruncated;
public S3Bucket() {
this.metadata = new Metadata();
}
public S3Bucket(String name) {
this.metadata = new Metadata(name);
}
@ -215,6 +227,10 @@ public class S3Bucket {
this.metadata = checkNotNull(metadata, "metadata");
}
public void setName(String name) {
this.metadata.setName(name);
}
/**
* @see org.jclouds.aws.s3.S3Connection#listBucket(String)
*/
@ -262,7 +278,7 @@ public class S3Bucket {
* and prefix is set to <code>a/</code> and delimiter is set to <code>/</code> then
* commonprefixes would return 1,2
*
* @see org.jclouds.aws.s3.commands.options.ListBucketOptions#getPrefix()
* @see org.jclouds.aws.s3.options.ListBucketOptions#getPrefix()
*/
public SortedSet<String> getCommonPrefixes() {
return commonPrefixes;
@ -275,7 +291,7 @@ public class S3Bucket {
/**
* return keys that start with this.
*
* @see org.jclouds.aws.s3.commands.options.ListBucketOptions#getPrefix()
* @see org.jclouds.aws.s3.options.ListBucketOptions#getPrefix()
*/
public String getPrefix() {
return prefix;
@ -287,7 +303,7 @@ public class S3Bucket {
/**
* @return maximum results of the bucket.
* @see org.jclouds.aws.s3.commands.options.ListBucketOptions#getMaxKeys()
* @see org.jclouds.aws.s3.options.ListBucketOptions#getMaxKeys()
*/
public long getMaxKeys() {
return maxKeys;
@ -300,7 +316,7 @@ public class S3Bucket {
/**
* when set, bucket contains results whose keys are lexigraphically after marker.
*
* @see org.jclouds.aws.s3.commands.options.ListBucketOptions#getMarker()
* @see org.jclouds.aws.s3.options.ListBucketOptions#getMarker()
*/
public String getMarker() {
return marker;
@ -316,7 +332,7 @@ public class S3Bucket {
* note that delimiter has no effect on prefix. prefix can contain the delimiter many times, or
* not at all. delimiter only restricts after the prefix.
*
* @see org.jclouds.aws.s3.commands.options.ListBucketOptions#getMarker()
* @see org.jclouds.aws.s3.options.ListBucketOptions#getMarker()
*/
public String getDelimiter() {
return delimiter;

View File

@ -31,448 +31,432 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import org.jclouds.aws.s3.commands.options.GetObjectOptions;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.aws.s3.util.S3Utils.Md5InputStreamResult;
import org.jclouds.http.ContentTypes;
import javax.ws.rs.core.MediaType;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.HttpUtils.ETagInputStreamResult;
import org.joda.time.DateTime;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
/**
* Amazon S3 is designed to store objects. Objects are stored in
* {@link S3Bucket buckets} and consist of a {@link org.jclouds.aws.s3.domain.S3Object#getData() value},
* a {@link S3Object#getKey key}, {@link S3Object.Metadata#getUserMetadata()
* metadata}, and an access control policy.
*
* Amazon S3 is designed to store objects. Objects are stored in {@link S3Bucket buckets} and
* consist of a {@link org.jclouds.aws.s3.domain.S3Object#getData() value}, a
* {@link S3Object#getKey key}, {@link S3Object.Metadata#getUserMetadata() metadata}, and an access
* control policy.
*
* @author Adrian Cole
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?UsingObjects.html"
* />
*/
public class S3Object {
public static final S3Object NOT_FOUND = new S3Object(Metadata.NOT_FOUND);
public static final S3Object NOT_FOUND = new S3Object(Metadata.NOT_FOUND);
private Object data;
private Metadata metadata;
private long contentLength = -1;
private String contentRange;
private Object data;
private final Metadata metadata;
private long contentLength = -1;
private String contentRange;
public S3Object(String key) {
this(new Metadata(key));
}
public S3Object(String key) {
this(new Metadata(key));
}
public S3Object(Metadata metadata) {
this.metadata = metadata;
}
public S3Object(Metadata metadata) {
this.metadata = metadata;
}
public S3Object(Metadata metadata, Object data) {
this(metadata);
setData(data);
}
public S3Object(Metadata metadata, Object data) {
this(metadata);
setData(data);
}
public S3Object(String key, Object data) {
this(key);
setData(data);
}
public S3Object(String key, Object data) {
this(key);
setData(data);
}
/**
* System and user Metadata for the {@link S3Object}.
*
* @author Adrian Cole
* @see <a href=
* "http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingMetadata.html"
* />
*/
public static class Metadata implements Comparable<Metadata> {
public static final Metadata NOT_FOUND = new Metadata("NOT_FOUND");
/**
* System and user Metadata for the {@link S3Object}.
*
* @author Adrian Cole
* @see <a href= "http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingMetadata.html" />
*/
public static class Metadata implements Comparable<Metadata> {
public static final Metadata NOT_FOUND = new Metadata("NOT_FOUND");
// parsed during list, head, or get
private final String key;
private byte[] md5;
private volatile long size = -1;
// parsed during list, head, or get
private String key;
private byte[] eTag;
private volatile long size = -1;
// only parsed during head or get
private Multimap<String, String> allHeaders = HashMultimap.create();
private Multimap<String, String> userMetadata = HashMultimap.create();
private DateTime lastModified;
private String dataType = ContentTypes.BINARY;
private String cacheControl;
private String dataDisposition;
private String dataEncoding;
private AccessControlList accessControlList;
// only parsed during head or get
private Multimap<String, String> allHeaders = HashMultimap.create();
private Multimap<String, String> userMetadata = HashMultimap.create();
private DateTime lastModified;
private String dataType = MediaType.APPLICATION_OCTET_STREAM;
private String cacheControl;
private String dataDisposition;
private String dataEncoding;
private AccessControlList accessControlList;
// only parsed on list
private CanonicalUser owner = null;
private String storageClass = null;
// only parsed on list
private CanonicalUser owner = null;
private String storageClass = null;
/**
* @param key
* @see #getKey()
*/
public Metadata(String key) {
checkNotNull(key, "key");
checkArgument(!key.startsWith("/"), "keys cannot start with /");
this.key = key;
}
public Metadata() {
super();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("Metadata");
sb.append("{key='").append(key).append('\'');
sb.append(", lastModified=").append(lastModified);
sb.append(", md5=").append(
getMd5() == null ? "null" : Arrays.asList(getMd5())
.toString());
sb.append(", size=").append(size);
sb.append(", dataType='").append(dataType).append('\'');
sb.append('}');
return sb.toString();
}
/**
* @param key
* @see #getKey()
*/
public Metadata(String key) {
setKey(key);
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof Metadata))
return false;
public void setKey(String key) {
checkNotNull(key, "key");
checkArgument(!key.startsWith("/"), "keys cannot start with /");
this.key = key;
}
Metadata metadata = (Metadata) o;
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("Metadata");
sb.append("{key='").append(key).append('\'');
sb.append(", lastModified=").append(lastModified);
sb.append(", eTag=").append(
getETag() == null ? "null" : Arrays.asList(getETag()).toString());
sb.append(", size=").append(size);
sb.append(", dataType='").append(dataType).append('\'');
sb.append('}');
return sb.toString();
}
if (size != metadata.size)
return false;
if (dataType != null ? !dataType.equals(metadata.dataType)
: metadata.dataType != null)
return false;
if (!key.equals(metadata.key))
return false;
if (lastModified != null ? !lastModified
.equals(metadata.lastModified)
: metadata.lastModified != null)
return false;
if (!Arrays.equals(getMd5(), metadata.getMd5()))
return false;
@Override
public boolean equals(Object o) {
if (this == o)
return true;
}
@Override
public int hashCode() {
int result = key.hashCode();
result = 31 * result
+ (lastModified != null ? lastModified.hashCode() : 0);
result = 31 * result
+ (getMd5() != null ? Arrays.hashCode(getMd5()) : 0);
result = 31 * result + (int) (size ^ (size >>> 32));
result = 31 * result + (dataType != null ? dataType.hashCode() : 0);
return result;
}
/**
* The key is the handle that you assign to an object that allows you
* retrieve it later. A key is a sequence of Unicode characters whose
* UTF-8 encoding is at most 1024 bytes long. Each object in a bucket
* must have a unique key.
*
* @see <a href=
* "http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingKeys.html"
* />
*/
public String getKey() {
return key;
}
public DateTime getLastModified() {
return lastModified;
}
public void setLastModified(DateTime lastModified) {
this.lastModified = lastModified;
}
/**
* The size of the object, in bytes.
*
* @see <a href=
* "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html?sec14.13."
* />
*/
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
/**
* A standard MIME type describing the format of the contents. If none
* is provided, the default is binary/octet-stream.
* @see <a href=
* "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html?sec14.17."
* />
*/
public String getContentType() {
return dataType;
}
public void setContentType(String dataType) {
this.dataType = dataType;
}
public void setMd5(byte[] md5) {
this.md5 = new byte[md5.length];
System.arraycopy(md5, 0, this.md5, 0, md5.length);
}
/**
* @return the md5 value stored in the Etag header returned by S3.
*/
public byte[] getMd5() {
if (md5 != null) {
byte[] retval = new byte[md5.length];
System.arraycopy(this.md5, 0, retval, 0, md5.length);
return retval;
} else {
return null;
}
}
public void setUserMetadata(Multimap<String, String> userMetadata) {
this.userMetadata = userMetadata;
}
/**
* Any header starting with <code>x-amz-meta-</code> is considered user
* metadata. It will be stored with the object and returned when you
* retrieve the object. The total size of the HTTP request, not
* including the body, must be less than 8 KB.
*/
public Multimap<String, String> getUserMetadata() {
return userMetadata;
}
public void setOwner(CanonicalUser owner) {
this.owner = owner;
}
/**
* Every bucket and object in Amazon S3 has an owner, the user that
* created the bucket or object. The owner of a bucket or object cannot
* be changed. However, if the object is overwritten by another user
* (deleted and rewritten), the new object will have a new owner.
*/
public CanonicalUser getOwner() {
return owner;
}
public void setStorageClass(String storageClass) {
this.storageClass = storageClass;
}
/**
* Currently defaults to 'STANDARD' and not used.
*/
public String getStorageClass() {
return storageClass;
}
public void setCacheControl(String cacheControl) {
this.cacheControl = cacheControl;
}
/**
* Can be used to specify caching behavior along the request/reply
* chain.
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html?sec14.9.
*/
public String getCacheControl() {
return cacheControl;
}
public void setContentDisposition(String dataDisposition) {
this.dataDisposition = dataDisposition;
}
/**
* Specifies presentational information for the object.
*
* @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html?sec19.5.1."/>
*/
public String getContentDisposition() {
return dataDisposition;
}
public void setContentEncoding(String dataEncoding) {
this.dataEncoding = dataEncoding;
}
/**
* Specifies what content encodings have been applied to the object and
* thus what decoding mechanisms must be applied in order to obtain the
* media-type referenced by the Content-Type header field.
*
* @see <a href=
* "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html?sec14.11"
* />
*/
public String getContentEncoding() {
return dataEncoding;
}
public void setAllHeaders(Multimap<String, String> allHeaders) {
this.allHeaders = allHeaders;
}
public void setAccessControlList(AccessControlList acl) {
this.accessControlList = acl;
}
public AccessControlList getAccessControlList() {
return this.accessControlList;
}
/**
* @return all http response headers associated with this S3Object
*/
public Multimap<String, String> getAllHeaders() {
return allHeaders;
}
public int compareTo(Metadata o) {
return (this == o) ? 0 : getKey().compareTo(o.getKey());
}
}
/**
* @see Metadata#getKey()
*/
public String getKey() {
return metadata.getKey();
}
/**
* Sets payload for the request or the content from the response. If size
* isn't set, this will attempt to discover it.
*
* @param data typically InputStream for downloads, or File, byte [], String,
* or InputStream for uploads.
*/
public void setData(Object data) {
this.data = checkNotNull(data, "data");
if (getMetadata().getSize() == -1)
this.getMetadata().setSize(S3Utils.calculateSize(data));
}
/**
* generate an MD5 Hash for the current data.
* <p/>
* <h2>Note</h2>
* <p/>
* If this is an InputStream, it will be converted to a byte array first.
*
* @throws IOException if there is a problem generating the hash.
*/
public void generateMd5() throws IOException {
checkState(data != null, "data");
if (data instanceof InputStream) {
Md5InputStreamResult result = S3Utils
.generateMd5Result((InputStream) data);
getMetadata().setSize(result.length);
getMetadata().setMd5(result.md5);
setData(result.data);
} else {
getMetadata().setMd5(S3Utils.md5(data));
}
}
/**
* @return InputStream, if downloading, or whatever was set during
* {@link #setData(Object)}
*/
public Object getData() {
return data;
}
public void setMetadata(Metadata metadata) {
this.metadata = metadata;
}
/**
* @return System and User metadata relevant to this object.
*/
public Metadata getMetadata() {
return metadata;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("S3Object");
sb.append("{metadata=").append(metadata);
sb.append('}');
return sb.toString();
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof S3Object))
if (!(o instanceof Metadata))
return false;
S3Object s3Object = (S3Object) o;
Metadata metadata = (Metadata) o;
if (data != null ? !data.equals(s3Object.data) : s3Object.data != null)
if (size != metadata.size)
return false;
if (!metadata.equals(s3Object.metadata))
if (dataType != null ? !dataType.equals(metadata.dataType) : metadata.dataType != null)
return false;
if (!key.equals(metadata.key))
return false;
if (lastModified != null ? !lastModified.equals(metadata.lastModified)
: metadata.lastModified != null)
return false;
if (!Arrays.equals(getETag(), metadata.getETag()))
return false;
return true;
}
return true;
}
@Override
public int hashCode() {
int result = key.hashCode();
result = 31 * result + (lastModified != null ? lastModified.hashCode() : 0);
result = 31 * result + (getETag() != null ? Arrays.hashCode(getETag()) : 0);
result = 31 * result + (int) (size ^ (size >>> 32));
result = 31 * result + (dataType != null ? dataType.hashCode() : 0);
return result;
}
@Override
public int hashCode() {
int result = data != null ? data.hashCode() : 0;
result = 31 * result + metadata.hashCode();
return result;
}
/**
* The key is the handle that you assign to an object that allows you retrieve it later. A key
* is a sequence of Unicode characters whose UTF-8 encoding is at most 1024 bytes long. Each
* object in a bucket must have a unique key.
*
* @see <a href= "http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingKeys.html" />
*/
public String getKey() {
return key;
}
public void setContentLength(long contentLength) {
this.contentLength = contentLength;
}
public DateTime getLastModified() {
return lastModified;
}
/**
* Returns the total size of the downloaded object, or the chunk that's
* available.
* <p/>
* Chunking is only used when
* {@link org.jclouds.aws.s3.S3Connection#getObject(String, String, org.jclouds.aws.s3.commands.options.GetObjectOptions) }
* is called with options like tail, range, or startAt.
*
* @return the length in bytes that can be be obtained from
* {@link #getData()}
* @see org.jclouds.http.HttpHeaders#CONTENT_LENGTH
* @see GetObjectOptions
*/
public long getContentLength() {
return contentLength;
}
public void setLastModified(DateTime lastModified) {
this.lastModified = lastModified;
}
public void setContentRange(String contentRange) {
this.contentRange = contentRange;
}
/**
* The size of the object, in bytes.
*
* @see <a href= "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html?sec14.13." />
*/
public long getSize() {
return size;
}
/**
* If this is not-null, {@link #getContentLength() } will the size of chunk
* of the S3Object available via {@link #getData()}
*
* @see org.jclouds.http.HttpHeaders#CONTENT_RANGE
* @see GetObjectOptions
*/
public String getContentRange() {
return contentRange;
}
public void setSize(long size) {
this.size = size;
}
/**
* A standard MIME type describing the format of the contents. If none is provided, the
* default is binary/octet-stream.
*
* @see <a href= "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html?sec14.17." />
*/
public String getContentType() {
return dataType;
}
public void setContentType(String dataType) {
this.dataType = dataType;
}
public void setETag(byte[] eTag) {
this.eTag = new byte[eTag.length];
System.arraycopy(eTag, 0, this.eTag, 0, eTag.length);
}
/**
* @return the eTag value stored in the Etag header returned by S3.
*/
public byte[] getETag() {
if (eTag != null) {
byte[] retval = new byte[eTag.length];
System.arraycopy(this.eTag, 0, retval, 0, eTag.length);
return retval;
} else {
return null;
}
}
public void setUserMetadata(Multimap<String, String> userMetadata) {
this.userMetadata = userMetadata;
}
/**
* Any header starting with <code>x-amz-meta-</code> is considered user metadata. It will be
* stored with the object and returned when you retrieve the object. The total size of the
* HTTP request, not including the body, must be less than 8 KB.
*/
public Multimap<String, String> getUserMetadata() {
return userMetadata;
}
public void setOwner(CanonicalUser owner) {
this.owner = owner;
}
/**
* Every bucket and object in Amazon S3 has an owner, the user that created the bucket or
* object. The owner of a bucket or object cannot be changed. However, if the object is
* overwritten by another user (deleted and rewritten), the new object will have a new owner.
*/
public CanonicalUser getOwner() {
return owner;
}
public void setStorageClass(String storageClass) {
this.storageClass = storageClass;
}
/**
* Currently defaults to 'STANDARD' and not used.
*/
public String getStorageClass() {
return storageClass;
}
public void setCacheControl(String cacheControl) {
this.cacheControl = cacheControl;
}
/**
* Can be used to specify caching behavior along the request/reply chain.
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html?sec14.9.
*/
public String getCacheControl() {
return cacheControl;
}
public void setContentDisposition(String dataDisposition) {
this.dataDisposition = dataDisposition;
}
/**
* Specifies presentational information for the object.
*
* @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html?sec19.5.1."/>
*/
public String getContentDisposition() {
return dataDisposition;
}
public void setContentEncoding(String dataEncoding) {
this.dataEncoding = dataEncoding;
}
/**
* Specifies what content encodings have been applied to the object and thus what decoding
* mechanisms must be applied in order to obtain the media-type referenced by the Content-Type
* header field.
*
* @see <a href= "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html?sec14.11" />
*/
public String getContentEncoding() {
return dataEncoding;
}
public void setAllHeaders(Multimap<String, String> allHeaders) {
this.allHeaders = allHeaders;
}
public void setAccessControlList(AccessControlList acl) {
this.accessControlList = acl;
}
public AccessControlList getAccessControlList() {
return this.accessControlList;
}
/**
* @return all http response headers associated with this S3Object
*/
public Multimap<String, String> getAllHeaders() {
return allHeaders;
}
public int compareTo(Metadata o) {
return (this == o) ? 0 : getKey().compareTo(o.getKey());
}
}
/**
* @see Metadata#getKey()
*/
public String getKey() {
return metadata.getKey();
}
/**
* Sets entity for the request or the content from the response. If size isn't set, this will
* attempt to discover it.
*
* @param data
* typically InputStream for downloads, or File, byte [], String, or InputStream for
* uploads.
*/
public void setData(Object data) {
this.data = checkNotNull(data, "data");
if (getMetadata().getSize() == -1)
this.getMetadata().setSize(HttpUtils.calculateSize(data));
}
/**
* generate an MD5 Hash for the current data.
* <p/>
* <h2>Note</h2>
* <p/>
* If this is an InputStream, it will be converted to a byte array first.
*
* @throws IOException
* if there is a problem generating the hash.
*/
public void generateETag() throws IOException {
checkState(data != null, "data");
if (data instanceof InputStream) {
ETagInputStreamResult result = HttpUtils.generateETagResult((InputStream) data);
getMetadata().setSize(result.length);
getMetadata().setETag(result.eTag);
setData(result.data);
} else {
getMetadata().setETag(HttpUtils.eTag(data));
}
}
/**
* @return InputStream, if downloading, or whatever was set during {@link #setData(Object)}
*/
public Object getData() {
return data;
}
/**
* @return System and User metadata relevant to this object.
*/
public Metadata getMetadata() {
return metadata;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("S3Object");
sb.append("{metadata=").append(metadata);
sb.append('}');
return sb.toString();
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof S3Object))
return false;
S3Object s3Object = (S3Object) o;
if (data != null ? !data.equals(s3Object.data) : s3Object.data != null)
return false;
if (!metadata.equals(s3Object.metadata))
return false;
return true;
}
@Override
public int hashCode() {
int result = data != null ? data.hashCode() : 0;
result = 31 * result + metadata.hashCode();
return result;
}
public void setContentLength(long contentLength) {
this.contentLength = contentLength;
}
/**
* Returns the total size of the downloaded object, or the chunk that's available.
* <p/>
* Chunking is only used when
* {@link org.jclouds.aws.s3.S3Connection#getObject(String, String, org.jclouds.aws.s3.commands.options.GetObjectOptions) }
* is called with options like tail, range, or startAt.
*
* @return the length in bytes that can be be obtained from {@link #getData()}
* @see org.jclouds.http.HttpHeaders#CONTENT_LENGTH
* @see GetObjectOptions
*/
public long getContentLength() {
return contentLength;
}
public void setContentRange(String contentRange) {
this.contentRange = contentRange;
}
/**
* If this is not-null, {@link #getContentLength() } will the size of chunk of the S3Object
* available via {@link #getData()}
*
* @see org.jclouds.http.HttpHeaders#CONTENT_RANGE
* @see GetObjectOptions
*/
public String getContentRange() {
return contentRange;
}
}

View File

@ -1,29 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.
* ====================================================================
*/
/**
* This package contains components that represent authorization state.
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/latest/RESTAccessPolicy.html" />
* @author Adrian Cole
*/
package org.jclouds.aws.s3.domain.acl;

View File

@ -23,24 +23,25 @@
*/
package org.jclouds.aws.s3.filters;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collection;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import javax.ws.rs.core.HttpHeaders;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.aws.s3.reference.S3Constants;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.aws.util.DateService;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpHeaders;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpUtils;
import org.jclouds.util.DateService;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
/**
@ -50,15 +51,16 @@ import com.google.inject.name.Named;
* @author Adrian Cole
*
*/
@Singleton
public class RequestAuthorizeSignature implements HttpRequestFilter {
private static final String[] firstHeadersToSign = new String[] { HttpHeaders.CONTENT_MD5,
private final String[] firstHeadersToSign = new String[] { HttpHeaders.ETAG,
HttpHeaders.CONTENT_TYPE, HttpHeaders.DATE };
private final String accessKey;
private final String secretKey;
private final DateService dateService;
public static final long BILLION = 1000000000;
public final long BILLION = 1000000000;
private final AtomicReference<String> timeStamp;
private final AtomicLong trigger = new AtomicLong(System.nanoTime() + 1 * BILLION);
@ -99,18 +101,17 @@ public class RequestAuthorizeSignature implements HttpRequestFilter {
}
public void filter(HttpRequest request) throws HttpException {
// re-sign the request
removeOldHeaders(request);
addDateHeader(request);
String toSign = createStringToSign(request);
addAuthHeader(request, toSign);
}
public static String createStringToSign(HttpRequest request) {
public String createStringToSign(HttpRequest request) {
StringBuilder buffer = new StringBuilder();
// re-sign the request
removeOldHeaders(request);
addDateHeader(request);
appendMethod(request, buffer);
appendHttpHeaders(request, buffer);
appendAmzHeaders(request, buffer);
@ -120,21 +121,21 @@ public class RequestAuthorizeSignature implements HttpRequestFilter {
}
private void removeOldHeaders(HttpRequest request) {
request.getHeaders().removeAll(S3Constants.AUTHORIZATION);
request.getHeaders().removeAll(HttpHeaders.AUTHORIZATION);
request.getHeaders().removeAll(HttpHeaders.DATE);
}
private void addAuthHeader(HttpRequest request, String toSign) throws HttpException {
String signature;
try {
signature = S3Utils.hmacSha1Base64(toSign, secretKey.getBytes());
signature = HttpUtils.hmacSha1Base64(toSign, secretKey.getBytes());
} catch (Exception e) {
throw new HttpException("error signing request", e);
}
request.getHeaders().put(S3Constants.AUTHORIZATION, "AWS " + accessKey + ":" + signature);
request.getHeaders().put(HttpHeaders.AUTHORIZATION, "AWS " + accessKey + ":" + signature);
}
private static void appendMethod(HttpRequest request, StringBuilder toSign) {
private void appendMethod(HttpRequest request, StringBuilder toSign) {
toSign.append(request.getMethod()).append("\n");
}
@ -142,7 +143,7 @@ public class RequestAuthorizeSignature implements HttpRequestFilter {
request.getHeaders().put(HttpHeaders.DATE, timestampAsHeaderString());
}
private static void appendAmzHeaders(HttpRequest request, StringBuilder toSign) {
private void appendAmzHeaders(HttpRequest request, StringBuilder toSign) {
Set<String> headers = new TreeSet<String>(request.getHeaders().keySet());
for (String header : headers) {
if (header.startsWith("x-amz-")) {
@ -155,37 +156,31 @@ public class RequestAuthorizeSignature implements HttpRequestFilter {
}
}
private static void appendHttpHeaders(HttpRequest request, StringBuilder toSign) {
private void appendHttpHeaders(HttpRequest request, StringBuilder toSign) {
for (String header : firstHeadersToSign)
toSign.append(valueOrEmpty(request.getHeaders().get(header))).append("\n");
}
@VisibleForTesting
static void appendBucketName(HttpRequest request, StringBuilder toSign) {
void appendBucketName(HttpRequest request, StringBuilder toSign) {
String hostHeader = request.getFirstHeaderOrNull(HttpHeaders.HOST);
if (hostHeader == null)
hostHeader = checkNotNull(request.getEndPoint().getHost(),
hostHeader = checkNotNull(request.getEndpoint().getHost(),
"request.getEndPoint().getHost()");
if (hostHeader.endsWith(".amazonaws.com") && !hostHeader.equals("s3.amazonaws.com"))
toSign.append("/").append(hostHeader.substring(0, hostHeader.lastIndexOf(".s3")));
}
private static void appendUriPath(HttpRequest request, StringBuilder toSign) {
// Remove parameters from URI, because most must not be included in the signed URI...
String paramsString = null;
int queryIndex = request.getUri().indexOf('?');
if (queryIndex >= 0) {
toSign.append(request.getUri().substring(0, queryIndex));
paramsString = request.getUri().substring(queryIndex + 1);
} else {
toSign.append(request.getUri());
}
@VisibleForTesting
void appendUriPath(HttpRequest request, StringBuilder toSign) {
toSign.append(request.getEndpoint().getPath());
// ...however, there are a few exceptions that must be included in the signed URI.
if (paramsString != null) {
if (request.getEndpoint().getQuery() != null) {
StringBuilder paramsToSign = new StringBuilder("?");
String[] params = paramsString.split("&");
String[] params = request.getEndpoint().getQuery().split("&");
for (String param : params) {
String[] paramNameAndValue = param.split("=");
@ -201,7 +196,7 @@ public class RequestAuthorizeSignature implements HttpRequestFilter {
}
}
private static String valueOrEmpty(Collection<String> collection) {
private String valueOrEmpty(Collection<String> collection) {
return (collection != null && collection.size() >= 1) ? collection.iterator().next() : "";
}
}

View File

@ -21,31 +21,33 @@
* under the License.
* ====================================================================
*/
package org.jclouds.aws.s3.commands.callables;
package org.jclouds.aws.s3.functions;
import javax.ws.rs.core.HttpHeaders;
import org.apache.commons.io.IOUtils;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpFutureCommand;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpUtils;
import com.google.common.base.Function;
/**
* Parses an MD5 checksum from the header {@link S3Headers#ETAG}.
*
* @author Adrian Cole
*/
public class ParseMd5FromETagHeader extends
HttpFutureCommand.ResponseCallable<byte[]> {
public class ParseETagHeader implements Function<HttpResponse, byte[]> {
public byte[] call() throws HttpException {
checkCode();
IOUtils.closeQuietly(getResponse().getContent());
public byte[] apply(HttpResponse from) {
IOUtils.closeQuietly(from.getContent());
String eTag = from.getFirstHeaderOrNull(HttpHeaders.ETAG);
if (eTag != null) {
return HttpUtils.fromHexString(eTag.replaceAll("\"", ""));
}
throw new HttpException("did not receive ETag");
}
String eTag = getResponse().getFirstHeaderOrNull(S3Headers.ETAG);
if (eTag != null) {
return S3Utils.fromHexString(eTag.replaceAll("\"", ""));
}
throw new HttpException("did not receive ETag");
}
}

View File

@ -21,19 +21,21 @@
* under the License.
* ====================================================================
*/
package org.jclouds.aws.s3.commands.callables;
package org.jclouds.aws.s3.functions;
import java.util.Map.Entry;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.domain.S3Object.Metadata;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.aws.util.DateService;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpFutureCommand;
import org.jclouds.http.HttpHeaders;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpUtils;
import org.jclouds.util.DateService;
import com.google.common.base.Function;
import com.google.inject.Inject;
/**
@ -42,9 +44,8 @@ import com.google.inject.Inject;
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/latest/RESTObjectGET.html" />
* @author Adrian Cole
*/
public class ParseMetadataFromHeaders extends HttpFutureCommand.ResponseCallable<S3Object.Metadata> {
public class ParseMetadataFromHeaders implements Function<HttpResponse, S3Object.Metadata> {
private final DateService dateParser;
private String key;
@Inject
public ParseMetadataFromHeaders(DateService dateParser) {
@ -55,75 +56,71 @@ public class ParseMetadataFromHeaders extends HttpFutureCommand.ResponseCallable
* parses the http response headers to create a new
* {@link org.jclouds.aws.s3.domain.S3Object.Metadata} object.
*/
public S3Object.Metadata call() throws HttpException {
checkCode();
public Metadata apply(HttpResponse from) {
S3Object.Metadata metadata = new S3Object.Metadata(key);
addAllHeadersTo(metadata);
S3Object.Metadata to = new S3Object.Metadata("TODO");
addAllHeadersTo(from, to);
addUserMetadataTo(metadata);
addMd5To(metadata);
addUserMetadataTo(from, to);
addETagTo(from, to);
parseLastModifiedOrThrowException(metadata);
setContentTypeOrThrowException(metadata);
setContentLengthOrThrowException(metadata);
metadata.setCacheControl(getResponse().getFirstHeaderOrNull(HttpHeaders.CACHE_CONTROL));
metadata.setContentDisposition(getResponse().getFirstHeaderOrNull(
HttpHeaders.CONTENT_DISPOSITION));
metadata.setContentEncoding(getResponse().getFirstHeaderOrNull(HttpHeaders.CONTENT_ENCODING));
return metadata;
parseLastModifiedOrThrowException(from, to);
setContentTypeOrThrowException(from, to);
setContentLengthOrThrowException(from, to);
to.setCacheControl(from.getFirstHeaderOrNull(HttpHeaders.CACHE_CONTROL));
to.setContentDisposition(from.getFirstHeaderOrNull("Content-Disposition"));
to.setContentEncoding(from.getFirstHeaderOrNull(HttpHeaders.CONTENT_ENCODING));
return to;
}
private void addAllHeadersTo(Metadata metadata) {
metadata.getAllHeaders().putAll(getResponse().getHeaders());
private void addAllHeadersTo(HttpResponse from, Metadata metadata) {
metadata.getAllHeaders().putAll(from.getHeaders());
}
private void setContentTypeOrThrowException(S3Object.Metadata metadata) throws HttpException {
String contentType = getResponse().getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE);
private void setContentTypeOrThrowException(HttpResponse from, Metadata metadata)
throws HttpException {
String contentType = from.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE);
if (contentType == null)
throw new HttpException(HttpHeaders.CONTENT_TYPE + " not found in headers");
else
metadata.setContentType(contentType);
}
private void setContentLengthOrThrowException(S3Object.Metadata metadata) throws HttpException {
String contentLength = getResponse().getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH);
private void setContentLengthOrThrowException(HttpResponse from, Metadata metadata)
throws HttpException {
String contentLength = from.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH);
if (contentLength == null)
throw new HttpException(HttpHeaders.CONTENT_LENGTH + " not found in headers");
else
metadata.setSize(Long.parseLong(contentLength));
}
private void parseLastModifiedOrThrowException(S3Object.Metadata metadata) throws HttpException {
String lastModified = getResponse().getFirstHeaderOrNull(HttpHeaders.LAST_MODIFIED);
private void parseLastModifiedOrThrowException(HttpResponse from, Metadata metadata)
throws HttpException {
String lastModified = from.getFirstHeaderOrNull(HttpHeaders.LAST_MODIFIED);
metadata.setLastModified(dateParser.rfc822DateParse(lastModified));
if (metadata.getLastModified() == null)
throw new HttpException("could not parse: " + HttpHeaders.LAST_MODIFIED + ": "
+ lastModified);
}
private void addMd5To(S3Object.Metadata metadata) {
String md5Header = getResponse().getFirstHeaderOrNull(S3Headers.AMZ_MD5);
if (md5Header != null) {
metadata.setMd5(S3Utils.fromHexString(md5Header));
private void addETagTo(HttpResponse from, Metadata metadata) {
String eTagHeader = from.getFirstHeaderOrNull(S3Headers.AMZ_MD5);
if (eTagHeader != null) {
metadata.setETag(HttpUtils.fromHexString(eTagHeader));
}
String eTag = getResponse().getFirstHeaderOrNull(S3Headers.ETAG);
if (metadata.getMd5() == null && eTag != null) {
metadata.setMd5(S3Utils.fromHexString(eTag.replaceAll("\"", "")));
String eTag = from.getFirstHeaderOrNull(HttpHeaders.ETAG);
if (metadata.getETag() == null && eTag != null) {
metadata.setETag(HttpUtils.fromHexString(eTag.replaceAll("\"", "")));
}
}
private void addUserMetadataTo(S3Object.Metadata metadata) {
for (Entry<String, String> header : getResponse().getHeaders().entries()) {
private void addUserMetadataTo(HttpResponse from, Metadata metadata) {
for (Entry<String, String> header : from.getHeaders().entries()) {
if (header.getKey() != null && header.getKey().startsWith(S3Headers.USER_METADATA_PREFIX))
metadata.getUserMetadata().put(header.getKey(), header.getValue());
}
}
public void setKey(String key) {
this.key = key;
}
}

View File

@ -0,0 +1,83 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.functions;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpResponse;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.inject.Inject;
/**
* Parses response headers and creates a new S3Object from them and the HTTP content.
*
* @see ParseMetadataFromHeaders
* @author Adrian Cole
*/
public class ParseObjectFromHeadersAndHttpContent implements Function<HttpResponse, S3Object> {
private final ParseMetadataFromHeaders metadataParser;
@Inject
public ParseObjectFromHeadersAndHttpContent(ParseMetadataFromHeaders metadataParser) {
this.metadataParser = metadataParser;
}
/**
* First, calls {@link ParseMetadataFromHeaders}.
*
* Then, sets the object size based on the Content-Length header and adds the content to the
* {@link S3Object} result.
*
* @throws org.jclouds.http.HttpException
*/
public S3Object apply(HttpResponse from) {
S3Object.Metadata metadata = metadataParser.apply(from);
S3Object object = new S3Object(metadata, from.getContent());
parseContentLengthOrThrowException(from, object);
return object;
}
@VisibleForTesting
void parseContentLengthOrThrowException(HttpResponse from, S3Object object) throws HttpException {
String contentLength = from.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH);
String contentRange = from.getFirstHeaderOrNull("Content-Range");
if (contentLength == null)
throw new HttpException(HttpHeaders.CONTENT_LENGTH + " header not present in headers: "
+ from.getHeaders());
object.setContentLength(Long.parseLong(contentLength));
if (contentRange == null) {
object.getMetadata().setSize(object.getContentLength());
} else {
object.setContentRange(contentRange);
object.getMetadata().setSize(
Long.parseLong(contentRange.substring(contentRange.lastIndexOf('/') + 1)));
}
}
}

View File

@ -0,0 +1,42 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.functions;
import org.jclouds.http.HttpResponseException;
import com.google.common.base.Function;
public class ReturnFalseOn404 implements Function<Exception, Boolean> {
public Boolean apply(Exception from) {
if (from instanceof HttpResponseException) {
HttpResponseException responseException = (HttpResponseException) from;
if (responseException.getResponse().getStatusCode() == 404) {
return false;
}
}
return null;
}
}

View File

@ -0,0 +1,42 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.functions;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.s3.domain.AccessControlList;
import com.google.common.base.Function;
public class ReturnNotFoundIfBucketDoesntExist implements Function<Exception, AccessControlList> {
public AccessControlList apply(Exception from) {
if (from != null && from instanceof AWSResponseException) {
AWSResponseException responseException = (AWSResponseException) from;
if ("NoSuchBucket".equals(responseException.getError().getCode())) {
return AccessControlList.NOT_FOUND;
}
}
return null;
}
}

View File

@ -0,0 +1,43 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.functions;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.s3.domain.AccessControlList;
import com.google.common.base.Function;
public class ReturnNotFoundIfObjectDoesntExist implements Function<Exception, AccessControlList> {
public AccessControlList apply(Exception from) {
if (from != null && from instanceof AWSResponseException) {
AWSResponseException responseException = (AWSResponseException) from;
if ("NoSuchObject".equals(responseException.getError().getCode())) {
return AccessControlList.NOT_FOUND;
}
}
return null;
}
}

View File

@ -0,0 +1,51 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.functions;
import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.http.HttpResponseException;
import com.google.common.base.Function;
/**
*
* {@code bucketParser} is only enacted when the http status code is 2xx. Amazon treats NoSuchBucket
* as an exception, while we regard this as a valid response. Accordingly, we check for this {@code
* NoSuchBucket} message and return {@code S3Bucket#NOT_FOUND} if present.
*
* @author James Murty
*/
public class ReturnS3BucketNotFoundOn404 implements Function<Exception, S3Bucket> {
public S3Bucket apply(Exception from) {
if (from instanceof HttpResponseException) {
HttpResponseException responseException = (HttpResponseException) from;
if (responseException.getResponse().getStatusCode() == 404) {
return S3Bucket.NOT_FOUND;
}
}
return null;
}
}

View File

@ -0,0 +1,43 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.functions;
import org.jclouds.aws.s3.domain.S3Object.Metadata;
import org.jclouds.http.HttpResponseException;
import com.google.common.base.Function;
public class ReturnS3ObjectMetadataNotFoundOn404 implements Function<Exception, Metadata> {
public Metadata apply(Exception from) {
if (from instanceof HttpResponseException) {
HttpResponseException responseException = (HttpResponseException) from;
if (responseException.getResponse().getStatusCode() == 404) {
return Metadata.NOT_FOUND;
}
}
return null;
}
}

View File

@ -0,0 +1,43 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.functions;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.http.HttpResponseException;
import com.google.common.base.Function;
public class ReturnS3ObjectNotFoundOn404 implements Function<Exception, S3Object> {
public S3Object apply(Exception from) {
if (from instanceof HttpResponseException) {
HttpResponseException responseException = (HttpResponseException) from;
if (responseException.getResponse().getStatusCode() == 404) {
return S3Object.NOT_FOUND;
}
}
return null;
}
}

View File

@ -21,26 +21,26 @@
* under the License.
* ====================================================================
*/
package org.jclouds.http.commands;
package org.jclouds.aws.s3.functions;
import java.net.URI;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.http.HttpFutureCommand;
import org.jclouds.http.HttpMethod;
import org.jclouds.http.commands.callables.ReturnStringIf200;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.google.common.base.Function;
/**
* // TODO: Adrian: Document this!
*
* @author Adrian Cole
*/
public class GetString extends HttpFutureCommand<String> {
public class ReturnTrueIfBucketAlreadyOwnedByYou implements Function<Exception, Boolean> {
@Inject
public GetString(URI endPoint, ReturnStringIf200 callable, @Assisted String uri) {
super(endPoint, HttpMethod.GET, uri, callable);
public Boolean apply(Exception from) {
if (from instanceof AWSResponseException) {
AWSResponseException responseException = (AWSResponseException) from;
if ("BucketAlreadyOwnedByYou".equals(responseException.getError().getCode())) {
return true;
}
}
return null;
}
}
}

View File

@ -0,0 +1,45 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.functions;
import org.jclouds.aws.AWSResponseException;
import com.google.common.base.Function;
public class ReturnTrueOn404FalseIfNotEmpty implements Function<Exception, Boolean> {
public Boolean apply(Exception from) {
if (from instanceof AWSResponseException) {
AWSResponseException responseException = (AWSResponseException) from;
if (responseException.getResponse().getStatusCode() == 404) {
return true;
} else if ("BucketNotEmpty".equals(responseException.getError().getCode())
|| responseException.getResponse().getStatusCode() == 409) {
return false;
}
}
return null;
}
}

View File

@ -21,12 +21,16 @@
* under the License.
* ====================================================================
*/
package org.jclouds.http;
package org.jclouds.aws.s3.functions;
public interface ContentTypes {
import org.jclouds.aws.s3.domain.S3Object;
public static final String BINARY = "application/octet-stream";
public static final String PLAIN = "text/plain";
public static final String UNKNOWN_MIME_TYPE = "application/x-unknown-mime-type";
import com.google.common.base.Function;
}
public class S3ObjectKey implements Function<Object, String> {
public String apply(Object from) {
return ((S3Object) from).getKey();
}
}

View File

@ -25,4 +25,4 @@
* This package contains response handlers for S3 commands.
* @author Adrian Cole
*/
package org.jclouds.aws.s3.commands.callables;
package org.jclouds.aws.s3.functions;

View File

@ -28,11 +28,12 @@ import javax.annotation.Resource;
import org.jclouds.aws.domain.AWSError;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.aws.s3.xml.S3ParserFactory;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpFutureCommand;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.logging.Logger;
import org.jclouds.util.Utils;
import com.google.inject.Inject;
import com.google.inject.name.Named;
@ -46,25 +47,27 @@ public class AWSClientErrorRetryHandler implements HttpRetryHandler {
private final S3ParserFactory parserFactory;
private final int retryCountLimit;
private final S3Utils utils;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public AWSClientErrorRetryHandler(S3ParserFactory parserFactory,
public AWSClientErrorRetryHandler(S3Utils utils, S3ParserFactory parserFactory,
@Named("jclouds.http.max-retries") int retryCountLimit) {
this.utils = utils;
this.retryCountLimit = retryCountLimit;
this.parserFactory = parserFactory;
}
public boolean shouldRetryRequest(HttpFutureCommand<?> command, HttpResponse response) {
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
if (command.getFailureCount() > retryCountLimit)
return false;
if (response.getStatusCode() == 400 || response.getStatusCode() == 409) {
byte[] content = S3Utils.closeConnectionButKeepContentStream(response);
byte[] content = Utils.closeConnectionButKeepContentStream(response);
command.incrementRedirectCount();
try {
AWSError error = S3Utils.parseAWSErrorFromContent(parserFactory, command, response,
AWSError error = utils.parseAWSErrorFromContent(parserFactory, command, response,
new String(content));
if ("RequestTimeout".equals(error.getCode())
|| "OperationAborted".equals(error.getCode())) {
@ -76,4 +79,5 @@ public class AWSClientErrorRetryHandler implements HttpRetryHandler {
}
return false;
}
}

View File

@ -23,17 +23,16 @@
*/
package org.jclouds.aws.s3.handlers;
import java.net.URI;
import org.jclouds.aws.domain.AWSError;
import org.jclouds.aws.s3.reference.S3Constants;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.aws.s3.xml.S3ParserFactory;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpFutureCommand;
import org.jclouds.http.HttpHeaders;
import org.jclouds.http.HttpMethod;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
import org.jclouds.http.handlers.RedirectionRetryHandler;
import org.jclouds.util.Utils;
@ -47,54 +46,45 @@ import com.google.inject.name.Named;
*/
public class AWSRedirectionRetryHandler extends RedirectionRetryHandler {
private final S3ParserFactory parserFactory;
private final S3Utils utils;
@Inject
public AWSRedirectionRetryHandler(S3ParserFactory parserFactory,
@Named("jclouds.http.max-redirects") int retryCountLimit) {
super(retryCountLimit);
public AWSRedirectionRetryHandler(BackoffLimitedRetryHandler backoffHandler, S3Utils utils,
S3ParserFactory parserFactory, @Named("jclouds.http.max-redirects") int retryCountLimit) {
super(backoffHandler, retryCountLimit);
this.utils = utils;
this.parserFactory = parserFactory;
}
public boolean shouldRetryRequest(HttpFutureCommand<?> command, HttpResponse response) {
if (response.getStatusCode() == 301 || response.getStatusCode() == 307) {
byte[] content = S3Utils.closeConnectionButKeepContentStream(response);
if (command.getRequest().getMethod() == HttpMethod.HEAD) {
command.getRequest().setMethod(HttpMethod.GET);
return true;
} else {
command.incrementRedirectCount();
try {
AWSError error = S3Utils.parseAWSErrorFromContent(parserFactory, command, response,
new String(content));
String host = error.getDetails().get(S3Constants.ENDPOINT);
if (host != null) {
if (host.equals(command.getRequest().getEndPoint().getHost())) {
// must be an amazon error related to
// http://developer.amazonwebservices.com/connect/thread.jspa?messageID=72287&#72287
try {
command.incrementFailureCount();
Thread.sleep(100);
return true;
} catch (InterruptedException e) {
command.setException(e);
return false;
}
} else {
URI endPoint = command.getRequest().getEndPoint();
endPoint = Utils.replaceHostInEndPoint(endPoint, host);
command.getRequest().setEndPoint(endPoint);
command.getRequest().getHeaders().removeAll(HttpHeaders.HOST);
}
return true;
public boolean shouldRetryRequest(HttpCommand command, HttpRequest request, HttpResponse response) {
byte[] content = Utils.closeConnectionButKeepContentStream(response);
if (request.getMethod() == HttpMethod.HEAD) {
command.setMethod(HttpMethod.GET);
return true;
} else {
command.incrementRedirectCount();
try {
AWSError error = utils.parseAWSErrorFromContent(parserFactory, command, response,
new String(content));
String host = error.getDetails().get(S3Constants.ENDPOINT);
if (host != null) {
if (host.equals(request.getEndpoint().getHost())) {
// must be an amazon error related to
// http://developer.amazonwebservices.com/connect/thread.jspa?messageID=72287&#72287
return backoffHandler.shouldRetryRequest(command, response);
} else {
return false;
command.setHostAndPort(host, request.getEndpoint().getPort());
}
} catch (HttpException e) {
return true;
} else {
return false;
}
} catch (HttpException e) {
logger.error(e, "error on redirect for command %s; response %s; retrying...", command,
response);
return false;
}
} else {
return super.shouldRetryRequest(command, response);
}
}
}

View File

@ -29,8 +29,8 @@ import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.domain.AWSError;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.aws.s3.xml.S3ParserFactory;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpFutureCommand;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.Logger;
@ -50,13 +50,15 @@ public class ParseAWSErrorFromXmlContent implements HttpErrorHandler {
protected Logger logger = Logger.NULL;
private final S3ParserFactory parserFactory;
private final S3Utils utils;
@Inject
public ParseAWSErrorFromXmlContent(S3ParserFactory parserFactory) {
public ParseAWSErrorFromXmlContent(S3Utils utils, S3ParserFactory parserFactory) {
this.utils = utils;
this.parserFactory = parserFactory;
}
public void handleError(HttpFutureCommand<?> command, HttpResponse response) {
public void handleError(HttpCommand command, HttpResponse response) {
String content;
try {
content = response.getContent() != null ? Utils.toStringAndClose(response.getContent())
@ -64,8 +66,8 @@ public class ParseAWSErrorFromXmlContent implements HttpErrorHandler {
if (content != null) {
try {
if (content.indexOf('<') >= 0) {
AWSError error = S3Utils.parseAWSErrorFromContent(parserFactory, command,
response, content);
AWSError error = utils.parseAWSErrorFromContent(parserFactory, command, response,
content);
command.setException(new AWSResponseException(command, response, error));
} else {
command.setException(new HttpResponseException(command, response, content));

View File

@ -102,16 +102,16 @@ public abstract class BaseS3Map<V> implements S3Map<String, V> {
}
}
protected boolean containsMd5(byte[] md5) throws InterruptedException, ExecutionException,
protected boolean containsETag(byte[] eTag) throws InterruptedException, ExecutionException,
TimeoutException {
for (S3Object.Metadata metadata : refreshBucket().getContents()) {
if (Arrays.equals(md5, metadata.getMd5()))
if (Arrays.equals(eTag, metadata.getETag()))
return true;
}
return false;
}
protected byte[] getMd5(Object value) throws IOException, FileNotFoundException,
protected byte[] getETag(Object value) throws IOException, FileNotFoundException,
InterruptedException, ExecutionException, TimeoutException {
S3Object object = null;
if (value instanceof S3Object) {
@ -119,9 +119,9 @@ public abstract class BaseS3Map<V> implements S3Map<String, V> {
} else {
object = new S3Object("dummy", value);
}
if (object.getMetadata().getMd5() == null)
object.generateMd5();
return object.getMetadata().getMd5();
if (object.getMetadata().getETag() == null)
object.generateETag();
return object.getMetadata().getETag();
}
/**
@ -171,8 +171,8 @@ public abstract class BaseS3Map<V> implements S3Map<String, V> {
*/
public boolean containsValue(Object value) {
try {
byte[] md5 = getMd5(value);
return containsMd5(md5);
byte[] eTag = getETag(value);
return containsETag(eTag);
} catch (Exception e) {
Utils.<S3RuntimeException> rethrowIfRuntimeOrSameType(e);
throw new S3RuntimeException(String.format(
@ -232,8 +232,7 @@ public abstract class BaseS3Map<V> implements S3Map<String, V> {
public boolean containsKey(Object key) {
try {
return connection.headObject(bucket, key.toString()).get(requestTimeoutMilliseconds,
TimeUnit.MILLISECONDS) != S3Object.Metadata.NOT_FOUND;
return connection.headObject(bucket, key.toString()) != S3Object.Metadata.NOT_FOUND;
} catch (Exception e) {
Utils.<S3RuntimeException> rethrowIfRuntimeOrSameType(e);
throw new S3RuntimeException(String.format("Error searching for %1$s:%2$s", bucket, key),

View File

@ -1,281 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.internal;
import java.util.List;
import java.util.concurrent.Future;
import org.jclouds.aws.s3.S3Connection;
import org.jclouds.aws.s3.commands.BucketExists;
import org.jclouds.aws.s3.commands.CopyObject;
import org.jclouds.aws.s3.commands.DeleteBucket;
import org.jclouds.aws.s3.commands.DeleteObject;
import org.jclouds.aws.s3.commands.GetAccessControlList;
import org.jclouds.aws.s3.commands.ListOwnedBuckets;
import org.jclouds.aws.s3.commands.GetObject;
import org.jclouds.aws.s3.commands.HeadObject;
import org.jclouds.aws.s3.commands.ListBucket;
import org.jclouds.aws.s3.commands.PutBucketAccessControlList;
import org.jclouds.aws.s3.commands.PutBucket;
import org.jclouds.aws.s3.commands.PutObject;
import org.jclouds.aws.s3.commands.PutObjectAccessControlList;
import org.jclouds.aws.s3.commands.S3CommandFactory;
import org.jclouds.aws.s3.commands.options.CopyObjectOptions;
import org.jclouds.aws.s3.commands.options.GetObjectOptions;
import org.jclouds.aws.s3.commands.options.ListBucketOptions;
import org.jclouds.aws.s3.commands.options.PutBucketOptions;
import org.jclouds.aws.s3.commands.options.PutObjectOptions;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.domain.S3Bucket.Metadata;
import org.jclouds.http.HttpFutureCommandClient;
import com.google.inject.Inject;
/**
* Uses {@link HttpFutureCommandClient} to invoke the REST API of S3.
*
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?" />
* @author Adrian Cole
*/
public class LiveS3Connection implements S3Connection {
private final HttpFutureCommandClient client;
/**
* creates command objects that can be submitted to the client
*/
private final S3CommandFactory factory;
@Inject
public LiveS3Connection(HttpFutureCommandClient client, S3CommandFactory factory) {
this.client = client;
this.factory = factory;
}
/**
* {@inheritDoc}
*
* @see GetObject
*/
public Future<S3Object> getObject(String s3Bucket, String key) {
return getObject(s3Bucket, key, GetObjectOptions.NONE);
}
/**
* {@inheritDoc}
*
* @see GetObject
*/
public Future<S3Object> getObject(String s3Bucket, String key, GetObjectOptions options) {
GetObject getObject = factory.createGetObject(s3Bucket, key, options);
client.submit(getObject);
return getObject;
}
/**
* {@inheritDoc}
*
* @see HeadObject
*/
public Future<S3Object.Metadata> headObject(String s3Bucket, String key) {
HeadObject headMetadata = factory.createHeadMetadata(s3Bucket, key);
client.submit(headMetadata);
return headMetadata;
}
/**
* {@inheritDoc}
*
* @see DeleteObject
*/
public Future<Boolean> deleteObject(String s3Bucket, String key) {
DeleteObject deleteObject = factory.createDeleteObject(s3Bucket, key);
client.submit(deleteObject);
return deleteObject;
}
/**
* {@inheritDoc}
*
* @see PutObject
*/
public Future<byte[]> putObject(String s3Bucket, S3Object object) {
return putObject(s3Bucket, object, PutObjectOptions.NONE);
}
/**
* {@inheritDoc}
*
* @see PutObject
*/
public Future<byte[]> putObject(String bucketName, S3Object object, PutObjectOptions options) {
PutObject putObject = factory.createPutObject(bucketName, object, options);
client.submit(putObject);
return putObject;
}
/**
* {@inheritDoc}
*
* @see PutBucket
*/
public Future<Boolean> putBucketIfNotExists(String s3Bucket) {
return putBucketIfNotExists(s3Bucket, PutBucketOptions.NONE);
}
/**
* {@inheritDoc}
*
* @see PutBucket
*/
public Future<Boolean> putBucketIfNotExists(String s3Bucket, PutBucketOptions options) {
PutBucket putBucket = factory.createPutBucket(s3Bucket, options);
client.submit(putBucket);
return putBucket;
}
/**
* {@inheritDoc}
*
* @see DeleteBucket
*/
public Future<Boolean> deleteBucketIfEmpty(String s3Bucket) {
DeleteBucket deleteBucket = factory.createDeleteBucket(s3Bucket);
client.submit(deleteBucket);
return deleteBucket;
}
/**
* {@inheritDoc}
*
* @see CopyObject
*/
public Future<S3Object.Metadata> copyObject(String sourceBucket, String sourceObject,
String destinationBucket, String destinationObject) {
return copyObject(sourceBucket, sourceObject, destinationBucket, destinationObject,
new CopyObjectOptions());
}
/**
* {@inheritDoc}
*
* @see CopyObject
*/
public Future<S3Object.Metadata> copyObject(String sourceBucket, String sourceObject,
String destinationBucket, String destinationObject, CopyObjectOptions options) {
CopyObject copy = factory.createCopyObject(sourceBucket, sourceObject, destinationBucket,
destinationObject, options);
client.submit(copy);
return copy;
}
/**
* {@inheritDoc}
*
* @see BucketExists
*/
public Future<Boolean> bucketExists(String s3Bucket) {
BucketExists headRequestObject = factory.createHeadBucket(s3Bucket);
client.submit(headRequestObject);
return headRequestObject;
}
/**
* {@inheritDoc}
*
* @see ListBucket
*/
public Future<S3Bucket> listBucket(String s3Bucket) {
return listBucket(s3Bucket, ListBucketOptions.NONE);
}
/**
* {@inheritDoc}
*
* @see ListBucket
*/
public Future<S3Bucket> listBucket(String s3Bucket, ListBucketOptions options) {
ListBucket getBucket = factory.createListBucket(s3Bucket, options);
client.submit(getBucket);
return getBucket;
}
/**
* {@inheritDoc}
*
* @see ListOwnedBuckets
*/
public Future<List<Metadata>> listOwnedBuckets() {
ListOwnedBuckets listRequest = factory.createGetMetadataForOwnedBuckets();
client.submit(listRequest);
return listRequest;
}
/**
* {@inheritDoc}
*
* @see GetAccessControlList
*/
public Future<AccessControlList> getBucketACL(String bucket) {
GetAccessControlList getBucketACLRequest = factory.createGetBucketACL(bucket);
client.submit(getBucketACLRequest);
return getBucketACLRequest;
}
/**
* {@inheritDoc}
*
* @see GetAccessControlList
*/
public Future<AccessControlList> getObjectACL(String bucket, String objectKey) {
GetAccessControlList getObjectACLRequest = factory.createGetObjectACL(bucket, objectKey);
client.submit(getObjectACLRequest);
return getObjectACLRequest;
}
/**
* {@inheritDoc}
*
* @see PutBucketAccessControlList
*/
public Future<Boolean> putBucketACL(String bucket, AccessControlList acl) {
PutBucketAccessControlList putBucketACLRequest = factory.createPutBucketACL(bucket, acl);
client.submit(putBucketACLRequest);
return putBucketACLRequest;
}
/**
* {@inheritDoc}
*
* @see PutBucketAccessControlList
*/
public Future<Boolean> putObjectACL(String bucket, String objectKey, AccessControlList acl) {
PutObjectAccessControlList putObjectACLRequest =
factory.createPutObjectACL(bucket, objectKey, acl);
client.submit(putObjectACLRequest);
return putObjectACLRequest;
}
}

View File

@ -23,23 +23,30 @@
*/
package org.jclouds.aws.s3.internal;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.jclouds.aws.s3.S3Connection;
import org.jclouds.aws.s3.S3InputStreamMap;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.util.Utils;
import java.io.File;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/**
* Map representation of a live connection to S3. All put operations will result
* in Md5 calculation. If this is not desired, use {@link LiveS3ObjectMap}
* in ETag calculation. If this is not desired, use {@link LiveS3ObjectMap}
* instead.
*
* @author Adrian Cole
@ -184,7 +191,7 @@ public class LiveS3InputStreamMap extends BaseS3Map<InputStream> implements
/**
* submits requests to add all objects and collects the results later. All
* values will have md5 calculated first. As a side-effect of this, the
* values will have eTag calculated first. As a side-effect of this, the
* content will be copied into a byte [].
*
* @see S3Connection#putObject(String, S3Object)
@ -196,8 +203,11 @@ public class LiveS3InputStreamMap extends BaseS3Map<InputStream> implements
for (Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) {
S3Object object = new S3Object(entry.getKey());
object.setData(entry.getValue());
object.generateMd5();
object.generateETag();
puts.add(connection.putObject(bucket, object));
/// ParamExtractor Funcion<?,String>
/// response transformer set key on the way out.
/// ExceptionHandler convert 404 to NOT_FOUND
}
for (Future<byte[]> put : puts)
// this will throw an exception if there was a problem
@ -246,7 +256,7 @@ public class LiveS3InputStreamMap extends BaseS3Map<InputStream> implements
}
/**
* calculates md5 before adding the object to s3. As a side-effect of this,
* calculates eTag before adding the object to s3. As a side-effect of this,
* the content will be copied into a byte []. *
*
* @see S3Connection#putObject(String, S3Object)
@ -257,7 +267,7 @@ public class LiveS3InputStreamMap extends BaseS3Map<InputStream> implements
try {
InputStream returnVal = containsKey(s) ? get(s) : null;
object.setData(o);
object.generateMd5();
object.generateETag();
connection.putObject(bucket, object).get(
requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
return returnVal;

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.aws.s3.commands.options;
package org.jclouds.aws.s3.options;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@ -29,11 +29,11 @@ import static com.google.common.base.Preconditions.checkState;
import java.io.UnsupportedEncodingException;
import org.jclouds.aws.s3.domain.acl.CannedAccessPolicy;
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.aws.util.DateService;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.options.BaseHttpRequestOptions;
import org.jclouds.util.DateService;
import org.joda.time.DateTime;
import com.google.common.base.Preconditions;
@ -140,7 +140,7 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
* This header can be used with x-amz-copy-source-if-unmodified-since, but cannot be used with
* other conditional copy headers.
*
* @see CopyObjectOptions#ifSourceMd5Matches(byte[])
* @see CopyObjectOptions#ifSourceETagMatches(byte[])
*/
public String getIfMatch() {
return getFirstHeaderOrNull("x-amz-copy-source-if-match");
@ -155,7 +155,7 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
* This header can be used with x-amz-copy-source-if-modified-since, but cannot be used with
* other conditional copy headers.
*
* @see CopyObjectOptions#ifSourceMd5DoesntMatch(byte[])
* @see CopyObjectOptions#ifSourceETagDoesntMatch(byte[])
*/
public String getIfNoneMatch() {
return getFirstHeaderOrNull("x-amz-copy-source-if-none-match");
@ -174,11 +174,11 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
/**
* Only return the object if it has changed since this time.
* <p/>
* Not compatible with {@link #ifSourceMd5Matches(byte[])} or
* Not compatible with {@link #ifSourceETagMatches(byte[])} or
* {@link #ifSourceUnmodifiedSince(DateTime)}
*/
public CopyObjectOptions ifSourceModifiedSince(DateTime ifModifiedSince) {
checkState(getIfMatch() == null, "ifMd5Matches() is not compatible with ifModifiedSince()");
checkState(getIfMatch() == null, "ifETagMatches() is not compatible with ifModifiedSince()");
checkState(getIfUnmodifiedSince() == null,
"ifUnmodifiedSince() is not compatible with ifModifiedSince()");
replaceHeader("x-amz-copy-source-if-modified-since", dateService
@ -189,12 +189,12 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
/**
* Only return the object if it hasn't changed since this time.
* <p/>
* Not compatible with {@link #ifSourceMd5DoesntMatch(byte[])} or
* Not compatible with {@link #ifSourceETagDoesntMatch(byte[])} or
* {@link #ifSourceModifiedSince(DateTime)}
*/
public CopyObjectOptions ifSourceUnmodifiedSince(DateTime ifUnmodifiedSince) {
checkState(getIfNoneMatch() == null,
"ifMd5DoesntMatch() is not compatible with ifUnmodifiedSince()");
"ifETagDoesntMatch() is not compatible with ifUnmodifiedSince()");
checkState(getIfModifiedSince() == null,
"ifModifiedSince() is not compatible with ifUnmodifiedSince()");
replaceHeader("x-amz-copy-source-if-unmodified-since", dateService
@ -203,42 +203,43 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
}
/**
* The object's md5 hash should match the parameter <code>md5</code>.
* The object's eTag hash should match the parameter <code>eTag</code>.
* <p/>
* <p/>
* Not compatible with {@link #ifSourceMd5DoesntMatch(byte[])} or
* Not compatible with {@link #ifSourceETagDoesntMatch(byte[])} or
* {@link #ifSourceModifiedSince(DateTime)}
*
* @param md5
* @param eTag
* hash representing the entity
*/
public CopyObjectOptions ifSourceMd5Matches(byte[] md5) throws UnsupportedEncodingException {
public CopyObjectOptions ifSourceETagMatches(byte[] eTag) throws UnsupportedEncodingException {
checkState(getIfNoneMatch() == null,
"ifMd5DoesntMatch() is not compatible with ifMd5Matches()");
"ifETagDoesntMatch() is not compatible with ifETagMatches()");
checkState(getIfModifiedSince() == null,
"ifModifiedSince() is not compatible with ifMd5Matches()");
replaceHeader("x-amz-copy-source-if-match", String.format("\"%1$s\"", S3Utils
.toHexString(checkNotNull(md5, "md5"))));
"ifModifiedSince() is not compatible with ifETagMatches()");
replaceHeader("x-amz-copy-source-if-match", String.format("\"%1$s\"", HttpUtils
.toHexString(checkNotNull(eTag, "eTag"))));
return this;
}
/**
* The object should not have a md5 hash corresponding with the parameter <code>md5</code>.
* The object should not have a eTag hash corresponding with the parameter <code>eTag</code>.
* <p/>
* Not compatible with {@link #ifSourceMd5Matches(byte[])} or
* Not compatible with {@link #ifSourceETagMatches(byte[])} or
* {@link #ifSourceUnmodifiedSince(DateTime)}
*
* @param md5
* @param eTag
* hash representing the entity
* @throws UnsupportedEncodingException
* if there was a problem converting this into an S3 eTag string
*/
public CopyObjectOptions ifSourceMd5DoesntMatch(byte[] md5) throws UnsupportedEncodingException {
checkState(getIfMatch() == null, "ifMd5Matches() is not compatible with ifMd5DoesntMatch()");
public CopyObjectOptions ifSourceETagDoesntMatch(byte[] eTag)
throws UnsupportedEncodingException {
checkState(getIfMatch() == null, "ifETagMatches() is not compatible with ifETagDoesntMatch()");
Preconditions.checkState(getIfUnmodifiedSince() == null,
"ifUnmodifiedSince() is not compatible with ifMd5DoesntMatch()");
replaceHeader("x-amz-copy-source-if-none-match", String.format("\"%1$s\"", S3Utils
.toHexString(checkNotNull(md5, "ifMd5DoesntMatch"))));
"ifUnmodifiedSince() is not compatible with ifETagDoesntMatch()");
replaceHeader("x-amz-copy-source-if-none-match", String.format("\"%1$s\"", HttpUtils
.toHexString(checkNotNull(eTag, "ifETagDoesntMatch"))));
return this;
}
@ -292,21 +293,21 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
}
/**
* @see CopyObjectOptions#ifSourceMd5Matches(byte[])
* @see CopyObjectOptions#ifSourceETagMatches(byte[])
*/
public static CopyObjectOptions ifSourceMd5Matches(byte[] md5)
public static CopyObjectOptions ifSourceETagMatches(byte[] eTag)
throws UnsupportedEncodingException {
CopyObjectOptions options = new CopyObjectOptions();
return options.ifSourceMd5Matches(md5);
return options.ifSourceETagMatches(eTag);
}
/**
* @see CopyObjectOptions#ifSourceMd5DoesntMatch(byte[])
* @see CopyObjectOptions#ifSourceETagDoesntMatch(byte[])
*/
public static CopyObjectOptions ifSourceMd5DoesntMatch(byte[] md5)
public static CopyObjectOptions ifSourceETagDoesntMatch(byte[] eTag)
throws UnsupportedEncodingException {
CopyObjectOptions options = new CopyObjectOptions();
return options.ifSourceMd5DoesntMatch(md5);
return options.ifSourceETagDoesntMatch(eTag);
}
/**

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.aws.s3.commands.options;
package org.jclouds.aws.s3.options;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
@ -56,33 +56,20 @@ public class ListBucketOptions extends BaseHttpRequestOptions {
*
*/
public ListBucketOptions withPrefix(String prefix) {
parameters.put("prefix", checkNotNull(prefix, "prefix"));
queryParameters.put("prefix", checkNotNull(prefix, "prefix"));
return this;
}
/**
* @see ListBucketOptions#withPrefix(String)
*/
public String getPrefix() {
return parameters.get("prefix");
}
/**
* Indicates where in the bucket to begin listing. The list will only include keys that occur
* lexicographically after marker. This is convenient for pagination: To get the next page of
* results use the last key of the current page as the marker.
*/
public ListBucketOptions afterMarker(String marker) {
parameters.put("marker", checkNotNull(marker, "marker"));
queryParameters.put("marker", checkNotNull(marker, "marker"));
return this;
}
/**
* @see ListBucketOptions#afterMarker(String)
*/
public String getMarker() {
return parameters.get("marker");
}
/**
* The maximum number of keys you'd like to see in the response body. The server might return
@ -90,17 +77,10 @@ public class ListBucketOptions extends BaseHttpRequestOptions {
*/
public ListBucketOptions maxResults(long maxKeys) {
checkState(maxKeys >= 0, "maxKeys must be >= 0");
parameters.put("max-keys", Long.toString(maxKeys));
queryParameters.put("max-keys", Long.toString(maxKeys));
return this;
}
/**
* @see ListBucketOptions#maxResults(long)
*/
public String getMaxKeys() {
return parameters.get("max-keys");
}
/**
* Causes keys that contain the same string between the prefix and the first occurrence of the
* delimiter to be rolled up into a single result element in the CommonPrefixes collection. These
@ -108,17 +88,10 @@ public class ListBucketOptions extends BaseHttpRequestOptions {
*
*/
public ListBucketOptions delimiter(String delimiter) {
parameters.put("delimiter", checkNotNull(delimiter, "delimiter"));
queryParameters.put("delimiter", checkNotNull(delimiter, "delimiter"));
return this;
}
/**
* @see ListBucketOptions#delimiter(String)
*/
public String getDelimiter() {
return parameters.get("delimiter");
}
public static class Builder {
/**

View File

@ -21,11 +21,12 @@
* under the License.
* ====================================================================
*/
package org.jclouds.aws.s3.commands.options;
package org.jclouds.aws.s3.options;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
import org.jclouds.aws.s3.domain.S3Bucket.Metadata.LocationConstraint;
import org.jclouds.aws.s3.domain.acl.CannedAccessPolicy;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.http.options.BaseHttpRequestOptions;
@ -60,7 +61,7 @@ public class PutBucketOptions extends BaseHttpRequestOptions {
*/
public PutBucketOptions createIn(LocationConstraint constraint) {
this.constraint = checkNotNull(constraint, "constraint");
this.payload = String
this.entity = String
.format(
"<CreateBucketConfiguration><LocationConstraint>%1$s</LocationConstraint></CreateBucketConfiguration>",
constraint.toString());

View File

@ -21,9 +21,9 @@
* under the License.
* ====================================================================
*/
package org.jclouds.aws.s3.commands.options;
package org.jclouds.aws.s3.options;
import org.jclouds.aws.s3.domain.acl.CannedAccessPolicy;
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.http.options.BaseHttpRequestOptions;

View File

@ -27,4 +27,4 @@
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/latest/RESTAPI.html" />
* @author Adrian Cole
*/
package org.jclouds.aws.s3.commands.options;
package org.jclouds.aws.s3.options;

View File

@ -22,7 +22,7 @@
* ====================================================================
*/
/**
* This package contains an Amazon S3 client implemented by {@link org.jclouds.http.HttpFutureCommandClient} commands.
* This package contains an Amazon S3 client implemented by {@link org.jclouds.http.HttpCommandExecutorService} commands.
*
* @see <a href="http://aws.amazon.com/s3"/>
* @author Adrian Cole

View File

@ -38,5 +38,9 @@ public interface S3Constants extends AWSConstants, S3Headers, ObjectStoreConstan
*/
public static final String S3_REST_API_XML_NAMESPACE = "http://s3.amazonaws.com/doc/2006-03-01/";
public static final String ENDPOINT = "Endpoint";
public static final String PREFIX = "prefix";
public static final String MARKER = "marker";
public static final String MAX_KEYS = "max-keys";
public static final String DELIMITER = "delimiter";
}

View File

@ -23,33 +23,31 @@
*/
package org.jclouds.aws.s3.reference;
import org.jclouds.http.HttpHeaders;
/**
* Additional headers specified by Amazon S3 REST API.
*
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/latest/index.html?RESTAuthentication.html"
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/latest/index.html?RESTAuthentication.html"
* />
* @author Adrian Cole
*
*/
public interface S3Headers extends HttpHeaders {
public interface S3Headers {
/**
* The canned ACL to apply to the object. Options include private,
* public-read, public-read-write, and authenticated-read. For more
* information, see REST Access Control Policy.
*/
public static final String CANNED_ACL = "x-amz-acl";
/**
* Any header starting with this prefix is considered user metadata. It will
* be stored with the object and returned when you retrieve the object. The
* total size of the HTTP request, not including the body, must be less than
* 8 KB.
*/
public static final String USER_METADATA_PREFIX = "x-amz-meta-";
public static final String AMZ_MD5 = "x-amz-meta-object-md5";
public static final String REQUEST_ID = "x-amz-request-id";
public static final String REQUEST_TOKEN = "x-amz-id-2";
/**
* The canned ACL to apply to the object. Options include private, public-read,
* public-read-write, and authenticated-read. For more information, see REST Access Control
* Policy.
*/
public static final String CANNED_ACL = "x-amz-acl";
/**
* Any header starting with this prefix is considered user metadata. It will be stored with the
* object and returned when you retrieve the object. The total size of the HTTP request, not
* including the body, must be less than 8 KB.
*/
public static final String USER_METADATA_PREFIX = "x-amz-meta-";
public static final String AMZ_MD5 = "x-amz-meta-object-eTag";
public static final String REQUEST_ID = "x-amz-request-id";
public static final String REQUEST_TOKEN = "x-amz-id-2";
}

View File

@ -27,45 +27,45 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.jclouds.aws.domain.AWSError;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.filters.RequestAuthorizeSignature;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.aws.s3.xml.S3ParserFactory;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpFutureCommand;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpUtils;
import org.jclouds.util.Utils;
import com.google.inject.Inject;
/**
* Encryption, Hashing, and IO Utilities needed to sign and verify S3 requests and responses.
*
* @author Adrian Cole
*/
public class S3Utils extends AWSUtils {
public class S3Utils {
public static AWSError parseAWSErrorFromContent(S3ParserFactory parserFactory,
HttpFutureCommand<?> command, HttpResponse response, InputStream content)
throws HttpException {
@Inject
RequestAuthorizeSignature signer;
public AWSError parseAWSErrorFromContent(S3ParserFactory parserFactory, HttpCommand command,
HttpResponse response, InputStream content) throws HttpException {
AWSError error = parserFactory.createErrorParser().parse(content);
error.setRequestId(response.getFirstHeaderOrNull(S3Headers.REQUEST_ID));
error.setRequestToken(response.getFirstHeaderOrNull(S3Headers.REQUEST_TOKEN));
if ("SignatureDoesNotMatch".equals(error.getCode()))
error.setStringSigned(RequestAuthorizeSignature.createStringToSign(command.getRequest()));
error.setStringSigned(signer.createStringToSign(command.getRequest()));
return error;
}
public static AWSError parseAWSErrorFromContent(S3ParserFactory parserFactory,
HttpFutureCommand<?> command, HttpResponse response, String content)
throws HttpException {
public AWSError parseAWSErrorFromContent(S3ParserFactory parserFactory, HttpCommand command,
HttpResponse response, String content) throws HttpException {
return parseAWSErrorFromContent(parserFactory, command, response, new ByteArrayInputStream(
content.getBytes()));
}
@ -79,88 +79,18 @@ public class S3Utils extends AWSUtils {
"bucketName name can only contain lowercase letters, numbers, periods (.), underscores (_), and dashes (-)");
checkArgument(bucketName.length() > 2 && bucketName.length() < 256,
"bucketName name must be between 3 and 255 characters long");
checkArgument(!IP_PATTERN.matcher(bucketName).matches(),
checkArgument(!HttpUtils.IP_PATTERN.matcher(bucketName).matches(),
"bucketName name cannot be ip address style");
return bucketName;
}
public static long calculateSize(Object data) {
long size = -1;
if (data instanceof byte[]) {
size = ((byte[]) data).length;
} else if (data instanceof String) {
size = ((String) data).length();
} else if (data instanceof File) {
size = ((File) data).length();
}
return size;
}
/**
* @throws IOException
*/
public static byte[] md5(Object data) throws IOException {
checkNotNull(data, "data must be set before calling generateMd5()");
byte[] md5 = null;
if (data == null) {
} else if (data instanceof byte[]) {
md5 = S3Utils.md5((byte[]) data);
} else if (data instanceof String) {
md5 = S3Utils.md5(((String) data).getBytes());
} else if (data instanceof File) {
md5 = S3Utils.md5(((File) data));
} else {
throw new UnsupportedOperationException("Content not supported " + data.getClass());
}
return md5;
}
public static Md5InputStreamResult generateMd5Result(InputStream toEncode) throws IOException {
MD5Digest md5 = new MD5Digest();
byte[] resBuf = new byte[md5.getDigestSize()];
byte[] buffer = new byte[1024];
ByteArrayOutputStream out = new ByteArrayOutputStream();
long length = 0;
int numRead = -1;
try {
do {
numRead = toEncode.read(buffer);
if (numRead > 0) {
length += numRead;
md5.update(buffer, 0, numRead);
out.write(buffer, 0, numRead);
}
} while (numRead != -1);
} finally {
out.close();
IOUtils.closeQuietly(toEncode);
}
md5.doFinal(resBuf, 0);
return new Md5InputStreamResult(out.toByteArray(), resBuf, length);
}
public static class Md5InputStreamResult {
public final byte[] data;
public final byte[] md5;
public final long length;
Md5InputStreamResult(byte[] data, byte[] md5, long length) {
this.data = checkNotNull(data, "data");
this.md5 = checkNotNull(md5, "md5");
checkArgument(length >= 0, "length cannot me negative");
this.length = length;
}
}
public static String getContentAsStringAndClose(S3Object object) throws IOException {
checkNotNull(object, "s3Object");
checkNotNull(object.getData(), "s3Object.content");
Object o = object.getData();
if (o instanceof InputStream) {
String returnVal = toStringAndClose((InputStream) o);
String returnVal = Utils.toStringAndClose((InputStream) o);
if (object.getMetadata().getContentType().indexOf("xml") >= 0) {
}

View File

@ -1,75 +0,0 @@
package org.jclouds.aws.s3.xml;
import java.util.Properties;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.AccessControlList.CanonicalUserGrantee;
import org.jclouds.aws.s3.domain.AccessControlList.EmailAddressGrantee;
import org.jclouds.aws.s3.domain.AccessControlList.Grant;
import org.jclouds.aws.s3.domain.AccessControlList.GroupGrantee;
import org.jclouds.aws.s3.reference.S3Constants;
import org.w3c.dom.Document;
import com.jamesmurty.utils.XMLBuilder;
public class AccessControlListBuilder {
private final AccessControlList acl;
public AccessControlListBuilder(AccessControlList acl) {
this.acl = acl;
}
protected XMLBuilder generateBuilder() throws ParserConfigurationException,
FactoryConfigurationError
{
XMLBuilder ownerBuilder = XMLBuilder
.create("AccessControlPolicy").attr("xmlns", S3Constants.S3_REST_API_XML_NAMESPACE)
.elem("Owner");
if (acl.getOwner() != null) {
ownerBuilder.elem("ID").text(acl.getOwner().getId()).up();
if (acl.getOwner().getDisplayName() != null) {
ownerBuilder.elem("DisplayName").text(acl.getOwner().getDisplayName()).up();
}
}
XMLBuilder grantsBuilder = ownerBuilder.root().elem("AccessControlList");
for (Grant grant : acl.getGrants()) {
XMLBuilder grantBuilder = grantsBuilder.elem("Grant");
XMLBuilder granteeBuilder = grantBuilder
.elem("Grantee").attr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
if (grant.getGrantee() instanceof GroupGrantee) {
granteeBuilder.attr("xsi:type", "Group")
.elem("URI").text(grant.getGrantee().getIdentifier());
} else if (grant.getGrantee() instanceof CanonicalUserGrantee) {
CanonicalUserGrantee grantee = (CanonicalUserGrantee) grant.getGrantee();
granteeBuilder.attr("xsi:type", "CanonicalUser")
.elem("ID").text(grantee.getIdentifier()).up();
if (grantee.getDisplayName() != null) {
granteeBuilder.elem("DisplayName").text(grantee.getDisplayName());
}
} else if (grant.getGrantee() instanceof EmailAddressGrantee) {
granteeBuilder.attr("xsi:type", "AmazonCustomerByEmail")
.elem("EmailAddress").text(grant.getGrantee().getIdentifier());
}
grantBuilder.elem("Permission").text(grant.getPermission().toString());
}
return grantsBuilder;
}
public Document getDocument() throws ParserConfigurationException, FactoryConfigurationError {
return generateBuilder().getDocument();
}
public String getXmlString() throws TransformerException, ParserConfigurationException,
FactoryConfigurationError
{
Properties outputProperties = new Properties();
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
return generateBuilder().asString(outputProperties);
}
}

View File

@ -31,7 +31,7 @@ import org.jclouds.aws.s3.domain.AccessControlList.Grantee;
import org.jclouds.aws.s3.domain.AccessControlList.GroupGrantee;
import org.jclouds.aws.s3.domain.AccessControlList.GroupGranteeURI;
import org.jclouds.aws.s3.domain.AccessControlList.Permission;
import org.jclouds.http.commands.callables.xml.ParseSax;
import org.jclouds.http.functions.ParseSax;
import org.xml.sax.Attributes;
/**

View File

@ -24,9 +24,9 @@
package org.jclouds.aws.s3.xml;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.aws.util.DateService;
import org.jclouds.http.commands.callables.xml.ParseSax;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.DateService;
import com.google.inject.Inject;
@ -40,22 +40,18 @@ import com.google.inject.Inject;
*/
public class CopyObjectHandler extends ParseSax.HandlerWithResult<S3Object.Metadata> {
private S3Object.Metadata metadata;
private S3Object.Metadata metadata = new S3Object.Metadata();
private StringBuilder currentText = new StringBuilder();
@Inject
private DateService dateParser;
public void setKey(String key) {
metadata = new S3Object.Metadata(key);
}
public S3Object.Metadata getResult() {
return metadata;
}
public void endElement(String uri, String name, String qName) {
if (qName.equals("ETag")) {
metadata.setMd5(S3Utils.fromHexString(currentText.toString().replaceAll("\"", "")));
metadata.setETag(HttpUtils.fromHexString(currentText.toString().replaceAll("\"", "")));
} else if (qName.equals("LastModified")) {
metadata.setLastModified(dateParser.iso8601DateParse(currentText.toString()));
}

View File

@ -28,8 +28,8 @@ import java.util.List;
import org.jclouds.aws.s3.domain.CanonicalUser;
import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.aws.util.DateService;
import org.jclouds.http.commands.callables.xml.ParseSax;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.DateService;
import com.google.inject.Inject;

View File

@ -23,14 +23,12 @@
*/
package org.jclouds.aws.s3.xml;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.aws.s3.domain.CanonicalUser;
import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.aws.util.DateService;
import org.jclouds.http.commands.callables.xml.ParseSax;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.DateService;
import org.xml.sax.Attributes;
import com.google.inject.Inject;
@ -56,16 +54,13 @@ public class ListBucketHandler extends ParseSax.HandlerWithResult<S3Bucket> {
@Inject
public ListBucketHandler(DateService dateParser) {
this.dateParser = dateParser;
this.s3Bucket = new S3Bucket();
}
public S3Bucket getResult() {
return s3Bucket;
}
public void setBucketName(String bucketName) {
this.s3Bucket = new S3Bucket(checkNotNull(bucketName, "bucketName"));
}
private boolean inCommonPrefixes;
public void startElement(String uri, String name, String qName, Attributes attrs) {
@ -84,8 +79,8 @@ public class ListBucketHandler extends ParseSax.HandlerWithResult<S3Bucket> {
} else if (qName.equals("LastModified")) {
currentObjectMetadata.setLastModified(dateParser.iso8601DateParse(currentText.toString()));
} else if (qName.equals("ETag")) {
currentObjectMetadata.setMd5(S3Utils.fromHexString(currentText.toString().replaceAll("\"",
"")));
currentObjectMetadata.setETag(HttpUtils.fromHexString(currentText.toString().replaceAll(
"\"", "")));
} else if (qName.equals("Size")) {
currentObjectMetadata.setSize(Long.parseLong(currentText.toString()));
} else if (qName.equals("Owner")) {
@ -94,7 +89,8 @@ public class ListBucketHandler extends ParseSax.HandlerWithResult<S3Bucket> {
currentObjectMetadata.setStorageClass(currentText.toString());
} else if (qName.equals("Contents")) {
s3Bucket.getContents().add(currentObjectMetadata);
} else if (qName.equals("Name")) {// bucketName stuff last, as least likely
} else if (qName.equals("Name")) {
s3Bucket.setName(currentText.toString());
} else if (qName.equals("Prefix")) {
String prefix = currentText.toString().trim();
if (inCommonPrefixes)

View File

@ -30,7 +30,7 @@ import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.S3Bucket;
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.functions.ParseSax;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;

View File

@ -35,9 +35,8 @@ import org.jclouds.aws.s3.xml.ListAllMyBucketsHandler;
import org.jclouds.aws.s3.xml.ListBucketHandler;
import org.jclouds.aws.s3.xml.S3ParserFactory;
import org.jclouds.aws.xml.ErrorHandler;
import org.jclouds.command.ConfiguresResponseParser;
import org.jclouds.http.commands.callables.xml.ParseSax;
import org.jclouds.http.commands.callables.xml.config.SaxModule;
import org.jclouds.command.ConfiguresResponseTransformer;
import org.jclouds.http.functions.ParseSax;
import com.google.inject.AbstractModule;
import com.google.inject.TypeLiteral;
@ -48,7 +47,7 @@ import com.google.inject.assistedinject.FactoryProvider;
*
* @author Adrian Cole
*/
@ConfiguresResponseParser
@ConfiguresResponseTransformer
public class S3ParserModule extends AbstractModule {
protected final TypeLiteral<S3ParserFactory.GenericParseFactory<AWSError>> errorTypeLiteral = new TypeLiteral<S3ParserFactory.GenericParseFactory<AWSError>>() {
};
@ -63,7 +62,6 @@ public class S3ParserModule extends AbstractModule {
@Override
protected void configure() {
install(new SaxModule());
bindErrorHandler();
bindCallablesThatReturnParseResults();
bindParserImplementationsToReturnTypes();

View File

@ -176,7 +176,7 @@ public abstract class BaseS3MapIntegrationTest<T> extends S3IntegrationTest {
}
/**
* containsValue() uses md5 comparison to bucket contents, so this can be subject to eventual
* containsValue() uses eTag comparison to bucket contents, so this can be subject to eventual
* consistency problems.
*/
protected void assertEventuallyContainsValue(final BaseS3Map<T> map, final Object value)

View File

@ -32,7 +32,7 @@ import java.net.URLConnection;
import java.util.concurrent.TimeUnit;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.http.HttpUtils;
import org.testng.annotations.Optional;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
@ -46,22 +46,22 @@ import org.testng.annotations.Test;
public class S3ConnectionLiveTest extends S3IntegrationTest {
private static final String sysHttpStreamUrl = System.getProperty("jclouds.s3.httpstream.url");
private static final String sysHttpStreamMd5 = System.getProperty("jclouds.s3.httpstream.md5");
private static final String sysHttpStreamETag = System.getProperty("jclouds.s3.httpstream.eTag");
@Test
@Parameters( { "jclouds.s3.httpstream.url", "jclouds.s3.httpstream.md5" })
public void testCopyUrl(@Optional String httpStreamUrl, @Optional String httpStreamMd5)
@Parameters( { "jclouds.s3.httpstream.url", "jclouds.s3.httpstream.eTag" })
public void testCopyUrl(@Optional String httpStreamUrl, @Optional String httpStreamETag)
throws Exception {
httpStreamUrl = checkNotNull(httpStreamUrl != null ? httpStreamUrl : sysHttpStreamUrl,
"httpStreamUrl");
httpStreamMd5 = checkNotNull(httpStreamMd5 != null ? httpStreamMd5 : sysHttpStreamMd5,
"httpStreamMd5");
httpStreamETag = checkNotNull(httpStreamETag != null ? httpStreamETag : sysHttpStreamETag,
"httpStreamETag");
String key = "hello";
URL url = new URL(httpStreamUrl);
byte[] md5 = S3Utils.fromHexString(httpStreamMd5);
byte[] eTag = HttpUtils.fromHexString(httpStreamETag);
URLConnection connection = url.openConnection();
int length = connection.getContentLength();
@ -69,12 +69,12 @@ public class S3ConnectionLiveTest extends S3IntegrationTest {
S3Object object = new S3Object(key, input);
object.setContentLength(length);
object.getMetadata().setMd5(md5);
object.getMetadata().setETag(eTag);
object.getMetadata().setSize(length);
String bucketName = getBucketName();
try {
byte[] newMd5 = client.putObject(bucketName, object).get(30, TimeUnit.SECONDS);
assertEquals(newMd5, md5);
byte[] newETag = client.putObject(bucketName, object).get(30, TimeUnit.SECONDS);
assertEquals(newETag, eTag);
} finally {
returnBucket(bucketName);
}

View File

@ -31,7 +31,7 @@ import static org.testng.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import org.jclouds.aws.s3.config.LiveS3ConnectionModule;
import org.jclouds.aws.s3.config.RestS3ConnectionModule;
import org.jclouds.aws.s3.config.S3ContextModule;
import org.jclouds.aws.s3.internal.GuiceS3Context;
import org.jclouds.aws.s3.xml.config.S3ParserModule;
@ -88,7 +88,7 @@ public class S3ContextBuilderTest {
S3ContextBuilder builder = S3ContextBuilder.newBuilder("id", "secret");
builder.addConnectionModule(modules);
assertEquals(modules.size(), 1);
assertEquals(modules.get(0).getClass(), LiveS3ConnectionModule.class);
assertEquals(modules.get(0).getClass(), RestS3ConnectionModule.class);
}
}

View File

@ -23,7 +23,7 @@
*/
package org.jclouds.aws.s3;
import static org.jclouds.aws.s3.commands.options.PutBucketOptions.Builder.createIn;
import static org.jclouds.aws.s3.options.PutBucketOptions.Builder.createIn;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
@ -45,7 +45,8 @@ import org.jclouds.aws.s3.domain.S3Bucket.Metadata;
import org.jclouds.aws.s3.domain.S3Bucket.Metadata.LocationConstraint;
import org.jclouds.aws.s3.reference.S3Constants;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.http.config.JavaUrlHttpFutureCommandClientModule;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.util.Utils;
import org.testng.ITestContext;
@ -70,8 +71,8 @@ public class S3IntegrationTest {
protected static int bucketCount = 20;
protected static volatile int bucketIndex = 0;
protected byte[] goodMd5;
protected byte[] badMd5;
protected byte[] goodETag;
protected byte[] badETag;
protected S3Connection client;
protected S3Context context = null;
protected boolean SANITY_CHECK_RETURNED_BUCKET_NAME = false;
@ -169,8 +170,8 @@ public class S3IntegrationTest {
}
client = context.getConnection();
assert client != null;
goodMd5 = S3Utils.md5(TEST_STRING);
badMd5 = S3Utils.md5("alf");
goodETag = HttpUtils.eTag(TEST_STRING);
badETag = HttpUtils.eTag("alf");
}
protected void createStubS3Context() {
@ -179,8 +180,7 @@ public class S3IntegrationTest {
}
protected void createLiveS3Context(String AWSAccessKeyId, String AWSSecretAccessKey) {
context = S3ContextFactory.createS3Context(AWSAccessKeyId, AWSSecretAccessKey,
createHttpModule(), new Log4JLoggingModule());
context = buildS3ContextFactory(AWSAccessKeyId, AWSSecretAccessKey).buildContext();
}
public String getBucketName() throws InterruptedException, ExecutionException, TimeoutException {
@ -212,7 +212,7 @@ public class S3IntegrationTest {
* *substantially* slow down tests on a real server over a network.
*/
if (SANITY_CHECK_RETURNED_BUCKET_NAME) {
if (!Iterables.any(client.listOwnedBuckets().get(), new Predicate<Metadata>() {
if (!Iterables.any(client.listOwnedBuckets(), new Predicate<Metadata>() {
public boolean apply(Metadata md) {
return bucketName.equals(md.getName());
}
@ -262,16 +262,16 @@ public class S3IntegrationTest {
protected S3ContextBuilder buildS3ContextFactory(String AWSAccessKeyId, String AWSSecretAccessKey) {
return (S3ContextBuilder) S3ContextBuilder.newBuilder(AWSAccessKeyId, AWSSecretAccessKey)
.withSaxDebug().withHttpSecure(false).withHttpPort(80);
.withSaxDebug().relaxSSLHostname().withModule(new Log4JLoggingModule());
}
protected Module createHttpModule() {
return new JavaUrlHttpFutureCommandClientModule();
return new JavaUrlHttpCommandExecutorServiceModule();
}
protected void deleteEverything() throws Exception {
try {
List<S3Bucket.Metadata> metadata = client.listOwnedBuckets().get(10, TimeUnit.SECONDS);
List<S3Bucket.Metadata> metadata = client.listOwnedBuckets();
for (S3Bucket.Metadata metaDatum : metadata) {
if (metaDatum.getName().startsWith(bucketPrefix.toLowerCase())) {
deleteBucket(metaDatum.getName());
@ -287,7 +287,7 @@ public class S3IntegrationTest {
*/
protected void emptyBucket(final String name) throws InterruptedException, ExecutionException,
TimeoutException {
if (client.bucketExists(name).get(10, TimeUnit.SECONDS)) {
if (client.bucketExists(name)) {
// This can fail to be zero length because of stale bucket lists. Ex. client.listBucket()
// could return 9 keys, when there are 10. When all the deletions finish, one entry would
// be left in this case. Instead of failing, we will attempt this entire bucket deletion
@ -331,9 +331,9 @@ public class S3IntegrationTest {
*/
protected void deleteBucket(String name) throws InterruptedException, ExecutionException,
TimeoutException {
if (client.bucketExists(name).get(10, TimeUnit.SECONDS)) {
if (client.bucketExists(name)) {
emptyBucket(name);
client.deleteBucketIfEmpty(name).get(10, TimeUnit.SECONDS);
client.deleteBucketIfEmpty(name);
}
}

View File

@ -123,7 +123,7 @@ public class S3ObjectMapIntegrationTest extends BaseS3MapIntegrationTest<S3Objec
.get(entry.getKey()));
S3Object value = entry.getValue();
value.setData("");
value.generateMd5();
value.generateETag();
entry.setValue(value);
}
assertEventuallyMapSize(map, 5);
@ -171,11 +171,11 @@ public class S3ObjectMapIntegrationTest extends BaseS3MapIntegrationTest<S3Objec
BaseS3Map<S3Object> map = createMap(context, bucketName);
S3Object object = new S3Object("one");
object.setData(IOUtils.toInputStream("apple"));
object.generateMd5();
object.generateETag();
S3Object old = map.put(object.getKey(), object);
getOneReturnsAppleAndOldValueIsNull(map, old);
object.setData(IOUtils.toInputStream("bear"));
object.generateMd5();
object.generateETag();
S3Object apple = map.put(object.getKey(), object);
getOneReturnsBearAndOldValueIsApple(map, apple);
} finally {

View File

@ -1,127 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.bouncycastle.util.encoders.Base64;
import org.jclouds.aws.PerformanceTest;
import org.jclouds.aws.s3.util.S3Utils;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
/**
* This tests the performance of Digest commands.
*
* @author Adrian Cole
*/
@Test(groups = "performance", sequential = true, testName = "s3.S3UtilsTest")
public class S3UtilsTest extends PerformanceTest {
@Test(dataProvider = "hmacsha1")
void testBouncyCastleDigestSerialResponseTime(byte[] key, String message,
String base64Digest) throws NoSuchProviderException,
NoSuchAlgorithmException, InvalidKeyException {
for (int i = 0; i < 10000; i++)
testBouncyCastleHmacSha1Base64(key, message, base64Digest);
}
@Test(dataProvider = "hmacsha1")
void testBouncyCastleDigestParallelResponseTime(final byte[] key,
final String message, final String base64Digest)
throws NoSuchProviderException, NoSuchAlgorithmException,
InvalidKeyException, InterruptedException, ExecutionException {
CompletionService<Boolean> completer = new ExecutorCompletionService<Boolean>(
exec);
for (int i = 0; i < 10000; i++)
completer.submit(new Callable<Boolean>() {
public Boolean call() throws Exception {
testBouncyCastleHmacSha1Base64(key, message, base64Digest);
return true;
}
});
for (int i = 0; i < 10000; i++)
assert completer.take().get();
}
@DataProvider(name = "md5")
public Object[][] createMD5Data() {
return base64MD5MessageDigest;
}
public final static Object[][] base64MD5MessageDigest = {
{"apple", "1f3870be274f6c49b3e31a0c6728957f"},
{"bear", "893b56e3cfe153fb770a120b83bac20c"},
{"candy", "c48ba993d35c3abe0380f91738fe2a34"},
{"dogma", "95eb470e4faee302e9cd3063b1923dab"},
{"emma", "00a809937eddc44521da9521269e75c6"}};
public final static Object[][] base64KeyMessageDigest = {
{Base64.decode("CwsLCwsLCwsLCwsLCwsLCwsLCws="), "Hi There",
"thcxhlUFcmTii8C2+zeMjvFGvgA="},
{Base64.decode("SmVmZQ=="), "what do ya want for nothing?",
"7/zfauXrL6LSdBbV8YTfnCWafHk="},
{Base64.decode("DAwMDAwMDAwMDAwMDAwMDAwMDAw="),
"Test With Truncation", "TBoDQktV4H/n8nvh1Yu5MkqaWgQ="},
{
Base64
.decode("qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo="),
"Test Using Larger Than Block-Size Key - Hash Key First",
"qkrl4VJy0A6VcFY3zoo7Ve1AIRI="},
{
Base64
.decode("qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo="),
"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
"6OmdD0UjfXhta7qnllx4CLv/GpE="}};
@DataProvider(name = "hmacsha1")
public Object[][] createData1() {
return base64KeyMessageDigest;
}
@Test(dataProvider = "hmacsha1")
public void testBouncyCastleHmacSha1Base64(byte[] key, String message,
String base64Digest) throws NoSuchProviderException,
NoSuchAlgorithmException, InvalidKeyException {
String b64 = S3Utils.hmacSha1Base64(message, key);
assertEquals(b64, base64Digest);
}
@Test(dataProvider = "md5")
public void testBouncyCastleMD5Digest(String message,
String base64Digest) throws NoSuchProviderException,
NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
String b64 = S3Utils.md5Hex(message.getBytes());
assertEquals(base64Digest, b64);
}
}

View File

@ -23,8 +23,6 @@
*/
package org.jclouds.aws.s3.commands;
import java.util.concurrent.TimeUnit;
import org.jclouds.aws.s3.S3IntegrationTest;
import org.testng.annotations.Test;
@ -40,14 +38,14 @@ public class BucketExistsIntegrationTest extends S3IntegrationTest {
@Test
void bucketDoesntExist() throws Exception {
assert !client.bucketExists("be").get(10, TimeUnit.SECONDS);
assert !client.bucketExists("be");
}
@Test
void bucketExists() throws Exception {
String bucketName = getBucketName();
try {
assert client.bucketExists(bucketName).get(10, TimeUnit.SECONDS);
assert client.bucketExists(bucketName);
} finally {
returnBucket(bucketName);
}

View File

@ -23,11 +23,11 @@
*/
package org.jclouds.aws.s3.commands;
import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.ifSourceMd5DoesntMatch;
import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.ifSourceMd5Matches;
import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.ifSourceModifiedSince;
import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.ifSourceUnmodifiedSince;
import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.overrideMetadataWith;
import static org.jclouds.aws.s3.options.CopyObjectOptions.Builder.ifSourceETagDoesntMatch;
import static org.jclouds.aws.s3.options.CopyObjectOptions.Builder.ifSourceETagMatches;
import static org.jclouds.aws.s3.options.CopyObjectOptions.Builder.ifSourceModifiedSince;
import static org.jclouds.aws.s3.options.CopyObjectOptions.Builder.ifSourceUnmodifiedSince;
import static org.jclouds.aws.s3.options.CopyObjectOptions.Builder.overrideMetadataWith;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
@ -148,12 +148,12 @@ public class CopyObjectIntegrationTest extends S3IntegrationTest {
addToBucketAndValidate(bucketName, sourceKey);
client.copyObject(bucketName, sourceKey, destinationBucket, destinationKey,
ifSourceMd5Matches(goodMd5)).get(10, TimeUnit.SECONDS);
ifSourceETagMatches(goodETag)).get(10, TimeUnit.SECONDS);
validateContent(destinationBucket, destinationKey);
try {
client.copyObject(bucketName, sourceKey, destinationBucket, destinationKey,
ifSourceMd5Matches(badMd5)).get(10, TimeUnit.SECONDS);
ifSourceETagMatches(badETag)).get(10, TimeUnit.SECONDS);
} catch (ExecutionException e) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 412);
@ -173,12 +173,12 @@ public class CopyObjectIntegrationTest extends S3IntegrationTest {
addToBucketAndValidate(bucketName, sourceKey);
client.copyObject(bucketName, sourceKey, destinationBucket, destinationKey,
ifSourceMd5DoesntMatch(badMd5)).get(10, TimeUnit.SECONDS);
ifSourceETagDoesntMatch(badETag)).get(10, TimeUnit.SECONDS);
validateContent(destinationBucket, destinationKey);
try {
client.copyObject(bucketName, sourceKey, destinationBucket, destinationKey,
ifSourceMd5DoesntMatch(goodMd5)).get(10, TimeUnit.SECONDS);
ifSourceETagDoesntMatch(goodETag)).get(10, TimeUnit.SECONDS);
} catch (ExecutionException e) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 412);
@ -206,8 +206,7 @@ public class CopyObjectIntegrationTest extends S3IntegrationTest {
validateContent(destinationBucket, destinationKey);
S3Object.Metadata objectMeta = client.headObject(destinationBucket, destinationKey).get(
10, TimeUnit.SECONDS);
S3Object.Metadata objectMeta = client.headObject(destinationBucket, destinationKey);
assertEquals(objectMeta.getUserMetadata(), metadata);
} finally {

View File

@ -23,15 +23,16 @@
*/
package org.jclouds.aws.s3.commands;
import org.jclouds.aws.s3.S3IntegrationTest;
import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.overrideAcl;
import org.jclouds.aws.s3.domain.acl.CannedAccessPolicy;
import org.jclouds.aws.s3.util.S3Utils;
import org.testng.annotations.Test;
import static org.jclouds.aws.s3.options.CopyObjectOptions.Builder.overrideAcl;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import org.jclouds.aws.s3.S3IntegrationTest;
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
import org.jclouds.util.Utils;
import org.testng.annotations.Test;
/**
* Tests integrated functionality of all copyObject commands.
* <p/>
@ -59,7 +60,7 @@ public class CopyObjectLiveTest extends S3IntegrationTest {
URL url = new URL(String.format("http://%1$s.s3.amazonaws.com/%2$s", destinationBucket,
destinationKey));
S3Utils.toStringAndClose(url.openStream());
Utils.toStringAndClose(url.openStream());
} finally {
returnBucket(bucketName);

View File

@ -26,8 +26,6 @@ package org.jclouds.aws.s3.commands;
import org.jclouds.aws.s3.S3IntegrationTest;
import org.testng.annotations.Test;
import java.util.concurrent.TimeUnit;
/**
* Tests integrated functionality of all deleteBucket commands.
* <p/>
@ -43,7 +41,7 @@ public class DeleteBucketIntegrationTest extends S3IntegrationTest {
*/
@Test
void deleteBucketIfEmptyNotFound() throws Exception {
assert client.deleteBucketIfEmpty("dbienf").get(10, TimeUnit.SECONDS);
assert client.deleteBucketIfEmpty("dbienf");
}
@Test
@ -51,7 +49,7 @@ public class DeleteBucketIntegrationTest extends S3IntegrationTest {
String bucketName = getBucketName();
try {
addObjectToBucket(bucketName, "test");
assert !client.deleteBucketIfEmpty(bucketName).get(10, TimeUnit.SECONDS);
assert !client.deleteBucketIfEmpty(bucketName);
} finally {
returnBucket(bucketName);
}
@ -61,8 +59,8 @@ public class DeleteBucketIntegrationTest extends S3IntegrationTest {
void deleteBucketIfEmpty() throws Exception {
String bucketName = getScratchBucketName();
try {
assert client.deleteBucketIfEmpty(bucketName).get(10, TimeUnit.SECONDS);
assert !client.bucketExists(bucketName).get(10, TimeUnit.SECONDS);
assert client.deleteBucketIfEmpty(bucketName);
assert !client.bucketExists(bucketName);
} finally {
returnScratchBucket(bucketName);
}

View File

@ -33,12 +33,12 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.aws.s3.S3IntegrationTest;
import org.jclouds.aws.s3.commands.options.PutObjectOptions;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.domain.AccessControlList.GroupGranteeURI;
import org.jclouds.aws.s3.domain.AccessControlList.Permission;
import org.jclouds.aws.s3.domain.acl.CannedAccessPolicy;
import org.jclouds.aws.s3.options.PutObjectOptions;
import org.testng.annotations.Test;
/**

View File

@ -23,13 +23,13 @@
*/
package org.jclouds.aws.s3.commands;
import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.ifMd5DoesntMatch;
import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.ifMd5Matches;
import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.ifModifiedSince;
import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.ifUnmodifiedSince;
import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.range;
import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.startAt;
import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.tail;
import static org.jclouds.http.options.GetOptions.Builder.ifETagDoesntMatch;
import static org.jclouds.http.options.GetOptions.Builder.ifETagMatches;
import static org.jclouds.http.options.GetOptions.Builder.ifModifiedSince;
import static org.jclouds.http.options.GetOptions.Builder.ifUnmodifiedSince;
import static org.jclouds.http.options.GetOptions.Builder.range;
import static org.jclouds.http.options.GetOptions.Builder.startAt;
import static org.jclouds.http.options.GetOptions.Builder.tail;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
@ -130,11 +130,11 @@ public class GetObjectIntegrationTest extends S3IntegrationTest {
addObjectAndValidateContent(bucketName, key);
client.getObject(bucketName, key, ifMd5Matches(goodMd5)).get(10, TimeUnit.SECONDS);
client.getObject(bucketName, key, ifETagMatches(goodETag)).get(10, TimeUnit.SECONDS);
validateContent(bucketName, key);
try {
client.getObject(bucketName, key, ifMd5Matches(badMd5)).get(10, TimeUnit.SECONDS);
client.getObject(bucketName, key, ifETagMatches(badETag)).get(10, TimeUnit.SECONDS);
validateContent(bucketName, key);
} catch (ExecutionException e) {
if (e.getCause() instanceof HttpResponseException) {
@ -161,11 +161,11 @@ public class GetObjectIntegrationTest extends S3IntegrationTest {
addObjectAndValidateContent(bucketName, key);
client.getObject(bucketName, key, ifMd5DoesntMatch(badMd5)).get(10, TimeUnit.SECONDS);
client.getObject(bucketName, key, ifETagDoesntMatch(badETag)).get(10, TimeUnit.SECONDS);
validateContent(bucketName, key);
try {
client.getObject(bucketName, key, ifMd5DoesntMatch(goodMd5)).get(10, TimeUnit.SECONDS);
client.getObject(bucketName, key, ifETagDoesntMatch(goodETag)).get(10, TimeUnit.SECONDS);
validateContent(bucketName, key);
} catch (ExecutionException e) {
if (e.getCause() instanceof HttpResponseException) {

View File

@ -24,7 +24,9 @@
package org.jclouds.aws.s3.commands;
import org.jclouds.aws.s3.S3IntegrationTest;
import static org.jclouds.aws.s3.commands.options.ListBucketOptions.Builder.*;
import static org.jclouds.aws.s3.options.ListBucketOptions.Builder.*;
import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.aws.s3.domain.S3Object;
import static org.testng.Assert.assertEquals;

View File

@ -24,7 +24,6 @@
package org.jclouds.aws.s3.commands;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.jclouds.aws.s3.S3IntegrationTest;
import org.jclouds.aws.s3.domain.S3Bucket;
@ -42,7 +41,7 @@ public class ListOwnedBucketsIntegrationTest extends S3IntegrationTest {
@Test()
void bucketDoesntExist() throws Exception {
List<S3Bucket.Metadata> list = client.listOwnedBuckets().get(10, TimeUnit.SECONDS);
List<S3Bucket.Metadata> list = client.listOwnedBuckets();
assert !list.contains(new S3Bucket("shouldntexist"));
}
@ -50,7 +49,7 @@ public class ListOwnedBucketsIntegrationTest extends S3IntegrationTest {
void bucketExists() throws Exception {
String bucketName = getBucketName();
try {
List<S3Bucket.Metadata> list = client.listOwnedBuckets().get(10, TimeUnit.SECONDS);
List<S3Bucket.Metadata> list = client.listOwnedBuckets();
S3Bucket.Metadata firstBucket = list.get(0);
S3Bucket.Metadata toMatch = new S3Bucket.Metadata(bucketName);
toMatch.setOwner(firstBucket.getOwner());

View File

@ -23,18 +23,19 @@
*/
package org.jclouds.aws.s3.commands;
import org.jclouds.aws.s3.S3IntegrationTest;
import static org.jclouds.aws.s3.commands.options.PutBucketOptions.Builder.createIn;
import static org.jclouds.aws.s3.commands.options.PutBucketOptions.Builder.withBucketAcl;
import org.jclouds.aws.s3.domain.S3Bucket.Metadata.LocationConstraint;
import org.jclouds.aws.s3.domain.acl.CannedAccessPolicy;
import org.jclouds.aws.s3.util.S3Utils;
import org.testng.annotations.Test;
import static org.jclouds.aws.s3.options.PutBucketOptions.Builder.createIn;
import static org.jclouds.aws.s3.options.PutBucketOptions.Builder.withBucketAcl;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import org.jclouds.aws.s3.S3IntegrationTest;
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
import org.jclouds.aws.s3.domain.S3Bucket.Metadata.LocationConstraint;
import org.jclouds.util.Utils;
import org.testng.annotations.Test;
/**
* Tests integrated functionality of all PutBucket commands.
* <p/>
@ -53,7 +54,7 @@ public class PutBucketLiveTest extends S3IntegrationTest {
client.putBucketIfNotExists(bucketName, withBucketAcl(CannedAccessPolicy.PUBLIC_READ))
.get(10, TimeUnit.SECONDS);
URL url = new URL(String.format("http://%1$s.s3.amazonaws.com", bucketName));
S3Utils.toStringAndClose(url.openStream());
Utils.toStringAndClose(url.openStream());
} finally {
returnScratchBucket(bucketName);
}
@ -74,7 +75,7 @@ public class PutBucketLiveTest extends S3IntegrationTest {
String bucketName = getBucketName();
try {
URL url = new URL(String.format("http://%1$s.s3.amazonaws.com", bucketName));
S3Utils.toStringAndClose(url.openStream());
Utils.toStringAndClose(url.openStream());
} finally {
returnBucket(bucketName);
}
@ -90,10 +91,10 @@ public class PutBucketLiveTest extends S3IntegrationTest {
try {
deleteBucket(bucketName);
client.putBucketIfNotExists(bucketName,
createIn(LocationConstraint.EU).withBucketAcl(CannedAccessPolicy.PUBLIC_READ)).get(
10, TimeUnit.SECONDS);
URL url = new URL(String.format("http://%1$s.s3.amazonaws.com", bucketName));
S3Utils.toStringAndClose(url.openStream());
createIn(LocationConstraint.EU).withBucketAcl(CannedAccessPolicy.PUBLIC_READ))
.get(10, TimeUnit.SECONDS);
URL url = new URL(String.format("http://%s.s3.amazonaws.com", bucketName));
Utils.toStringAndClose(url.openStream());
} finally {
returnScratchBucket(bucketName);
}

View File

@ -37,6 +37,7 @@ 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.jclouds.http.HttpUtils;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@ -65,7 +66,7 @@ public class PutObjectIntegrationTest extends S3IntegrationTest {
object.getMetadata().setContentType(type);
object.setData(content);
if (content instanceof InputStream) {
object.generateMd5();
object.generateETag();
}
String bucketName = getBucketName();
try {
@ -92,7 +93,7 @@ public class PutObjectIntegrationTest extends S3IntegrationTest {
object.getMetadata().setContentDisposition("attachment; filename=hello.txt");
object.getMetadata().getUserMetadata().put(S3Headers.USER_METADATA_PREFIX + "adrian",
"powderpuff");
object.getMetadata().setMd5(S3Utils.md5(TEST_STRING.getBytes()));
object.getMetadata().setETag(HttpUtils.eTag(TEST_STRING.getBytes()));
String bucketName = getBucketName();
try {
addObjectToBucket(bucketName, object);
@ -106,7 +107,7 @@ public class PutObjectIntegrationTest extends S3IntegrationTest {
assertEquals(newObject.getMetadata().getSize(), TEST_STRING.length());
assertEquals(newObject.getMetadata().getUserMetadata().values().iterator().next(),
"powderpuff");
assertEquals(newObject.getMetadata().getMd5(), S3Utils.md5(TEST_STRING.getBytes()));
assertEquals(newObject.getMetadata().getETag(), HttpUtils.eTag(TEST_STRING.getBytes()));
} finally {
returnBucket(bucketName);
}

View File

@ -23,15 +23,15 @@
*/
package org.jclouds.aws.s3.commands;
import static org.jclouds.aws.s3.commands.options.PutObjectOptions.Builder.withAcl;
import static org.jclouds.aws.s3.options.PutObjectOptions.Builder.withAcl;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import org.jclouds.aws.s3.S3IntegrationTest;
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.domain.acl.CannedAccessPolicy;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.util.Utils;
import org.testng.annotations.Test;
/**
@ -55,7 +55,7 @@ public class PutObjectLiveTest extends S3IntegrationTest {
withAcl(CannedAccessPolicy.PUBLIC_READ)).get(10, TimeUnit.SECONDS);
URL url = new URL(String.format("http://%1$s.s3.amazonaws.com/%2$s", bucketName, key));
S3Utils.toStringAndClose(url.openStream());
Utils.toStringAndClose(url.openStream());
} finally {
returnBucket(bucketName);
}

View File

@ -27,45 +27,36 @@ import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import java.util.concurrent.ExecutionException;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.domain.AWSError;
import org.jclouds.aws.s3.functions.ReturnTrueIfBucketAlreadyOwnedByYou;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(testName = "s3.PutBucketTest")
public class PutBucketTest {
@Test(testName = "s3.ReturnTrueIfBucketAlreadyOwnedByYouTest")
public class ReturnTrueIfBucketAlreadyOwnedByYouTest {
@Test
void testBucketAlreadyOwnedByYouIsOk() throws Exception {
ExecutionException e = getErrorWithCode("BucketAlreadyOwnedByYou");
assert PutBucket.eventualConsistencyAlreadyOwnedIsOk(e);
Exception e = getErrorWithCode("BucketAlreadyOwnedByYou");
assert new ReturnTrueIfBucketAlreadyOwnedByYou().apply(e);
}
@Test
void testBlahIsNotOk() throws Exception {
ExecutionException e = getErrorWithCode("blah");
try {
PutBucket.eventualConsistencyAlreadyOwnedIsOk(e);
assert false;
} catch (ExecutionException er) {
// don't try expectedExceptions as it will fail due to easymock reasons
}
Exception e = getErrorWithCode("blah");
assert new ReturnTrueIfBucketAlreadyOwnedByYou().apply(e) == null;
}
private ExecutionException getErrorWithCode(String code) {
private Exception getErrorWithCode(String code) {
AWSResponseException inner = createMock(AWSResponseException.class);
ExecutionException e = createMock(ExecutionException.class);
expect(e.getCause()).andReturn(inner).atLeastOnce();
AWSError error = createMock(AWSError.class);
expect(inner.getError()).andReturn(error);
expect(error.getCode()).andReturn(code);
replay(e);
replay(inner);
replay(error);
return e;
return inner;
}
}

View File

@ -1,155 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.commands;
import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import java.net.URI;
import org.jclouds.aws.s3.commands.config.S3CommandsModule;
import org.jclouds.aws.s3.commands.options.CopyObjectOptions;
import org.jclouds.aws.s3.commands.options.GetObjectOptions;
import org.jclouds.aws.s3.commands.options.ListBucketOptions;
import org.jclouds.aws.s3.commands.options.PutBucketOptions;
import org.jclouds.aws.s3.commands.options.PutObjectOptions;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.domain.S3Bucket.Metadata.LocationConstraint;
import org.jclouds.aws.s3.xml.config.S3ParserModule;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* @author Adrian Cole
*/
@Test(groups = { "unit" }, testName = "s3.S3CommandFactoryTest")
public class S3CommandFactoryTest {
Injector injector = null;
S3CommandFactory commandFactory = null;
@BeforeTest
void setUpInjector() {
injector = Guice.createInjector(new S3ParserModule(), new S3CommandsModule() {
@Override
protected void configure() {
bind(URI.class).toInstance(URI.create("http://localhost:8080"));
super.configure();
}
});
commandFactory = injector.getInstance(S3CommandFactory.class);
}
@AfterTest
void tearDownInjector() {
commandFactory = null;
injector = null;
}
@Test
void testCreateCopyObject() {
assert commandFactory.createCopyObject("sourcebucket", "sourceObject", "destbucket",
"destObject", CopyObjectOptions.NONE) != null;
}
@Test
void testCreateCopyObjectOptions() {
assert commandFactory.createCopyObject("sourcebucket", "sourceObject", "destbucket",
"destObject", new CopyObjectOptions()) != null;
}
@Test
void testCreateDeleteBucket() {
assert commandFactory.createDeleteBucket("test") != null;
}
@Test
void testCreateDeleteObject() {
assert commandFactory.createDeleteObject("test", "blah") != null;
}
@Test
void testCreateHeadBucket() {
assert commandFactory.createHeadBucket("test") != null;
}
@Test
void testCreatePutBucket() {
assert commandFactory.createPutBucket("test", PutBucketOptions.NONE) != null;
}
@Test
void testCreatePutBucketOptions() {
assert commandFactory.createPutBucket("test", PutBucketOptions.Builder
.createIn(LocationConstraint.EU)) != null;
}
@Test
void testCreatePutObject() {
S3Object.Metadata metadata = createMock(S3Object.Metadata.class);
S3Object object = new S3Object(metadata);
expect(metadata.getSize()).andReturn(4L).atLeastOnce();
expect(metadata.getKey()).andReturn("rawr");
expect(metadata.getContentType()).andReturn("text/xml").atLeastOnce();
expect(metadata.getCacheControl()).andReturn("no-cache").atLeastOnce();
expect(metadata.getContentDisposition()).andReturn("disposition").atLeastOnce();
expect(metadata.getContentEncoding()).andReturn("encoding").atLeastOnce();
expect(metadata.getMd5()).andReturn("encoding".getBytes()).atLeastOnce();
Multimap<String, String> userMdata = HashMultimap.create();
expect(metadata.getUserMetadata()).andReturn(userMdata).atLeastOnce();
replay(metadata);
object.setData("<a></a>");
assert commandFactory.createPutObject("test", object, PutObjectOptions.NONE) != null;
}
@Test
void testCreateGetObject() {
assert commandFactory.createGetObject("test", "blah", GetObjectOptions.NONE) != null;
}
@Test
void testCreateHeadMetadata() {
assert commandFactory.createHeadMetadata("test", "blah") != null;
}
@Test
void testCreateListAllMyBuckets() {
assert commandFactory.createGetMetadataForOwnedBuckets() != null;
}
@Test
void testCreateListBucket() {
assert commandFactory.createListBucket("test", ListBucketOptions.NONE) != null;
}
}

View File

@ -34,17 +34,16 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import org.apache.commons.io.IOUtils;
import org.jclouds.aws.PerformanceTest;
import org.jclouds.PerformanceTest;
import org.jclouds.aws.s3.domain.CanonicalUser;
import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.util.S3Utils;
import org.jclouds.aws.s3.xml.CopyObjectHandler;
import org.jclouds.aws.s3.xml.ListBucketHandler;
import org.jclouds.aws.s3.xml.S3ParserFactory;
import org.jclouds.aws.s3.xml.config.S3ParserModule;
import org.jclouds.http.HttpException;
import org.jclouds.http.commands.callables.xml.ParseSax;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.config.SaxModule;
import org.joda.time.DateTime;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
@ -69,7 +68,7 @@ public class S3ParserTest extends PerformanceTest {
@BeforeTest
protected void setUpInjector() {
injector = Guice.createInjector(new S3ParserModule());
injector = Guice.createInjector(new SaxModule(), new S3ParserModule());
parserFactory = injector.getInstance(S3ParserFactory.class);
assert parserFactory != null;
}
@ -138,7 +137,7 @@ public class S3ParserTest extends PerformanceTest {
DateTime expected = new DateTime("2009-03-12T02:00:13.000Z");
assert object.getLastModified().equals(expected) : String.format(
"expected %1$s, but got %1$s", expected, object.getLastModified());
assertEquals(S3Utils.toHexString(object.getMd5()), "9d7bb64e8e18ee34eec06dd2cf37b766");
assertEquals(HttpUtils.toHexString(object.getETag()), "9d7bb64e8e18ee34eec06dd2cf37b766");
assert object.getSize() == 136;
CanonicalUser owner = new CanonicalUser(
"e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0");
@ -149,8 +148,6 @@ public class S3ParserTest extends PerformanceTest {
private S3Bucket runParseListBucketResult() throws HttpException {
ParseSax<S3Bucket> parser = parserFactory.createListBucketParser();
ListBucketHandler handler = (ListBucketHandler) parser.getHandler();
handler.setBucketName("adrianjbosstest");
return parser.parse(IOUtils.toInputStream(listBucketResult));
}
@ -158,8 +155,6 @@ public class S3ParserTest extends PerformanceTest {
private S3Object.Metadata runParseCopyObjectResult() throws HttpException {
ParseSax<S3Object.Metadata> parser = parserFactory.createCopyObjectParser();
CopyObjectHandler handler = (CopyObjectHandler) parser.getHandler();
handler.setKey("adrianjbosstest");
return parser.parse(IOUtils.toInputStream(successfulCopyObject200));
}
@ -167,8 +162,7 @@ public class S3ParserTest extends PerformanceTest {
S3Object.Metadata metadata = runParseCopyObjectResult();
DateTime expected = new DateTime("2009-03-19T13:23:27.000Z");
assertEquals(metadata.getLastModified(), expected);
assertEquals(S3Utils.toHexString(metadata.getMd5()), "92836a3ea45a6984d1b4d23a747d46bb");
assertEquals(metadata.getKey(), "adrianjbosstest");
assertEquals(HttpUtils.toHexString(metadata.getETag()), "92836a3ea45a6984d1b4d23a747d46bb");
}
@Test

View File

@ -1,188 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.commands.options;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.aws.s3.commands.options.ListBucketOptions.Builder.*;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import java.io.UnsupportedEncodingException;
import org.jclouds.http.options.HttpRequestOptions;
import org.testng.annotations.Test;
/**
* Tests possible uses of ListBucketOptions and ListBucketOptions.Builder.*
*
* @author Adrian Cole
*/
public class ListBucketOptionsTest {
@Test
public void testPrefix() throws UnsupportedEncodingException {
ListBucketOptions options = new ListBucketOptions();
options.withPrefix("test");
assertEquals(options.getPrefix(), "test");
}
@Test
public void testNoOptionsQueryString() {
HttpRequestOptions options = new ListBucketOptions();
assertEquals(options.buildQueryString(), "");
}
@Test
public void testOneOptionQueryString() throws UnsupportedEncodingException {
ListBucketOptions options = new ListBucketOptions();
options.withPrefix("test");
assertEquals(options.buildQueryString(), "?prefix=test");
}
@Test
public void testTwoOptionQueryString() throws UnsupportedEncodingException {
ListBucketOptions options = new ListBucketOptions();
options.withPrefix("test").maxResults(1);
String query = options.buildQueryString();
checkQuery(query);
checkQuery(checkNotNull(query));
}
private void checkQuery(String query) {
try {
assertEquals(query, "?prefix=test&max-keys=1");
} catch (AssertionError e) {
assertEquals(query, "?max-keys=1&prefix=test");
}
}
@Test
public void testPrefixAndDelimiterUrlEncodingQueryString()
throws UnsupportedEncodingException {
ListBucketOptions options = new ListBucketOptions();
options.withPrefix("/test").delimiter("/");
String query = options.buildQueryString();
checkEncodedQuery(query);
checkEncodedQuery(checkNotNull(query));
}
private void checkEncodedQuery(String query) {
try {
assertEquals(query, "?prefix=%2Ftest&delimiter=%2F");
} catch (AssertionError e) {
assertEquals(query, "?delimiter=%2F&prefix=%2Ftest");
}
}
@Test
public void testNullPrefix() {
ListBucketOptions options = new ListBucketOptions();
assertNull(options.getPrefix());
}
@Test
public void testPrefixStatic() throws UnsupportedEncodingException {
ListBucketOptions options = withPrefix("test");
assertEquals(options.getPrefix(), "test");
}
@Test(expectedExceptions = NullPointerException.class)
public void testPrefixNPE() throws UnsupportedEncodingException {
withPrefix(null);
}
@Test
public void testMarker() throws UnsupportedEncodingException {
ListBucketOptions options = new ListBucketOptions();
options.afterMarker("test");
assertEquals(options.getMarker(), "test");
}
@Test
public void testNullMarker() {
ListBucketOptions options = new ListBucketOptions();
assertNull(options.getMarker());
}
@Test
public void testMarkerStatic() throws UnsupportedEncodingException {
ListBucketOptions options = afterMarker("test");
assertEquals(options.getMarker(), "test");
}
@Test(expectedExceptions = NullPointerException.class)
public void testMarkerNPE() throws UnsupportedEncodingException {
afterMarker(null);
}
@Test
public void testMaxKeys() {
ListBucketOptions options = new ListBucketOptions();
options.maxResults(1000);
assertEquals(options.getMaxKeys(), "1000");
}
@Test
public void testNullMaxKeys() {
ListBucketOptions options = new ListBucketOptions();
assertNull(options.getMaxKeys());
}
@Test
public void testMaxKeysStatic() {
ListBucketOptions options = maxResults(1000);
assertEquals(options.getMaxKeys(), "1000");
}
@Test(expectedExceptions = IllegalStateException.class)
public void testMaxKeysNegative() {
maxResults(-1);
}
@Test
public void testDelimiter() throws UnsupportedEncodingException {
ListBucketOptions options = new ListBucketOptions();
options.delimiter("test");
assertEquals(options.getDelimiter(), "test");
}
@Test
public void testNullDelimiter() {
ListBucketOptions options = new ListBucketOptions();
assertNull(options.getDelimiter());
}
@Test
public void testDelimiterStatic() throws UnsupportedEncodingException {
ListBucketOptions options = delimiter("test");
assertEquals(options.getDelimiter(), "test");
}
@Test(expectedExceptions = NullPointerException.class)
public void testDelimiterNPE() throws UnsupportedEncodingException {
delimiter(null);
}
}

View File

@ -30,7 +30,9 @@ import org.jclouds.aws.s3.handlers.AWSRedirectionRetryHandler;
import org.jclouds.aws.s3.handlers.ParseAWSErrorFromXmlContent;
import org.jclouds.aws.s3.reference.S3Constants;
import org.jclouds.aws.s3.xml.config.S3ParserModule;
import org.jclouds.http.config.JavaUrlHttpFutureCommandClientModule;
import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.http.handlers.DelegatingErrorHandler;
import org.jclouds.http.handlers.DelegatingRetryHandler;
import org.testng.annotations.Test;
@ -46,29 +48,25 @@ import com.google.inject.name.Names;
public class S3ContextModuleTest {
Injector createInjector() {
return Guice.createInjector(new LiveS3ConnectionModule(), new S3ParserModule(),
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");
bindConstant().annotatedWith(
Names.named(S3Constants.PROPERTY_HTTP_MAX_RETRIES)).to("5");
bindConstant().annotatedWith(
Names.named(S3Constants.PROPERTY_HTTP_MAX_REDIRECTS)).to("5");
super.configure();
}
}, new JavaUrlHttpFutureCommandClientModule());
return Guice.createInjector(new RestS3ConnectionModule(), new ExecutorServiceModule(
new WithinThreadExecutorService()), new S3ParserModule(), 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");
bindConstant().annotatedWith(Names.named(S3Constants.PROPERTY_HTTP_MAX_RETRIES))
.to("5");
bindConstant().annotatedWith(Names.named(S3Constants.PROPERTY_HTTP_MAX_REDIRECTS)).to(
"5");
super.configure();
}
}, new JavaUrlHttpCommandExecutorServiceModule());
}
@Test
@ -86,13 +84,15 @@ public class S3ContextModuleTest {
@Test
void testClientRetryHandler() {
DelegatingRetryHandler handler = createInjector().getInstance(DelegatingRetryHandler.class);
assertEquals(handler.getClientErrorRetryHandler().getClass(), AWSClientErrorRetryHandler.class);
assertEquals(handler.getClientErrorRetryHandler().getClass(),
AWSClientErrorRetryHandler.class);
}
@Test
void testRedirectionRetryHandler() {
DelegatingRetryHandler handler = createInjector().getInstance(DelegatingRetryHandler.class);
assertEquals(handler.getRedirectionRetryHandler().getClass(), AWSRedirectionRetryHandler.class);
assertEquals(handler.getRedirectionRetryHandler().getClass(),
AWSRedirectionRetryHandler.class);
}
}

View File

@ -28,6 +28,7 @@ import java.net.URI;
import org.jclouds.aws.s3.S3Connection;
import org.jclouds.aws.s3.internal.StubS3Connection;
import org.jclouds.cloud.ConfiguresCloudConnection;
import org.jclouds.http.functions.config.SaxModule;
import com.google.inject.AbstractModule;
@ -39,6 +40,7 @@ import com.google.inject.AbstractModule;
@ConfiguresCloudConnection
public class StubS3ConnectionModule extends AbstractModule {
protected void configure() {
install(new SaxModule());
bind(S3Connection.class).to(StubS3Connection.class);
bind(URI.class).toInstance(URI.create("http://localhost:8080"));
}

View File

@ -23,13 +23,15 @@
*/
package org.jclouds.aws.s3.domain;
import org.jclouds.http.ContentTypes;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotSame;
import org.testng.annotations.Test;
import java.io.File;
import javax.ws.rs.core.MediaType;
import org.testng.annotations.Test;
@Test(groups = "unit", testName = "s3.S3ObjectTest")
public class S3ObjectTest {
@ -39,16 +41,16 @@ public class S3ObjectTest {
File file = new File("hello.txt");
object.setData(file);
assertEquals(object.getMetadata().getContentType(),
ContentTypes.BINARY);
MediaType.APPLICATION_OCTET_STREAM);
}
@Test
void testMd5CopyingNotReference() {
byte[] md5 = new byte[12];
void testETagCopyingNotReference() {
byte[] eTag = new byte[12];
S3Object object = new S3Object("test");
object.getMetadata().setMd5(md5);
byte[] returnedMd5 = object.getMetadata().getMd5();
assertNotSame(md5, returnedMd5);
object.getMetadata().setETag(eTag);
byte[] returnedETag = object.getMetadata().getETag();
assertNotSame(eTag, returnedETag);
}
}

View File

@ -27,11 +27,12 @@ import static org.testng.Assert.assertEquals;
import java.net.URI;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.aws.s3.reference.S3Constants;
import org.jclouds.aws.util.DateService;
import org.jclouds.http.HttpHeaders;
import org.jclouds.http.HttpMethod;
import org.jclouds.http.HttpRequest;
import org.jclouds.util.DateService;
import org.testng.annotations.Test;
import com.google.inject.AbstractModule;
@ -44,29 +45,40 @@ public class RequestAuthorizeSignatureTest {
@Test
void testAppendBucketNameHostHeader() {
URI host = URI.create("http://s3.amazonaws.com:80");
HttpRequest request = new HttpRequest(host, HttpMethod.GET, "/");
HttpRequest request = new HttpRequest(HttpMethod.GET, host);
request.getHeaders().put(HttpHeaders.HOST, "adriancole.s3int5.s3.amazonaws.com");
StringBuilder builder = new StringBuilder();
RequestAuthorizeSignature.appendBucketName(request, builder);
createFilter().appendBucketName(request, builder);
assertEquals(builder.toString(), "/adriancole.s3int5");
}
@Test
void testAclQueryString() {
URI host = URI.create("http://s3.amazonaws.com:80/?acl");
HttpRequest request = new HttpRequest(HttpMethod.GET, host);
StringBuilder builder = new StringBuilder();
createFilter().appendUriPath(request, builder);
assertEquals(builder.toString(), "/?acl");
}
// "?acl", "?location", "?logging", or "?torrent"
@Test
void testAppendBucketNameHostHeaderService() {
URI host = URI.create("http://s3.amazonaws.com:80");
HttpRequest request = new HttpRequest(host, HttpMethod.GET, "/");
HttpRequest request = new HttpRequest(HttpMethod.GET, host);
request.getHeaders().put(HttpHeaders.HOST, "s3.amazonaws.com");
StringBuilder builder = new StringBuilder();
RequestAuthorizeSignature.appendBucketName(request, builder);
createFilter().appendBucketName(request, builder);
assertEquals(builder.toString(), "");
}
@Test
void testAppendBucketNameURIHost() {
URI host = URI.create("http://adriancole.s3int5.s3-external-3.amazonaws.com:80");
HttpRequest request = new HttpRequest(host, HttpMethod.GET, "/");
HttpRequest request = new HttpRequest(HttpMethod.GET, host);
StringBuilder builder = new StringBuilder();
RequestAuthorizeSignature.appendBucketName(request, builder);
createFilter().appendBucketName(request, builder);
assertEquals(builder.toString(), "/adriancole.s3int5");
}

View File

@ -21,21 +21,17 @@
* under the License.
* ====================================================================
*/
package org.jclouds.aws.s3.xml;
package org.jclouds.aws.s3.functions;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import org.apache.commons.io.IOUtils;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.AccessControlList.GroupGranteeURI;
import org.jclouds.aws.s3.domain.AccessControlList.Permission;
import org.jclouds.http.HttpException;
import org.jclouds.http.commands.callables.xml.ParseSax;
import org.jclouds.http.functions.ParseSax;
import org.testng.annotations.Test;
@Test(groups = "unit", testName = "s3.AccessControlListHandlerTest")
@ -51,8 +47,7 @@ public class AccessControlListHandlerTest extends BaseHandlerTest {
@Test
public void testAccessControlListOwnerOnly() throws HttpException {
String ownerId = "1a405254c932b52e5b5caaa88186bc431a1bacb9ece631f835daddaf0c47677c";
AccessControlList acl = createParser().parse(
IOUtils.toInputStream(aclOwnerOnly));
AccessControlList acl = createParser().parse(IOUtils.toInputStream(aclOwnerOnly));
assertEquals(acl.getOwner().getId(), ownerId);
assertEquals(acl.getOwner().getDisplayName(), "jamesmurty");
assertEquals(acl.getPermissions(ownerId).size(), 1);
@ -66,8 +61,7 @@ public class AccessControlListHandlerTest extends BaseHandlerTest {
@Test
public void testAccessControlListExtreme() throws HttpException {
String ownerId = "1a405254c932b52e5b5caaa88186bc431a1bacb9ece631f835daddaf0c47677c";
AccessControlList acl = createParser().parse(
IOUtils.toInputStream(aclExtreme));
AccessControlList acl = createParser().parse(IOUtils.toInputStream(aclExtreme));
assertEquals(acl.getOwner().getId(), ownerId);
assertEquals(acl.getOwner().getDisplayName(), "jamesmurty");
assertEquals(acl.getPermissions(ownerId).size(), 3);
@ -82,23 +76,5 @@ public class AccessControlListHandlerTest extends BaseHandlerTest {
assertTrue(acl.hasPermission(GroupGranteeURI.AUTHENTICATED_USERS, Permission.WRITE_ACP));
assertTrue(acl.hasPermission(GroupGranteeURI.LOG_DELIVERY, Permission.WRITE));
}
@Test
public void testRoundTripParseAndFormat() throws HttpException, TransformerException,
ParserConfigurationException, FactoryConfigurationError
{
AccessControlList parsedAcl;
String formattedAcl;
parsedAcl = createParser().parse(
IOUtils.toInputStream(aclOwnerOnly));
formattedAcl = new AccessControlListBuilder(parsedAcl).getXmlString();
assertEquals(formattedAcl, aclOwnerOnly);
parsedAcl = createParser().parse(
IOUtils.toInputStream(aclExtreme));
formattedAcl = new AccessControlListBuilder(parsedAcl).getXmlString();
assertEquals(formattedAcl, aclExtreme);
}
}

View File

@ -21,9 +21,11 @@
* under the License.
* ====================================================================
*/
package org.jclouds.aws.s3.xml;
package org.jclouds.aws.s3.functions;
import org.jclouds.aws.s3.xml.S3ParserFactory;
import org.jclouds.aws.s3.xml.config.S3ParserModule;
import org.jclouds.http.functions.config.SaxModule;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
@ -37,7 +39,7 @@ public class BaseHandlerTest {
@BeforeTest
protected void setUpInjector() {
injector = Guice.createInjector(new S3ParserModule());
injector = Guice.createInjector(new S3ParserModule(), new SaxModule());
parserFactory = injector.getInstance(S3ParserFactory.class);
assert parserFactory != null;
}

View File

@ -21,12 +21,13 @@
* under the License.
* ====================================================================
*/
package org.jclouds.aws.s3.xml;
package org.jclouds.aws.s3.functions;
import org.apache.commons.io.IOUtils;
import org.jclouds.aws.domain.AWSError;
import org.jclouds.http.HttpException;
import org.jclouds.http.commands.callables.xml.ParseSax;
import org.jclouds.http.functions.ParseSax;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.Test;

Some files were not shown because too many files have changed in this diff Show More