mirror of https://github.com/apache/jclouds.git
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:
parent
8c49965f3d
commit
e9aee711d3
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 + "");
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
|
||||
}
|
||||
}
|
|
@ -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 + "");
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
|
@ -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() {
|
|
@ -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));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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:
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
|
@ -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() : "";
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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𑩟
|
||||
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𑩟
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
|
@ -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 {
|
||||
|
||||
/**
|
|
@ -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());
|
|
@ -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;
|
||||
|
|
@ -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;
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
||||
}
|
|
@ -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) {
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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"));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue