mirror of https://github.com/apache/jclouds.git
Issue 109, Issue 73: more work on compatibility layer; expose vendor interface as getApi(); more Strategies
git-svn-id: http://jclouds.googlecode.com/svn/trunk@1946 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
ce6930226e
commit
557d28783f
|
@ -34,30 +34,23 @@ 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.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.ListBucketResponse;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.aws.s3.filters.RequestAuthorizeSignature;
|
||||
import org.jclouds.aws.s3.functions.ClearAndDeleteBucketIfNotEmpty;
|
||||
import org.jclouds.aws.s3.functions.ParseObjectFromHeadersAndHttpContent;
|
||||
import org.jclouds.aws.s3.functions.ParseObjectMetadataFromHeaders;
|
||||
import org.jclouds.aws.s3.functions.ReturnTrueIfBucketAlreadyOwnedByYou;
|
||||
import org.jclouds.aws.s3.functions.ReturnTrueOn404FalseIfNotEmpty;
|
||||
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.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.functions.BlobKey;
|
||||
import org.jclouds.blobstore.functions.ThrowContainerNotFoundOn404;
|
||||
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
|
||||
import org.jclouds.http.functions.ParseETagHeader;
|
||||
import org.jclouds.http.functions.ReturnFalseOn404;
|
||||
|
@ -65,7 +58,6 @@ import org.jclouds.http.options.GetOptions;
|
|||
import org.jclouds.rest.Endpoint;
|
||||
import org.jclouds.rest.EntityParam;
|
||||
import org.jclouds.rest.ExceptionParser;
|
||||
import org.jclouds.rest.Headers;
|
||||
import org.jclouds.rest.HostPrefixParam;
|
||||
import org.jclouds.rest.ParamParser;
|
||||
import org.jclouds.rest.QueryParams;
|
||||
|
@ -74,9 +66,6 @@ import org.jclouds.rest.ResponseParser;
|
|||
import org.jclouds.rest.SkipEncoding;
|
||||
import org.jclouds.rest.VirtualHost;
|
||||
import org.jclouds.rest.XMLResponseParser;
|
||||
import org.jclouds.rest.binders.HttpRequestOptionsBinder;
|
||||
|
||||
import com.google.inject.internal.Nullable;
|
||||
|
||||
/**
|
||||
* Provides access to S3 via their REST API.
|
||||
|
@ -184,38 +173,8 @@ public interface S3BlobStore extends BlobStore<BucketMetadata, ObjectMetadata, S
|
|||
*/
|
||||
@DELETE
|
||||
@Path("{key}")
|
||||
Future<Boolean> removeBlob(@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.
|
||||
*
|
||||
* <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
|
||||
* @param options
|
||||
* options for creating the object
|
||||
* @return MD5 hash of the content uploaded
|
||||
* @throws org.jclouds.http.HttpResponseException
|
||||
* if the conditions requested set are not satisfied by the object on the server.
|
||||
* @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[]> putBlob(
|
||||
@HostPrefixParam String bucketName,
|
||||
@PathParam("key") @ParamParser(BlobKey.class) @EntityParam(S3ObjectBinder.class) S3Object object,
|
||||
PutObjectOptions options);
|
||||
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
||||
Future<Void> removeBlob(@HostPrefixParam String bucketName, @PathParam("key") String key);
|
||||
|
||||
@PUT
|
||||
@Path("{key}")
|
||||
|
@ -224,33 +183,6 @@ public interface S3BlobStore extends BlobStore<BucketMetadata, ObjectMetadata, S
|
|||
@HostPrefixParam String bucketName,
|
||||
@PathParam("key") @ParamParser(BlobKey.class) @EntityParam(S3ObjectBinder.class) S3Object object);
|
||||
|
||||
/**
|
||||
* Create and name your own bucket in which to store your objects.
|
||||
*
|
||||
* <p/>
|
||||
* 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
|
||||
* @return true, if the bucket was created or already exists
|
||||
*
|
||||
* @see PutBucketOptions
|
||||
* @see <a
|
||||
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketPUT.html"
|
||||
* />
|
||||
*
|
||||
*/
|
||||
@PUT
|
||||
@Path("/")
|
||||
@ExceptionParser(ReturnTrueIfBucketAlreadyOwnedByYou.class)
|
||||
Future<Boolean> createContainer(@HostPrefixParam String bucketName,
|
||||
@Nullable @EntityParam(HttpRequestOptionsBinder.class) PutBucketOptions options);
|
||||
|
||||
@PUT
|
||||
@Path("/")
|
||||
@ExceptionParser(ReturnTrueIfBucketAlreadyOwnedByYou.class)
|
||||
|
@ -267,7 +199,6 @@ public interface S3BlobStore extends BlobStore<BucketMetadata, ObjectMetadata, S
|
|||
*
|
||||
* @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"
|
||||
|
@ -275,8 +206,8 @@ public interface S3BlobStore extends BlobStore<BucketMetadata, ObjectMetadata, S
|
|||
*/
|
||||
@DELETE
|
||||
@Path("/")
|
||||
@ExceptionParser(ReturnTrueOn404FalseIfNotEmpty.class)
|
||||
Future<Boolean> deleteContainer(@HostPrefixParam String bucketName);
|
||||
@ExceptionParser(ClearAndDeleteBucketIfNotEmpty.class)
|
||||
Future<Void> deleteContainer(@HostPrefixParam String bucketName);
|
||||
|
||||
/**
|
||||
* Issues a HEAD command to determine if the bucket exists or not.
|
||||
|
@ -308,12 +239,6 @@ public interface S3BlobStore extends BlobStore<BucketMetadata, ObjectMetadata, S
|
|||
@GET
|
||||
@Path("/")
|
||||
@XMLResponseParser(ListBucketHandler.class)
|
||||
Future<ListBucketResponse> listBlobs(@HostPrefixParam String bucketName,
|
||||
@Nullable ListBucketOptions options);
|
||||
|
||||
@GET
|
||||
@Path("/")
|
||||
@XMLResponseParser(ListBucketHandler.class)
|
||||
Future<ListBucketResponse> listBlobs(@HostPrefixParam String bucketName);
|
||||
|
||||
/**
|
||||
|
@ -330,129 +255,4 @@ public interface S3BlobStore extends BlobStore<BucketMetadata, ObjectMetadata, S
|
|||
@Path("/")
|
||||
SortedSet<BucketMetadata> listContainers();
|
||||
|
||||
/**
|
||||
* 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"
|
||||
* />
|
||||
* @throws org.jclouds.http.HttpResponseException
|
||||
* if the conditions requested set are not satisfied by the object on the server.
|
||||
* @see CopyObjectOptions
|
||||
* @see org.jclouds.aws.s3.domain.CannedAccessPolicy
|
||||
*/
|
||||
@PUT
|
||||
@Path("{destinationObject}")
|
||||
@Headers(keys = "x-amz-copy-source", values = "/{sourceBucket}/{sourceObject}")
|
||||
@XMLResponseParser(CopyObjectHandler.class)
|
||||
Future<ObjectMetadata> copyBlob(@PathParam("sourceBucket") String sourceBucket,
|
||||
@PathParam("sourceObject") String sourceObject,
|
||||
@HostPrefixParam String destinationBucket,
|
||||
@PathParam("destinationObject") String destinationObject,
|
||||
@Nullable CopyObjectOptions options);
|
||||
|
||||
@PUT
|
||||
@Path("{destinationObject}")
|
||||
@Headers(keys = "x-amz-copy-source", values = "/{sourceBucket}/{sourceObject}")
|
||||
@XMLResponseParser(CopyObjectHandler.class)
|
||||
Future<ObjectMetadata> copyBlob(@PathParam("sourceBucket") String sourceBucket,
|
||||
@PathParam("sourceObject") String sourceObject,
|
||||
@HostPrefixParam String destinationBucket,
|
||||
@PathParam("destinationObject") String destinationObject);
|
||||
|
||||
/**
|
||||
*
|
||||
* 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
|
||||
@QueryParams(keys = "acl")
|
||||
@XMLResponseParser(AccessControlListHandler.class)
|
||||
@ExceptionParser(ThrowContainerNotFoundOn404.class)
|
||||
@Path("/")
|
||||
Future<AccessControlList> getContainerACL(@HostPrefixParam String bucketName);
|
||||
|
||||
/**
|
||||
* 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("/")
|
||||
@QueryParams(keys = "acl")
|
||||
Future<Boolean> putContainerACL(@HostPrefixParam String bucketName,
|
||||
@EntityParam(AccessControlListBinder.class) AccessControlList acl);
|
||||
|
||||
/**
|
||||
* 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
|
||||
@QueryParams(keys = "acl")
|
||||
@Path("{key}")
|
||||
@XMLResponseParser(AccessControlListHandler.class)
|
||||
@ExceptionParser(ThrowKeyNotFoundOn404.class)
|
||||
Future<AccessControlList> getBlobACL(@HostPrefixParam String bucketName,
|
||||
@PathParam("key") String key);
|
||||
|
||||
/**
|
||||
* 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
|
||||
@QueryParams(keys = "acl")
|
||||
@Path("{key}")
|
||||
Future<Boolean> putBlobACL(@HostPrefixParam String bucketName, @PathParam("key") String key,
|
||||
@EntityParam(AccessControlListBinder.class) AccessControlList acl);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,426 @@
|
|||
/**
|
||||
*
|
||||
* 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 java.util.SortedSet;
|
||||
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.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.ListBucketResponse;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.aws.s3.filters.RequestAuthorizeSignature;
|
||||
import org.jclouds.aws.s3.functions.ParseObjectFromHeadersAndHttpContent;
|
||||
import org.jclouds.aws.s3.functions.ParseObjectMetadataFromHeaders;
|
||||
import org.jclouds.aws.s3.functions.ReturnTrueIfBucketAlreadyOwnedByYou;
|
||||
import org.jclouds.aws.s3.functions.ReturnTrueOn404FalseIfNotEmpty;
|
||||
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.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.functions.BlobKey;
|
||||
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.blobstore.functions.ThrowContainerNotFoundOn404;
|
||||
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
|
||||
import org.jclouds.http.functions.ParseETagHeader;
|
||||
import org.jclouds.http.functions.ReturnFalseOn404;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
import org.jclouds.rest.Endpoint;
|
||||
import org.jclouds.rest.EntityParam;
|
||||
import org.jclouds.rest.ExceptionParser;
|
||||
import org.jclouds.rest.Headers;
|
||||
import org.jclouds.rest.HostPrefixParam;
|
||||
import org.jclouds.rest.ParamParser;
|
||||
import org.jclouds.rest.QueryParams;
|
||||
import org.jclouds.rest.RequestFilters;
|
||||
import org.jclouds.rest.ResponseParser;
|
||||
import org.jclouds.rest.SkipEncoding;
|
||||
import org.jclouds.rest.VirtualHost;
|
||||
import org.jclouds.rest.XMLResponseParser;
|
||||
import org.jclouds.rest.binders.HttpRequestOptionsBinder;
|
||||
|
||||
import com.google.inject.internal.Nullable;
|
||||
|
||||
/**
|
||||
* 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()}.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
* @author James Murty
|
||||
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAPI.html" />
|
||||
*/
|
||||
@VirtualHost
|
||||
@SkipEncoding('/')
|
||||
@RequestFilters(RequestAuthorizeSignature.class)
|
||||
@Endpoint(S3.class)
|
||||
public interface S3Connection {
|
||||
|
||||
/**
|
||||
* Retrieves the S3Object associated with the Key or {@link Blob <ObjectMetadata>#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 />
|
||||
* 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>
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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(ThrowKeyNotFoundOn404.class)
|
||||
@ResponseParser(ParseObjectFromHeadersAndHttpContent.class)
|
||||
Future<S3Object> getObject(@HostPrefixParam String bucketName, @PathParam("key") String key,
|
||||
GetOptions... options);
|
||||
|
||||
/**
|
||||
* Retrieves the {@link org.jclouds.aws.s3.domain.ObjectMetadata metadata} of the object
|
||||
* associated with the key or {@link org.jclouds.aws.s3.domain.ObjectMetadata#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.ObjectMetadata#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(ThrowKeyNotFoundOn404.class)
|
||||
@ResponseParser(ParseObjectMetadataFromHeaders.class)
|
||||
ObjectMetadata headObject(@HostPrefixParam String bucketName, @PathParam("key") 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}")
|
||||
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
||||
Future<Void> 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.
|
||||
*
|
||||
* <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
|
||||
* @param options
|
||||
* options for creating the object
|
||||
* @return MD5 hash of the content uploaded
|
||||
* @throws org.jclouds.http.HttpResponseException
|
||||
* if the conditions requested set are not satisfied by the object on the server.
|
||||
* @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") @ParamParser(BlobKey.class) @EntityParam(S3ObjectBinder.class) S3Object object,
|
||||
PutObjectOptions... options);
|
||||
|
||||
/**
|
||||
* Create and name your own bucket in which to store your objects.
|
||||
*
|
||||
* <p/>
|
||||
* 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
|
||||
* @return true, if the bucket was created or already exists
|
||||
*
|
||||
* @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,
|
||||
@Nullable @EntityParam(HttpRequestOptionsBinder.class) PutBucketOptions... options);
|
||||
|
||||
/**
|
||||
* 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)
|
||||
Future<Boolean> deleteBucketIfEmpty(@HostPrefixParam String bucketName);
|
||||
|
||||
/**
|
||||
* Issues a HEAD command to determine if the bucket exists or not.
|
||||
*/
|
||||
@HEAD
|
||||
@Path("/")
|
||||
@QueryParams(keys = "max-keys", values = "0")
|
||||
@ExceptionParser(ReturnFalseOn404.class)
|
||||
boolean bucketExists(@HostPrefixParam String bucketName);
|
||||
|
||||
/**
|
||||
* Retrieve a <code>S3Bucket</code> listing. A GET request operation using a bucket URI lists
|
||||
* information about the objects in the bucket. You can use {@link ListBucketOptions} to control
|
||||
* the amount of S3Objects to return.
|
||||
* <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 BoundedList<ObjectMetadata>#NOT_FOUND} if not present.
|
||||
* @see ListBucketOptions
|
||||
*
|
||||
* @see <a
|
||||
* href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketGET.html"
|
||||
* />
|
||||
*/
|
||||
@GET
|
||||
@Path("/")
|
||||
@XMLResponseParser(ListBucketHandler.class)
|
||||
Future<ListBucketResponse> listBucket(@HostPrefixParam String bucketName,
|
||||
ListBucketOptions... options);
|
||||
|
||||
/**
|
||||
* 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("/")
|
||||
SortedSet<BucketMetadata> listOwnedBuckets();
|
||||
|
||||
/**
|
||||
* 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"
|
||||
* />
|
||||
* @throws org.jclouds.http.HttpResponseException
|
||||
* if the conditions requested set are not satisfied by the object on the server.
|
||||
* @see CopyObjectOptions
|
||||
* @see org.jclouds.aws.s3.domain.CannedAccessPolicy
|
||||
*/
|
||||
@PUT
|
||||
@Path("{destinationObject}")
|
||||
@Headers(keys = "x-amz-copy-source", values = "/{sourceBucket}/{sourceObject}")
|
||||
@XMLResponseParser(CopyObjectHandler.class)
|
||||
Future<ObjectMetadata> copyObject(@PathParam("sourceBucket") String sourceBucket,
|
||||
@PathParam("sourceObject") String sourceObject,
|
||||
@HostPrefixParam String destinationBucket,
|
||||
@PathParam("destinationObject") String destinationObject, CopyObjectOptions... options);
|
||||
|
||||
/**
|
||||
*
|
||||
* 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
|
||||
@QueryParams(keys = "acl")
|
||||
@XMLResponseParser(AccessControlListHandler.class)
|
||||
@ExceptionParser(ThrowContainerNotFoundOn404.class)
|
||||
@Path("/")
|
||||
Future<AccessControlList> getBucketACL(@HostPrefixParam String bucketName);
|
||||
|
||||
/**
|
||||
* 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("/")
|
||||
@QueryParams(keys = "acl")
|
||||
Future<Boolean> putBucketACL(@HostPrefixParam String bucketName,
|
||||
@EntityParam(AccessControlListBinder.class) AccessControlList acl);
|
||||
|
||||
/**
|
||||
* 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
|
||||
@QueryParams(keys = "acl")
|
||||
@Path("{key}")
|
||||
@XMLResponseParser(AccessControlListHandler.class)
|
||||
@ExceptionParser(ThrowKeyNotFoundOn404.class)
|
||||
Future<AccessControlList> getObjectACL(@HostPrefixParam String bucketName,
|
||||
@PathParam("key") String key);
|
||||
|
||||
/**
|
||||
* 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
|
||||
@QueryParams(keys = "acl")
|
||||
@Path("{key}")
|
||||
Future<Boolean> putObjectACL(@HostPrefixParam String bucketName, @PathParam("key") String key,
|
||||
@EntityParam(AccessControlListBinder.class) AccessControlList acl);
|
||||
|
||||
}
|
|
@ -41,6 +41,6 @@ import org.jclouds.blobstore.BlobStoreContext;
|
|||
*
|
||||
*/
|
||||
public interface S3Context extends
|
||||
BlobStoreContext<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
BlobStoreContext<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
|
||||
}
|
|
@ -61,7 +61,7 @@ import com.google.inject.TypeLiteral;
|
|||
* @see S3Context
|
||||
*/
|
||||
public class S3ContextBuilder extends
|
||||
BlobStoreContextBuilder<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
BlobStoreContextBuilder<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
|
||||
@Override
|
||||
public S3Context buildContext() {
|
||||
|
@ -69,7 +69,7 @@ public class S3ContextBuilder extends
|
|||
}
|
||||
|
||||
public S3ContextBuilder(Properties props) {
|
||||
super(new TypeLiteral<S3BlobStore>() {
|
||||
super(new TypeLiteral<S3Connection>() {
|
||||
}, new TypeLiteral<BucketMetadata>() {
|
||||
}, new TypeLiteral<ObjectMetadata>() {
|
||||
}, new TypeLiteral<S3Object>() {
|
||||
|
|
|
@ -45,7 +45,8 @@ public class S3ObjectBinder extends BlobBinder {
|
|||
public void addEntityToRequest(Object entity, HttpRequest request) {
|
||||
Blob<?> object = (Blob<?>) entity;
|
||||
checkArgument(object.getMetadata().getSize() >= 0, "size must be set");
|
||||
|
||||
checkArgument(object.getContentLength() <= 5 * 1024 * 1024 * 1024,
|
||||
"maximum size for put object is 5GB");
|
||||
if (object instanceof S3Object) {
|
||||
S3Object s3Object = (S3Object) object;
|
||||
if (s3Object.getMetadata().getCacheControl() != null) {
|
||||
|
|
|
@ -30,11 +30,16 @@ import javax.inject.Singleton;
|
|||
|
||||
import org.jclouds.aws.s3.S3;
|
||||
import org.jclouds.aws.s3.S3BlobStore;
|
||||
import org.jclouds.aws.s3.S3Connection;
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.aws.s3.filters.RequestAuthorizeSignature;
|
||||
import org.jclouds.aws.s3.handlers.AWSClientErrorRetryHandler;
|
||||
import org.jclouds.aws.s3.handlers.AWSRedirectionRetryHandler;
|
||||
import org.jclouds.aws.s3.handlers.ParseAWSErrorFromXmlContent;
|
||||
import org.jclouds.aws.s3.reference.S3Constants;
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.cloud.ConfiguresCloudConnection;
|
||||
import org.jclouds.http.HttpErrorHandler;
|
||||
import org.jclouds.http.HttpRetryHandler;
|
||||
|
@ -73,10 +78,16 @@ public class RestS3ConnectionModule extends AbstractModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected S3BlobStore provideS3Connection(RestClientFactory factory) {
|
||||
protected BlobStore<BucketMetadata, ObjectMetadata, S3Object> provideS3BlobStore(RestClientFactory factory) {
|
||||
return factory.create(S3BlobStore.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected S3Connection provideS3Connection(RestClientFactory factory) {
|
||||
return factory.create(S3Connection.class);
|
||||
}
|
||||
|
||||
protected void bindErrorHandlers() {
|
||||
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(
|
||||
ParseAWSErrorFromXmlContent.class);
|
||||
|
|
|
@ -32,10 +32,12 @@ import javax.inject.Provider;
|
|||
import org.jclouds.aws.reference.AWSConstants;
|
||||
import org.jclouds.aws.s3.S3;
|
||||
import org.jclouds.aws.s3.S3BlobStore;
|
||||
import org.jclouds.aws.s3.S3Connection;
|
||||
import org.jclouds.aws.s3.S3Context;
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.BlobStoreContextImpl;
|
||||
import org.jclouds.blobstore.BlobMap.Factory;
|
||||
import org.jclouds.lifecycle.Closer;
|
||||
|
@ -56,15 +58,17 @@ public class S3ContextModule extends AbstractModule {
|
|||
}
|
||||
|
||||
public static class S3ContextImpl extends
|
||||
BlobStoreContextImpl<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> implements
|
||||
BlobStoreContextImpl<S3Connection, BucketMetadata, ObjectMetadata, S3Object> implements
|
||||
S3Context {
|
||||
@Inject
|
||||
S3ContextImpl(Factory<ObjectMetadata, S3Object> blobMapFactory,
|
||||
org.jclouds.blobstore.InputStreamMap.Factory<ObjectMetadata> inputStreamMapFactory,
|
||||
Closer closer, Provider<S3Object> blobProvider, S3BlobStore defaultApi,
|
||||
@S3 URI endPoint, @Named(AWSConstants.PROPERTY_AWS_ACCESSKEYID) String account) {
|
||||
super(blobMapFactory, inputStreamMapFactory, closer, blobProvider, defaultApi, endPoint,
|
||||
account);
|
||||
Closer closer, Provider<S3Object> blobProvider,
|
||||
BlobStore<BucketMetadata, ObjectMetadata, S3Object> blobStore,
|
||||
S3Connection defaultApi, @S3 URI endPoint,
|
||||
@Named(AWSConstants.PROPERTY_AWS_ACCESSKEYID) String account) {
|
||||
super(blobMapFactory, inputStreamMapFactory, closer, blobProvider, blobStore, defaultApi,
|
||||
endPoint, account);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 javax.inject.Inject;
|
||||
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.functions.ClearAndDeleteIfNotEmpty;
|
||||
import org.jclouds.blobstore.strategy.ClearContainerStrategy;
|
||||
|
||||
public class ClearAndDeleteBucketIfNotEmpty extends
|
||||
ClearAndDeleteIfNotEmpty<BucketMetadata, ObjectMetadata, S3Object> {
|
||||
|
||||
@Inject
|
||||
ClearAndDeleteBucketIfNotEmpty(
|
||||
ClearContainerStrategy<BucketMetadata, ObjectMetadata, S3Object> clear,
|
||||
BlobStore<BucketMetadata, ObjectMetadata, S3Object> connection) {
|
||||
super(clear, connection);
|
||||
}
|
||||
|
||||
}
|
|
@ -95,6 +95,7 @@ public class ListBucketHandler extends ParseSax.HandlerWithResult<ListBucketResp
|
|||
} else if (qName.equals("ETag")) {
|
||||
currentObjectMetadata.setETag(HttpUtils.fromHexString(currentText.toString().replaceAll(
|
||||
"\"", "")));
|
||||
currentObjectMetadata.setContentMD5(currentObjectMetadata.getETag());
|
||||
} else if (qName.equals("Size")) {
|
||||
currentObjectMetadata.setSize(Long.parseLong(currentText.toString()));
|
||||
} else if (qName.equals("Owner")) {
|
||||
|
|
|
@ -0,0 +1,705 @@
|
|||
/**
|
||||
*
|
||||
* 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 static org.jclouds.aws.s3.internal.StubS3Connection.TEST_ACL_EMAIL;
|
||||
import static org.jclouds.aws.s3.internal.StubS3Connection.TEST_ACL_ID;
|
||||
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.overrideAcl;
|
||||
import static org.jclouds.aws.s3.options.CopyObjectOptions.Builder.overrideMetadataWith;
|
||||
import static org.jclouds.aws.s3.options.ListBucketOptions.Builder.afterMarker;
|
||||
import static org.jclouds.aws.s3.options.ListBucketOptions.Builder.delimiter;
|
||||
import static org.jclouds.aws.s3.options.ListBucketOptions.Builder.maxResults;
|
||||
import static org.jclouds.aws.s3.options.ListBucketOptions.Builder.withPrefix;
|
||||
import static org.jclouds.aws.s3.options.PutBucketOptions.Builder.createIn;
|
||||
import static org.jclouds.aws.s3.options.PutBucketOptions.Builder.withBucketAcl;
|
||||
import static org.jclouds.aws.s3.options.PutObjectOptions.Builder.withAcl;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
import java.util.SortedSet;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.aws.s3.domain.AccessControlList;
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
|
||||
import org.jclouds.aws.s3.domain.ListBucketResponse;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.aws.s3.domain.AccessControlList.CanonicalUserGrantee;
|
||||
import org.jclouds.aws.s3.domain.AccessControlList.EmailAddressGrantee;
|
||||
import org.jclouds.aws.s3.domain.AccessControlList.GroupGranteeURI;
|
||||
import org.jclouds.aws.s3.domain.AccessControlList.Permission;
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata.LocationConstraint;
|
||||
import org.jclouds.aws.s3.options.PutObjectOptions;
|
||||
import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.util.Utils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author James Murty
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = { "integration", "live" }, testName = "s3.S3ConnectionLiveTest")
|
||||
public class S3ConnectionLiveTest extends
|
||||
BaseBlobStoreIntegrationTest<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
|
||||
/**
|
||||
* this method overrides containerName to ensure it isn't found
|
||||
*/
|
||||
@Test(groups = { "integration", "live" })
|
||||
public void deleteContainerIfEmptyNotFound() throws Exception {
|
||||
assert context.getApi().deleteBucketIfEmpty("dbienf").get(10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Test(groups = { "integration", "live" })
|
||||
public void deleteContainerIfEmptyButHasContents() throws Exception {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
addBlobToContainer(containerName, "test");
|
||||
assert !context.getApi().deleteBucketIfEmpty(containerName).get(10, TimeUnit.SECONDS);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
}
|
||||
|
||||
public void testPutCannedAccessPolicyPublic() throws Exception {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
String key = "hello";
|
||||
|
||||
context.getApi().putObject(containerName, new S3Object(key, TEST_STRING),
|
||||
|
||||
withAcl(CannedAccessPolicy.PUBLIC_READ)).get(10, TimeUnit.SECONDS);
|
||||
|
||||
URL url = new URL(String.format("http://%1$s.s3.amazonaws.com/%2$s", containerName, key));
|
||||
Utils.toStringAndClose(url.openStream());
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testCopyCannedAccessPolicyPublic() throws Exception {
|
||||
String containerName = getContainerName();
|
||||
String destinationContainer = getContainerName();
|
||||
try {
|
||||
addBlobToContainer(containerName, sourceKey);
|
||||
validateContent(containerName, sourceKey);
|
||||
|
||||
context.getApi().copyObject(containerName, sourceKey, destinationContainer,
|
||||
destinationKey, overrideAcl(CannedAccessPolicy.PUBLIC_READ)).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
URL url = new URL(String.format("http://%1$s.s3.amazonaws.com/%2$s", destinationContainer,
|
||||
destinationKey));
|
||||
Utils.toStringAndClose(url.openStream());
|
||||
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
returnContainer(destinationContainer);
|
||||
}
|
||||
}
|
||||
|
||||
String sourceKey = "apples";
|
||||
String destinationKey = "pears";
|
||||
|
||||
public void testPublicWriteOnObject() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException {
|
||||
final String publicReadWriteObjectKey = "public-read-write-acl";
|
||||
final String containerName = getContainerName();
|
||||
try {
|
||||
// Public Read-Write object
|
||||
context.getApi().putObject(containerName, new S3Object(publicReadWriteObjectKey, ""),
|
||||
new PutObjectOptions().withAcl(CannedAccessPolicy.PUBLIC_READ_WRITE)).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
|
||||
assertEventually(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
AccessControlList acl = context.getApi().getObjectACL(containerName,
|
||||
publicReadWriteObjectKey).get(10, TimeUnit.SECONDS);
|
||||
assertEquals(acl.getGrants().size(), 3);
|
||||
assertEquals(acl.getPermissions(GroupGranteeURI.ALL_USERS).size(), 2);
|
||||
assertTrue(acl.getOwner() != null);
|
||||
String ownerId = acl.getOwner().getId();
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ));
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.WRITE));
|
||||
assertFalse(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ_ACP));
|
||||
assertFalse(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.WRITE_ACP));
|
||||
assertFalse(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.FULL_CONTROL));
|
||||
} catch (Exception e) {
|
||||
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testUpdateObjectACL() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
String objectKey = "private-acl";
|
||||
|
||||
// Private object
|
||||
addBlobToContainer(containerName, objectKey);
|
||||
AccessControlList acl = context.getApi().getObjectACL(containerName, objectKey).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
String ownerId = acl.getOwner().getId();
|
||||
|
||||
assertEquals(acl.getGrants().size(), 1);
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
|
||||
|
||||
addGrantsToACL(acl);
|
||||
assertEquals(acl.getGrants().size(), 4);
|
||||
assertTrue(context.getApi().putObjectACL(containerName, objectKey, acl).get(10,
|
||||
TimeUnit.SECONDS));
|
||||
|
||||
// Confirm that the updated ACL has stuck.
|
||||
acl = context.getApi().getObjectACL(containerName, objectKey).get(10, TimeUnit.SECONDS);
|
||||
checkGrants(acl);
|
||||
|
||||
/*
|
||||
* Revoke all of owner's permissions!
|
||||
*/
|
||||
acl.revokeAllPermissions(new CanonicalUserGrantee(ownerId));
|
||||
if (!ownerId.equals(TEST_ACL_ID))
|
||||
acl.revokeAllPermissions(new CanonicalUserGrantee(TEST_ACL_ID));
|
||||
assertEquals(acl.getGrants().size(), 1);
|
||||
// Only public read permission should remain...
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ));
|
||||
|
||||
// Update the object's ACL settings
|
||||
assertTrue(context.getApi().putObjectACL(containerName, objectKey, acl).get(10,
|
||||
TimeUnit.SECONDS));
|
||||
|
||||
// Confirm that the updated ACL has stuck
|
||||
acl = context.getApi().getObjectACL(containerName, objectKey).get(10, TimeUnit.SECONDS);
|
||||
assertEquals(acl.getGrants().size(), 1);
|
||||
assertEquals(acl.getPermissions(ownerId).size(), 0);
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ), acl.toString());
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testPrivateAclIsDefaultForObject() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException {
|
||||
String privateObjectKey = "private-acl";
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
// Private object
|
||||
addBlobToContainer(containerName, privateObjectKey);
|
||||
AccessControlList acl = context.getApi().getObjectACL(containerName, privateObjectKey)
|
||||
.get(10, TimeUnit.SECONDS);
|
||||
|
||||
assertEquals(acl.getGrants().size(), 1);
|
||||
assertTrue(acl.getOwner() != null);
|
||||
String ownerId = acl.getOwner().getId();
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testPublicReadOnObject() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException {
|
||||
final String publicReadObjectKey = "public-read-acl";
|
||||
final String containerName = getContainerName();
|
||||
try {
|
||||
context.getApi().putObject(containerName, new S3Object(publicReadObjectKey, ""),
|
||||
new PutObjectOptions().withAcl(CannedAccessPolicy.PUBLIC_READ)).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
|
||||
assertEventually(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
AccessControlList acl = context.getApi().getObjectACL(containerName,
|
||||
publicReadObjectKey).get(10, TimeUnit.SECONDS);
|
||||
|
||||
assertEquals(acl.getGrants().size(), 2);
|
||||
assertEquals(acl.getPermissions(GroupGranteeURI.ALL_USERS).size(), 1);
|
||||
assertTrue(acl.getOwner() != null);
|
||||
String ownerId = acl.getOwner().getId();
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ));
|
||||
} catch (Exception e) {
|
||||
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testMetadataWithCacheControlAndContentDisposition() throws Exception {
|
||||
String key = "hello";
|
||||
|
||||
S3Object object = context.newBlob(key);
|
||||
object.setData(TEST_STRING);
|
||||
object.getMetadata().setCacheControl("no-cache");
|
||||
object.getMetadata().setContentDisposition("attachment; filename=hello.txt");
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
addBlobToContainer(containerName, object);
|
||||
S3Object newObject = validateContent(containerName, key);
|
||||
|
||||
assertEquals(newObject.getMetadata().getCacheControl(), "no-cache");
|
||||
assertEquals(newObject.getMetadata().getContentDisposition(),
|
||||
"attachment; filename=hello.txt");
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(groups = { "integration", "live" })
|
||||
public void testMetadataContentEncoding() throws Exception {
|
||||
String key = "hello";
|
||||
|
||||
S3Object object = context.newBlob(key);
|
||||
object.setData(TEST_STRING);
|
||||
object.getMetadata().setContentEncoding("x-compress");
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
addBlobToContainer(containerName, object);
|
||||
S3Object newObject = validateContent(containerName, key);
|
||||
|
||||
assertEquals(newObject.getMetadata().getContentEncoding(), "x-compress");
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
}
|
||||
|
||||
public void testCopyObject() throws Exception {
|
||||
String containerName = getContainerName();
|
||||
String destinationContainer = getContainerName();
|
||||
|
||||
try {
|
||||
addToContainerAndValidate(containerName, sourceKey);
|
||||
|
||||
context.getApi()
|
||||
.copyObject(containerName, sourceKey, destinationContainer, destinationKey).get(
|
||||
10, TimeUnit.SECONDS);
|
||||
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
returnContainer(destinationContainer);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void addToContainerAndValidate(String containerName, String sourceKey)
|
||||
throws InterruptedException, ExecutionException, TimeoutException, IOException {
|
||||
addBlobToContainer(containerName, sourceKey);
|
||||
validateContent(containerName, sourceKey);
|
||||
}
|
||||
|
||||
// TODO: fails on linux and windows
|
||||
public void testCopyIfModifiedSince() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException {
|
||||
String containerName = getContainerName();
|
||||
String destinationContainer = getContainerName();
|
||||
try {
|
||||
DateTime before = new DateTime();
|
||||
addToContainerAndValidate(containerName, sourceKey + "mod");
|
||||
DateTime after = new DateTime().plusSeconds(1);
|
||||
|
||||
context.getApi().copyObject(containerName, sourceKey + "mod", destinationContainer,
|
||||
destinationKey, ifSourceModifiedSince(before)).get(10, TimeUnit.SECONDS);
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
try {
|
||||
context.getApi().copyObject(containerName, sourceKey + "mod", destinationContainer,
|
||||
destinationKey, ifSourceModifiedSince(after)).get(10, TimeUnit.SECONDS);
|
||||
} catch (ExecutionException e) {
|
||||
if (e.getCause() instanceof HttpResponseException) {
|
||||
HttpResponseException ex = (HttpResponseException) e.getCause();
|
||||
assertEquals(ex.getResponse().getStatusCode(), 412);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
returnContainer(destinationContainer);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: fails on linux and windows
|
||||
public void testCopyIfUnmodifiedSince() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException {
|
||||
String containerName = getContainerName();
|
||||
String destinationContainer = getContainerName();
|
||||
try {
|
||||
DateTime before = new DateTime();
|
||||
addToContainerAndValidate(containerName, sourceKey + "un");
|
||||
DateTime after = new DateTime().plusSeconds(1);
|
||||
|
||||
context.getApi().copyObject(containerName, sourceKey + "un", destinationContainer,
|
||||
destinationKey, ifSourceUnmodifiedSince(after)).get(10, TimeUnit.SECONDS);
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
try {
|
||||
context.getApi().copyObject(containerName, sourceKey + "un", destinationContainer,
|
||||
destinationKey, ifSourceModifiedSince(before)).get(10, TimeUnit.SECONDS);
|
||||
} catch (ExecutionException e) {
|
||||
HttpResponseException ex = (HttpResponseException) e.getCause();
|
||||
assertEquals(ex.getResponse().getStatusCode(), 412);
|
||||
}
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
returnContainer(destinationContainer);
|
||||
}
|
||||
}
|
||||
|
||||
public void testCopyIfMatch() throws InterruptedException, ExecutionException, TimeoutException,
|
||||
IOException {
|
||||
String containerName = getContainerName();
|
||||
String destinationContainer = getContainerName();
|
||||
try {
|
||||
addToContainerAndValidate(containerName, sourceKey);
|
||||
|
||||
context.getApi().copyObject(containerName, sourceKey, destinationContainer,
|
||||
destinationKey, ifSourceETagMatches(goodETag)).get(10, TimeUnit.SECONDS);
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
try {
|
||||
context.getApi().copyObject(containerName, sourceKey, destinationContainer,
|
||||
destinationKey, ifSourceETagMatches(badETag)).get(10, TimeUnit.SECONDS);
|
||||
} catch (ExecutionException e) {
|
||||
HttpResponseException ex = (HttpResponseException) e.getCause();
|
||||
assertEquals(ex.getResponse().getStatusCode(), 412);
|
||||
}
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
returnContainer(destinationContainer);
|
||||
}
|
||||
}
|
||||
|
||||
public void testCopyIfNoneMatch() throws IOException, InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
String containerName = getContainerName();
|
||||
String destinationContainer = getContainerName();
|
||||
try {
|
||||
addToContainerAndValidate(containerName, sourceKey);
|
||||
|
||||
context.getApi().copyObject(containerName, sourceKey, destinationContainer,
|
||||
destinationKey, ifSourceETagDoesntMatch(badETag)).get(10, TimeUnit.SECONDS);
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
try {
|
||||
context.getApi().copyObject(containerName, sourceKey, destinationContainer,
|
||||
destinationKey, ifSourceETagDoesntMatch(goodETag)).get(10, TimeUnit.SECONDS);
|
||||
} catch (ExecutionException e) {
|
||||
HttpResponseException ex = (HttpResponseException) e.getCause();
|
||||
assertEquals(ex.getResponse().getStatusCode(), 412);
|
||||
}
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
returnContainer(destinationContainer);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void testCopyWithMetadata() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException {
|
||||
String containerName = getContainerName();
|
||||
String destinationContainer = getContainerName();
|
||||
try {
|
||||
addToContainerAndValidate(containerName, sourceKey);
|
||||
|
||||
Multimap<String, String> metadata = HashMultimap.create();
|
||||
metadata.put("adrian", "cole");
|
||||
|
||||
context.getApi().copyObject(containerName, sourceKey, destinationContainer,
|
||||
destinationKey, overrideMetadataWith(metadata)).get(10, TimeUnit.SECONDS);
|
||||
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
ObjectMetadata objectMeta = context.getApi().headObject(destinationContainer,
|
||||
destinationKey);
|
||||
|
||||
assertEquals(objectMeta.getUserMetadata(), metadata);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
returnContainer(destinationContainer);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void testListContainerDelimiter() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, UnsupportedEncodingException {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
String prefix = "apps";
|
||||
addTenObjectsUnderPrefix(containerName, prefix);
|
||||
add15UnderRoot(containerName);
|
||||
ListBucketResponse container = context.getApi().listBucket(containerName, delimiter("/"))
|
||||
.get(10, TimeUnit.SECONDS);
|
||||
assertEquals(container.getDelimiter(), "/");
|
||||
assert !container.isTruncated();
|
||||
assertEquals(container.size(), 15);
|
||||
assertEquals(container.getCommonPrefixes().size(), 1);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testListContainerPrefix() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, UnsupportedEncodingException {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
String prefix = "apps";
|
||||
addTenObjectsUnderPrefix(containerName, prefix);
|
||||
add15UnderRoot(containerName);
|
||||
|
||||
ListBucketResponse container = context.getApi().listBucket(containerName,
|
||||
withPrefix("apps/")).get(10, TimeUnit.SECONDS);
|
||||
assert !container.isTruncated();
|
||||
assertEquals(container.size(), 10);
|
||||
assertEquals(container.getPrefix(), "apps/");
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testPrivateAclIsDefaultForContainer() throws InterruptedException,
|
||||
ExecutionException, TimeoutException, IOException {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
AccessControlList acl = context.getApi().getBucketACL(containerName).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
assertEquals(acl.getGrants().size(), 1);
|
||||
assertTrue(acl.getOwner() != null);
|
||||
String ownerId = acl.getOwner().getId();
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testUpdateContainerACL() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException, Exception {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
// Confirm the container is private
|
||||
AccessControlList acl = context.getApi().getBucketACL(containerName).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
String ownerId = acl.getOwner().getId();
|
||||
assertEquals(acl.getGrants().size(), 1);
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
|
||||
|
||||
addGrantsToACL(acl);
|
||||
assertEquals(acl.getGrants().size(), 4);
|
||||
assertTrue(context.getApi().putBucketACL(containerName, acl).get(10, TimeUnit.SECONDS));
|
||||
|
||||
// Confirm that the updated ACL has stuck.
|
||||
acl = context.getApi().getBucketACL(containerName).get(10, TimeUnit.SECONDS);
|
||||
checkGrants(acl);
|
||||
} finally {
|
||||
destroyContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void checkGrants(AccessControlList acl) {
|
||||
String ownerId = acl.getOwner().getId();
|
||||
|
||||
assertEquals(acl.getGrants().size(), 4, acl.toString());
|
||||
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL), acl.toString());
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ), acl.toString());
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.WRITE_ACP), acl.toString());
|
||||
// EmailAddressGrantee is replaced by a CanonicalUserGrantee, so we cannot test by email addr
|
||||
assertTrue(acl.hasPermission(TEST_ACL_ID, Permission.READ_ACP), acl.toString());
|
||||
}
|
||||
|
||||
private void addGrantsToACL(AccessControlList acl) {
|
||||
String ownerId = acl.getOwner().getId();
|
||||
acl.addPermission(GroupGranteeURI.ALL_USERS, Permission.READ);
|
||||
acl.addPermission(new EmailAddressGrantee(TEST_ACL_EMAIL), Permission.READ_ACP);
|
||||
acl.addPermission(new CanonicalUserGrantee(ownerId), Permission.WRITE_ACP);
|
||||
}
|
||||
|
||||
public void testListContainerMarker() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, UnsupportedEncodingException {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
addAlphabetUnderRoot(containerName);
|
||||
ListBucketResponse container = context.getApi()
|
||||
.listBucket(containerName, afterMarker("y")).get(10, TimeUnit.SECONDS);
|
||||
assertEquals(container.getMarker(), "y");
|
||||
assert !container.isTruncated();
|
||||
assertEquals(container.size(), 1);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
}
|
||||
|
||||
public void testListContainerMaxResults() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, UnsupportedEncodingException {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
addAlphabetUnderRoot(containerName);
|
||||
ListBucketResponse container = context.getApi().listBucket(containerName, maxResults(5))
|
||||
.get(10, TimeUnit.SECONDS);
|
||||
assertEquals(container.getMaxResults(), 5);
|
||||
assert container.isTruncated();
|
||||
assertEquals(container.size(), 5);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
}
|
||||
|
||||
public void testPublicReadAccessPolicy() throws Exception {
|
||||
String containerName = getScratchContainerName();
|
||||
try {
|
||||
context.getApi().putBucketIfNotExists(containerName,
|
||||
withBucketAcl(CannedAccessPolicy.PUBLIC_READ)).get(10, TimeUnit.SECONDS);
|
||||
AccessControlList acl = context.getApi().getBucketACL(containerName).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ), acl.toString());
|
||||
// TODO: I believe that the following should work based on the above acl assertion passing.
|
||||
// However, it fails on 403
|
||||
// URL url = new URL(String.format("http://%s.s3.amazonaws.com", containerName));
|
||||
// Utils.toStringAndClose(url.openStream());
|
||||
} finally {
|
||||
destroyContainer(containerName);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IOException.class)
|
||||
public void testDefaultAccessPolicy() throws Exception {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
URL url = new URL(String.format("https://%s.s3.amazonaws.com", containerName));
|
||||
Utils.toStringAndClose(url.openStream());
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* using scratch containerName as we are changing location
|
||||
*/
|
||||
public void testEu() throws Exception {
|
||||
final String containerName = getScratchContainerName();
|
||||
try {
|
||||
context.getApi().putBucketIfNotExists(containerName + "eu",
|
||||
createIn(LocationConstraint.EU).withBucketAcl(CannedAccessPolicy.PUBLIC_READ))
|
||||
.get(30, TimeUnit.SECONDS);
|
||||
assertEventually(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
AccessControlList acl = context.getApi().getBucketACL(containerName + "eu").get(
|
||||
30, TimeUnit.SECONDS);
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ), acl
|
||||
.toString());
|
||||
} catch (Exception e) {
|
||||
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
// TODO: I believe that the following should work based on the above acl assertion passing.
|
||||
// However, it fails on 403
|
||||
// URL url = new URL(String.format("http://%s.s3.amazonaws.com", containerName));
|
||||
// Utils.toStringAndClose(url.openStream());
|
||||
} finally {
|
||||
destroyContainer(containerName + "eu");
|
||||
}
|
||||
}
|
||||
|
||||
void containerExists() throws Exception {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
SortedSet<BucketMetadata> list = context.getApi().listOwnedBuckets();
|
||||
BucketMetadata firstContainer = list.first();
|
||||
BucketMetadata toMatch = new BucketMetadata(containerName);
|
||||
toMatch.setOwner(firstContainer.getOwner());
|
||||
assert list.contains(toMatch);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addAlphabetUnderRoot(String containerName) throws InterruptedException,
|
||||
ExecutionException, TimeoutException {
|
||||
for (char letter = 'a'; letter <= 'z'; letter++) {
|
||||
S3Object blob = context.newBlob(letter + "");
|
||||
blob.setData(letter + "content");
|
||||
context.getApi().putObject(containerName, blob).get(10, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
protected void add15UnderRoot(String containerName) throws InterruptedException,
|
||||
ExecutionException, TimeoutException {
|
||||
for (int i = 0; i < 15; i++) {
|
||||
S3Object blob = context.newBlob(i + "");
|
||||
blob.setData(i + "content");
|
||||
context.getApi().putObject(containerName, blob).get(10, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addTenObjectsUnderPrefix(String containerName, String prefix)
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
S3Object blob = context.newBlob(prefix + "/" + i);
|
||||
blob.setData(i + "content");
|
||||
context.getApi().putObject(containerName, blob).get(10, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,6 +36,8 @@ import org.jclouds.aws.s3.config.RestS3ConnectionModule;
|
|||
import org.jclouds.aws.s3.config.S3ContextModule;
|
||||
import org.jclouds.aws.s3.config.StubS3BlobStoreModule;
|
||||
import org.jclouds.aws.s3.config.S3ContextModule.S3ContextImpl;
|
||||
import org.jclouds.aws.s3.internal.StubS3Connection;
|
||||
import org.jclouds.blobstore.integration.internal.StubBlobStore;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.Injector;
|
||||
|
@ -61,6 +63,8 @@ public class S3ContextBuilderTest {
|
|||
S3Context context = new S3ContextBuilder("id", "secret").withModules(
|
||||
new StubS3BlobStoreModule()).buildContext();
|
||||
assertEquals(context.getClass(), S3ContextImpl.class);
|
||||
assertEquals(context.getApi().getClass(), StubS3Connection.class);
|
||||
assertEquals(context.getBlobStore().getClass(), StubBlobStore.class);
|
||||
assertEquals(context.getAccount(), "id");
|
||||
assertEquals(context.getEndPoint(), URI.create("https://localhost/s3stub"));
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ package org.jclouds.aws.s3.config;
|
|||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import org.jclouds.aws.s3.S3BlobStore;
|
||||
import org.jclouds.aws.s3.S3Context;
|
||||
import org.jclouds.aws.s3.config.S3ContextModule.S3ContextImpl;
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
|
@ -48,8 +47,7 @@ public class S3ContextModuleTest {
|
|||
|
||||
Injector createInjector() {
|
||||
return Guice.createInjector(new StubS3BlobStoreModule(), BlobStoreMapsModule.Builder
|
||||
.newBuilder(new TypeLiteral<S3BlobStore>() {
|
||||
}, new TypeLiteral<BucketMetadata>() {
|
||||
.newBuilder(new TypeLiteral<BucketMetadata>() {
|
||||
}, new TypeLiteral<ObjectMetadata>() {
|
||||
}, new TypeLiteral<S3Object>() {
|
||||
}).build(), new S3ContextModule() {
|
||||
|
|
|
@ -28,9 +28,13 @@ import java.util.Map;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.jclouds.aws.s3.S3;
|
||||
import org.jclouds.aws.s3.S3BlobStore;
|
||||
import org.jclouds.aws.s3.S3Connection;
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.aws.s3.internal.StubS3BlobStore;
|
||||
import org.jclouds.aws.s3.internal.StubS3Connection;
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.integration.internal.StubBlobStore;
|
||||
import org.jclouds.cloud.ConfiguresCloudConnection;
|
||||
import org.jclouds.http.functions.config.ParserModule;
|
||||
|
||||
|
@ -50,7 +54,10 @@ public class StubS3BlobStoreModule extends AbstractModule {
|
|||
install(new ParserModule());
|
||||
bind(new TypeLiteral<Map<String, Map<String, S3Object>>>() {
|
||||
}).toInstance(map);
|
||||
bind(S3BlobStore.class).to(StubS3BlobStore.class).asEagerSingleton();
|
||||
bind(new TypeLiteral<BlobStore<BucketMetadata, ObjectMetadata, S3Object>>() {
|
||||
}).to(new TypeLiteral<StubBlobStore<BucketMetadata, ObjectMetadata, S3Object>>() {
|
||||
}).asEagerSingleton();
|
||||
bind(S3Connection.class).to(StubS3Connection.class).asEagerSingleton();
|
||||
bind(URI.class).annotatedWith(S3.class).toInstance(URI.create("https://localhost/s3stub"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,42 +23,13 @@
|
|||
*/
|
||||
package org.jclouds.aws.s3.integration;
|
||||
|
||||
import static org.jclouds.aws.s3.internal.StubS3BlobStore.TEST_ACL_EMAIL;
|
||||
import static org.jclouds.aws.s3.internal.StubS3BlobStore.TEST_ACL_ID;
|
||||
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 static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.aws.s3.S3BlobStore;
|
||||
import org.jclouds.aws.s3.domain.AccessControlList;
|
||||
import org.jclouds.aws.s3.S3Connection;
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.aws.s3.domain.AccessControlList.CanonicalUserGrantee;
|
||||
import org.jclouds.aws.s3.domain.AccessControlList.EmailAddressGrantee;
|
||||
import org.jclouds.aws.s3.domain.AccessControlList.GroupGranteeURI;
|
||||
import org.jclouds.aws.s3.domain.AccessControlList.Permission;
|
||||
import org.jclouds.aws.s3.options.PutObjectOptions;
|
||||
import org.jclouds.blobstore.integration.internal.BaseBlobIntegrationTest;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.util.Utils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author James Murty
|
||||
|
@ -66,361 +37,6 @@ import com.google.common.collect.Multimap;
|
|||
*/
|
||||
@Test(groups = { "integration", "live" }, testName = "s3.S3BlobIntegrationTest")
|
||||
public class S3BlobIntegrationTest extends
|
||||
BaseBlobIntegrationTest<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
String sourceKey = "apples";
|
||||
String destinationKey = "pears";
|
||||
|
||||
public void testPublicWriteOnObject() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException {
|
||||
final String publicReadWriteObjectKey = "public-read-write-acl";
|
||||
final String containerName = getContainerName();
|
||||
try {
|
||||
// Public Read-Write object
|
||||
context.getApi().putBlob(containerName, new S3Object(publicReadWriteObjectKey, ""),
|
||||
new PutObjectOptions().withAcl(CannedAccessPolicy.PUBLIC_READ_WRITE)).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
|
||||
assertEventually(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
AccessControlList acl = context.getApi().getBlobACL(containerName,
|
||||
publicReadWriteObjectKey).get(10, TimeUnit.SECONDS);
|
||||
assertEquals(acl.getGrants().size(), 3);
|
||||
assertEquals(acl.getPermissions(GroupGranteeURI.ALL_USERS).size(), 2);
|
||||
assertTrue(acl.getOwner() != null);
|
||||
String ownerId = acl.getOwner().getId();
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ));
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.WRITE));
|
||||
assertFalse(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ_ACP));
|
||||
assertFalse(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.WRITE_ACP));
|
||||
assertFalse(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.FULL_CONTROL));
|
||||
} catch (Exception e) {
|
||||
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testUpdateObjectACL() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
String objectKey = "private-acl";
|
||||
|
||||
// Private object
|
||||
addBlobToContainer(containerName, objectKey);
|
||||
AccessControlList acl = context.getApi().getBlobACL(containerName, objectKey).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
String ownerId = acl.getOwner().getId();
|
||||
|
||||
assertEquals(acl.getGrants().size(), 1);
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
|
||||
|
||||
addGrantsToACL(acl);
|
||||
assertEquals(acl.getGrants().size(), 4);
|
||||
assertTrue(context.getApi().putBlobACL(containerName, objectKey, acl).get(10,
|
||||
TimeUnit.SECONDS));
|
||||
|
||||
// Confirm that the updated ACL has stuck.
|
||||
acl = context.getApi().getBlobACL(containerName, objectKey).get(10, TimeUnit.SECONDS);
|
||||
checkGrants(acl);
|
||||
|
||||
/*
|
||||
* Revoke all of owner's permissions!
|
||||
*/
|
||||
acl.revokeAllPermissions(new CanonicalUserGrantee(ownerId));
|
||||
if (!ownerId.equals(TEST_ACL_ID))
|
||||
acl.revokeAllPermissions(new CanonicalUserGrantee(TEST_ACL_ID));
|
||||
assertEquals(acl.getGrants().size(), 1);
|
||||
// Only public read permission should remain...
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ));
|
||||
|
||||
// Update the object's ACL settings
|
||||
assertTrue(context.getApi().putBlobACL(containerName, objectKey, acl).get(10,
|
||||
TimeUnit.SECONDS));
|
||||
|
||||
// Confirm that the updated ACL has stuck
|
||||
acl = context.getApi().getBlobACL(containerName, objectKey).get(10, TimeUnit.SECONDS);
|
||||
assertEquals(acl.getGrants().size(), 1);
|
||||
assertEquals(acl.getPermissions(ownerId).size(), 0);
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ), acl.toString());
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void checkGrants(AccessControlList acl) {
|
||||
String ownerId = acl.getOwner().getId();
|
||||
|
||||
assertEquals(acl.getGrants().size(), 4, acl.toString());
|
||||
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL), acl.toString());
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ), acl.toString());
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.WRITE_ACP), acl.toString());
|
||||
// EmailAddressGrantee is replaced by a CanonicalUserGrantee, so we cannot test by email addr
|
||||
assertTrue(acl.hasPermission(TEST_ACL_ID, Permission.READ_ACP), acl.toString());
|
||||
}
|
||||
|
||||
private void addGrantsToACL(AccessControlList acl) {
|
||||
String ownerId = acl.getOwner().getId();
|
||||
acl.addPermission(GroupGranteeURI.ALL_USERS, Permission.READ);
|
||||
acl.addPermission(new EmailAddressGrantee(TEST_ACL_EMAIL), Permission.READ_ACP);
|
||||
acl.addPermission(new CanonicalUserGrantee(ownerId), Permission.WRITE_ACP);
|
||||
}
|
||||
|
||||
public void testPrivateAclIsDefaultForObject() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException {
|
||||
String privateObjectKey = "private-acl";
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
// Private object
|
||||
addBlobToContainer(containerName, privateObjectKey);
|
||||
AccessControlList acl = context.getApi().getBlobACL(containerName, privateObjectKey).get(
|
||||
10, TimeUnit.SECONDS);
|
||||
|
||||
assertEquals(acl.getGrants().size(), 1);
|
||||
assertTrue(acl.getOwner() != null);
|
||||
String ownerId = acl.getOwner().getId();
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testPublicReadOnObject() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException {
|
||||
final String publicReadObjectKey = "public-read-acl";
|
||||
final String containerName = getContainerName();
|
||||
try {
|
||||
context.getApi().putBlob(containerName, new S3Object(publicReadObjectKey, ""),
|
||||
new PutObjectOptions().withAcl(CannedAccessPolicy.PUBLIC_READ)).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
|
||||
assertEventually(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
AccessControlList acl = context.getApi().getBlobACL(containerName,
|
||||
publicReadObjectKey).get(10, TimeUnit.SECONDS);
|
||||
|
||||
assertEquals(acl.getGrants().size(), 2);
|
||||
assertEquals(acl.getPermissions(GroupGranteeURI.ALL_USERS).size(), 1);
|
||||
assertTrue(acl.getOwner() != null);
|
||||
String ownerId = acl.getOwner().getId();
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ));
|
||||
} catch (Exception e) {
|
||||
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testMetadataWithCacheControlAndContentDisposition() throws Exception {
|
||||
String key = "hello";
|
||||
|
||||
S3Object object = context.newBlob(key);
|
||||
object.setData(TEST_STRING);
|
||||
object.getMetadata().setCacheControl("no-cache");
|
||||
object.getMetadata().setContentDisposition("attachment; filename=hello.txt");
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
addBlobToContainer(containerName, object);
|
||||
S3Object newObject = validateContent(containerName, key);
|
||||
|
||||
assertEquals(newObject.getMetadata().getCacheControl(), "no-cache");
|
||||
assertEquals(newObject.getMetadata().getContentDisposition(),
|
||||
"attachment; filename=hello.txt");
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(groups = { "integration", "live" })
|
||||
public void testMetadataContentEncoding() throws Exception {
|
||||
String key = "hello";
|
||||
|
||||
S3Object object = context.newBlob(key);
|
||||
object.setData(TEST_STRING);
|
||||
object.getMetadata().setContentEncoding("x-compress");
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
addBlobToContainer(containerName, object);
|
||||
S3Object newObject = validateContent(containerName, key);
|
||||
|
||||
assertEquals(newObject.getMetadata().getContentEncoding(), "x-compress");
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
}
|
||||
|
||||
public void testCopyObject() throws Exception {
|
||||
String containerName = getContainerName();
|
||||
String destinationContainer = getContainerName();
|
||||
|
||||
try {
|
||||
addToContainerAndValidate(containerName, sourceKey);
|
||||
|
||||
context.getApi().copyBlob(containerName, sourceKey, destinationContainer, destinationKey)
|
||||
.get(10, TimeUnit.SECONDS);
|
||||
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
returnContainer(destinationContainer);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void addToContainerAndValidate(String containerName, String sourceKey)
|
||||
throws InterruptedException, ExecutionException, TimeoutException, IOException {
|
||||
addBlobToContainer(containerName, sourceKey);
|
||||
validateContent(containerName, sourceKey);
|
||||
}
|
||||
|
||||
// TODO: fails on linux and windows
|
||||
public void testCopyIfModifiedSince() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException {
|
||||
String containerName = getContainerName();
|
||||
String destinationContainer = getContainerName();
|
||||
try {
|
||||
DateTime before = new DateTime();
|
||||
addToContainerAndValidate(containerName, sourceKey + "mod");
|
||||
DateTime after = new DateTime().plusSeconds(1);
|
||||
|
||||
context.getApi().copyBlob(containerName, sourceKey + "mod", destinationContainer,
|
||||
destinationKey, ifSourceModifiedSince(before)).get(10, TimeUnit.SECONDS);
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
try {
|
||||
context.getApi().copyBlob(containerName, sourceKey + "mod", destinationContainer,
|
||||
destinationKey, ifSourceModifiedSince(after)).get(10, TimeUnit.SECONDS);
|
||||
} catch (ExecutionException e) {
|
||||
if (e.getCause() instanceof HttpResponseException) {
|
||||
HttpResponseException ex = (HttpResponseException) e.getCause();
|
||||
assertEquals(ex.getResponse().getStatusCode(), 412);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
returnContainer(destinationContainer);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: fails on linux and windows
|
||||
public void testCopyIfUnmodifiedSince() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException {
|
||||
String containerName = getContainerName();
|
||||
String destinationContainer = getContainerName();
|
||||
try {
|
||||
DateTime before = new DateTime();
|
||||
addToContainerAndValidate(containerName, sourceKey + "un");
|
||||
DateTime after = new DateTime().plusSeconds(1);
|
||||
|
||||
context.getApi().copyBlob(containerName, sourceKey + "un", destinationContainer,
|
||||
destinationKey, ifSourceUnmodifiedSince(after)).get(10, TimeUnit.SECONDS);
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
try {
|
||||
context.getApi().copyBlob(containerName, sourceKey + "un", destinationContainer,
|
||||
destinationKey, ifSourceModifiedSince(before)).get(10, TimeUnit.SECONDS);
|
||||
} catch (ExecutionException e) {
|
||||
HttpResponseException ex = (HttpResponseException) e.getCause();
|
||||
assertEquals(ex.getResponse().getStatusCode(), 412);
|
||||
}
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
returnContainer(destinationContainer);
|
||||
}
|
||||
}
|
||||
|
||||
public void testCopyIfMatch() throws InterruptedException, ExecutionException, TimeoutException,
|
||||
IOException {
|
||||
String containerName = getContainerName();
|
||||
String destinationContainer = getContainerName();
|
||||
try {
|
||||
addToContainerAndValidate(containerName, sourceKey);
|
||||
|
||||
context.getApi().copyBlob(containerName, sourceKey, destinationContainer, destinationKey,
|
||||
ifSourceETagMatches(goodETag)).get(10, TimeUnit.SECONDS);
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
try {
|
||||
context.getApi().copyBlob(containerName, sourceKey, destinationContainer,
|
||||
destinationKey, ifSourceETagMatches(badETag)).get(10, TimeUnit.SECONDS);
|
||||
} catch (ExecutionException e) {
|
||||
HttpResponseException ex = (HttpResponseException) e.getCause();
|
||||
assertEquals(ex.getResponse().getStatusCode(), 412);
|
||||
}
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
returnContainer(destinationContainer);
|
||||
}
|
||||
}
|
||||
|
||||
public void testCopyIfNoneMatch() throws IOException, InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
String containerName = getContainerName();
|
||||
String destinationContainer = getContainerName();
|
||||
try {
|
||||
addToContainerAndValidate(containerName, sourceKey);
|
||||
|
||||
context.getApi().copyBlob(containerName, sourceKey, destinationContainer, destinationKey,
|
||||
ifSourceETagDoesntMatch(badETag)).get(10, TimeUnit.SECONDS);
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
try {
|
||||
context.getApi().copyBlob(containerName, sourceKey, destinationContainer,
|
||||
destinationKey, ifSourceETagDoesntMatch(goodETag)).get(10, TimeUnit.SECONDS);
|
||||
} catch (ExecutionException e) {
|
||||
HttpResponseException ex = (HttpResponseException) e.getCause();
|
||||
assertEquals(ex.getResponse().getStatusCode(), 412);
|
||||
}
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
returnContainer(destinationContainer);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void testCopyWithMetadata() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException {
|
||||
String containerName = getContainerName();
|
||||
String destinationContainer = getContainerName();
|
||||
try {
|
||||
addToContainerAndValidate(containerName, sourceKey);
|
||||
|
||||
Multimap<String, String> metadata = HashMultimap.create();
|
||||
metadata.put("adrian", "cole");
|
||||
|
||||
context.getApi().copyBlob(containerName, sourceKey, destinationContainer, destinationKey,
|
||||
overrideMetadataWith(metadata)).get(10, TimeUnit.SECONDS);
|
||||
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
ObjectMetadata objectMeta = context.getApi().blobMetadata(destinationContainer,
|
||||
destinationKey);
|
||||
|
||||
assertEquals(objectMeta.getUserMetadata(), metadata);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
returnContainer(destinationContainer);
|
||||
|
||||
}
|
||||
}
|
||||
BaseBlobIntegrationTest<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
|
||||
}
|
|
@ -23,19 +23,11 @@
|
|||
*/
|
||||
package org.jclouds.aws.s3.integration;
|
||||
|
||||
import static org.jclouds.aws.s3.options.CopyObjectOptions.Builder.overrideAcl;
|
||||
import static org.jclouds.aws.s3.options.PutObjectOptions.Builder.withAcl;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.aws.s3.S3BlobStore;
|
||||
import org.jclouds.aws.s3.S3Connection;
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.blobstore.integration.internal.BaseBlobLiveTest;
|
||||
import org.jclouds.util.Utils;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
|
@ -45,48 +37,6 @@ import org.testng.annotations.Test;
|
|||
*/
|
||||
@Test(groups = { "live" }, testName = "s3.S3BlobLiveTest")
|
||||
public class S3BlobLiveTest extends
|
||||
BaseBlobLiveTest<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
|
||||
public void testPutCannedAccessPolicyPublic() throws Exception {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
String key = "hello";
|
||||
|
||||
context.getApi().putBlob(containerName, new S3Object(key, TEST_STRING),
|
||||
|
||||
withAcl(CannedAccessPolicy.PUBLIC_READ)).get(10, TimeUnit.SECONDS);
|
||||
|
||||
URL url = new URL(String.format("http://%1$s.s3.amazonaws.com/%2$s", containerName, key));
|
||||
Utils.toStringAndClose(url.openStream());
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
String sourceKey = "apples";
|
||||
String destinationKey = "pears";
|
||||
|
||||
public void testCopyCannedAccessPolicyPublic() throws Exception {
|
||||
String containerName = getContainerName();
|
||||
String destinationContainer = getContainerName();
|
||||
try {
|
||||
addBlobToContainer(containerName, sourceKey);
|
||||
validateContent(containerName, sourceKey);
|
||||
|
||||
context.getApi().copyBlob(containerName, sourceKey, destinationContainer, destinationKey,
|
||||
overrideAcl(CannedAccessPolicy.PUBLIC_READ)).get(10, TimeUnit.SECONDS);
|
||||
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
URL url = new URL(String.format("http://%1$s.s3.amazonaws.com/%2$s", destinationContainer,
|
||||
destinationKey));
|
||||
Utils.toStringAndClose(url.openStream());
|
||||
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
returnContainer(destinationContainer);
|
||||
}
|
||||
}
|
||||
BaseBlobLiveTest<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
*/
|
||||
package org.jclouds.aws.s3.integration;
|
||||
|
||||
import org.jclouds.aws.s3.S3BlobStore;
|
||||
import org.jclouds.aws.s3.S3Connection;
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
|
@ -35,6 +35,6 @@ import org.testng.annotations.Test;
|
|||
*/
|
||||
@Test(groups = { "integration", "live" }, testName = "s3.S3BlobMapIntegrationTest")
|
||||
public class S3BlobMapIntegrationTest extends
|
||||
BaseBlobMapIntegrationTest<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
BaseBlobMapIntegrationTest<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
|
||||
}
|
|
@ -23,31 +23,10 @@
|
|||
*/
|
||||
package org.jclouds.aws.s3.integration;
|
||||
|
||||
import static org.jclouds.aws.s3.internal.StubS3BlobStore.TEST_ACL_EMAIL;
|
||||
import static org.jclouds.aws.s3.internal.StubS3BlobStore.TEST_ACL_ID;
|
||||
import static org.jclouds.aws.s3.options.ListBucketOptions.Builder.afterMarker;
|
||||
import static org.jclouds.aws.s3.options.ListBucketOptions.Builder.delimiter;
|
||||
import static org.jclouds.aws.s3.options.ListBucketOptions.Builder.maxResults;
|
||||
import static org.jclouds.aws.s3.options.ListBucketOptions.Builder.withPrefix;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.aws.s3.S3BlobStore;
|
||||
import org.jclouds.aws.s3.domain.AccessControlList;
|
||||
import org.jclouds.aws.s3.S3Connection;
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.ListBucketResponse;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.aws.s3.domain.AccessControlList.CanonicalUserGrantee;
|
||||
import org.jclouds.aws.s3.domain.AccessControlList.EmailAddressGrantee;
|
||||
import org.jclouds.aws.s3.domain.AccessControlList.GroupGranteeURI;
|
||||
import org.jclouds.aws.s3.domain.AccessControlList.Permission;
|
||||
import org.jclouds.blobstore.integration.internal.BaseContainerIntegrationTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
|
@ -57,133 +36,6 @@ import org.testng.annotations.Test;
|
|||
*/
|
||||
@Test(groups = { "integration", "live" }, testName = "s3.S3ContainerIntegrationTest")
|
||||
public class S3ContainerIntegrationTest extends
|
||||
BaseContainerIntegrationTest<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
|
||||
public void testListContainerDelimiter() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, UnsupportedEncodingException {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
String prefix = "apps";
|
||||
addTenObjectsUnderPrefix(containerName, prefix);
|
||||
add15UnderRoot(containerName);
|
||||
ListBucketResponse container = context.getApi().listBlobs(containerName, delimiter("/"))
|
||||
.get(10, TimeUnit.SECONDS);
|
||||
assertEquals(container.getDelimiter(), "/");
|
||||
assert !container.isTruncated();
|
||||
assertEquals(container.size(), 15);
|
||||
assertEquals(container.getCommonPrefixes().size(), 1);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testListContainerPrefix() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, UnsupportedEncodingException {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
String prefix = "apps";
|
||||
addTenObjectsUnderPrefix(containerName, prefix);
|
||||
add15UnderRoot(containerName);
|
||||
|
||||
ListBucketResponse container = context.getApi().listBlobs(containerName,
|
||||
withPrefix("apps/")).get(10, TimeUnit.SECONDS);
|
||||
assert !container.isTruncated();
|
||||
assertEquals(container.size(), 10);
|
||||
assertEquals(container.getPrefix(), "apps/");
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testPrivateAclIsDefaultForContainer() throws InterruptedException,
|
||||
ExecutionException, TimeoutException, IOException {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
AccessControlList acl = context.getApi().getContainerACL(containerName).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
assertEquals(acl.getGrants().size(), 1);
|
||||
assertTrue(acl.getOwner() != null);
|
||||
String ownerId = acl.getOwner().getId();
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testUpdateContainerACL() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException, Exception {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
// Confirm the container is private
|
||||
AccessControlList acl = context.getApi().getContainerACL(containerName).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
String ownerId = acl.getOwner().getId();
|
||||
assertEquals(acl.getGrants().size(), 1);
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
|
||||
|
||||
addGrantsToACL(acl);
|
||||
assertEquals(acl.getGrants().size(), 4);
|
||||
assertTrue(context.getApi().putContainerACL(containerName, acl).get(10, TimeUnit.SECONDS));
|
||||
|
||||
// Confirm that the updated ACL has stuck.
|
||||
acl = context.getApi().getContainerACL(containerName).get(10, TimeUnit.SECONDS);
|
||||
checkGrants(acl);
|
||||
} finally {
|
||||
destroyContainer(containerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void checkGrants(AccessControlList acl) {
|
||||
String ownerId = acl.getOwner().getId();
|
||||
|
||||
assertEquals(acl.getGrants().size(), 4, acl.toString());
|
||||
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL), acl.toString());
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ), acl.toString());
|
||||
assertTrue(acl.hasPermission(ownerId, Permission.WRITE_ACP), acl.toString());
|
||||
// EmailAddressGrantee is replaced by a CanonicalUserGrantee, so we cannot test by email addr
|
||||
assertTrue(acl.hasPermission(TEST_ACL_ID, Permission.READ_ACP), acl.toString());
|
||||
}
|
||||
|
||||
private void addGrantsToACL(AccessControlList acl) {
|
||||
String ownerId = acl.getOwner().getId();
|
||||
acl.addPermission(GroupGranteeURI.ALL_USERS, Permission.READ);
|
||||
acl.addPermission(new EmailAddressGrantee(TEST_ACL_EMAIL), Permission.READ_ACP);
|
||||
acl.addPermission(new CanonicalUserGrantee(ownerId), Permission.WRITE_ACP);
|
||||
}
|
||||
|
||||
public void testListContainerMarker() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, UnsupportedEncodingException {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
addAlphabetUnderRoot(containerName);
|
||||
ListBucketResponse container = context.getApi().listBlobs(containerName, afterMarker("y"))
|
||||
.get(10, TimeUnit.SECONDS);
|
||||
assertEquals(container.getMarker(), "y");
|
||||
assert !container.isTruncated();
|
||||
assertEquals(container.size(), 1);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
}
|
||||
|
||||
public void testListContainerMaxResults() throws InterruptedException, ExecutionException,
|
||||
TimeoutException, UnsupportedEncodingException {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
addAlphabetUnderRoot(containerName);
|
||||
ListBucketResponse container = context.getApi().listBlobs(containerName, maxResults(5))
|
||||
.get(10, TimeUnit.SECONDS);
|
||||
assertEquals(container.getMaxResults(), 5);
|
||||
assert container.isTruncated();
|
||||
assertEquals(container.size(), 5);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
}
|
||||
BaseContainerIntegrationTest<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
|
||||
}
|
|
@ -23,25 +23,11 @@
|
|||
*/
|
||||
package org.jclouds.aws.s3.integration;
|
||||
|
||||
import static org.jclouds.aws.s3.options.PutBucketOptions.Builder.createIn;
|
||||
import static org.jclouds.aws.s3.options.PutBucketOptions.Builder.withBucketAcl;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.aws.s3.S3BlobStore;
|
||||
import org.jclouds.aws.s3.domain.AccessControlList;
|
||||
import org.jclouds.aws.s3.S3Connection;
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
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.BucketMetadata.LocationConstraint;
|
||||
import org.jclouds.blobstore.integration.internal.BaseContainerLiveTest;
|
||||
import org.jclouds.util.Utils;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
|
@ -50,63 +36,6 @@ import org.testng.annotations.Test;
|
|||
*/
|
||||
@Test(groups = { "live" }, testName = "s3.S3ContainerLiveTest")
|
||||
public class S3ContainerLiveTest extends
|
||||
BaseContainerLiveTest<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
|
||||
public void testPublicReadAccessPolicy() throws Exception {
|
||||
String containerName = getScratchContainerName();
|
||||
try {
|
||||
context.getApi().createContainer(containerName, withBucketAcl(CannedAccessPolicy.PUBLIC_READ)).get(
|
||||
10, TimeUnit.SECONDS);
|
||||
AccessControlList acl = context.getApi().getContainerACL(containerName).get(10, TimeUnit.SECONDS);
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ), acl.toString());
|
||||
// TODO: I believe that the following should work based on the above acl assertion passing.
|
||||
// However, it fails on 403
|
||||
// URL url = new URL(String.format("http://%s.s3.amazonaws.com", containerName));
|
||||
// Utils.toStringAndClose(url.openStream());
|
||||
} finally {
|
||||
destroyContainer(containerName);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IOException.class)
|
||||
public void testDefaultAccessPolicy() throws Exception {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
URL url = new URL(String.format("https://%s.s3.amazonaws.com", containerName));
|
||||
Utils.toStringAndClose(url.openStream());
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
BaseContainerLiveTest<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* using scratch containerName as we are changing location
|
||||
*/
|
||||
public void testEu() throws Exception {
|
||||
final String containerName = getScratchContainerName();
|
||||
try {
|
||||
context.getApi().createContainer(containerName + "eu",
|
||||
createIn(LocationConstraint.EU).withBucketAcl(CannedAccessPolicy.PUBLIC_READ))
|
||||
.get(30, TimeUnit.SECONDS);
|
||||
assertEventually(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
AccessControlList acl = context.getApi().getContainerACL(containerName + "eu").get(30,
|
||||
TimeUnit.SECONDS);
|
||||
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ), acl
|
||||
.toString());
|
||||
} catch (Exception e) {
|
||||
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
// TODO: I believe that the following should work based on the above acl assertion passing.
|
||||
// However, it fails on 403
|
||||
// URL url = new URL(String.format("http://%s.s3.amazonaws.com", containerName));
|
||||
// Utils.toStringAndClose(url.openStream());
|
||||
} finally {
|
||||
destroyContainer(containerName + "eu");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
*/
|
||||
package org.jclouds.aws.s3.integration;
|
||||
|
||||
import org.jclouds.aws.s3.S3BlobStore;
|
||||
import org.jclouds.aws.s3.S3Connection;
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
|
@ -35,6 +35,6 @@ import org.testng.annotations.Test;
|
|||
*/
|
||||
@Test(groups = { "integration", "live" }, testName = "s3.S3InputStreamMapIntegrationTest")
|
||||
public class S3InputStreamMapIntegrationTest extends
|
||||
BaseInputStreamMapIntegrationTest<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
BaseInputStreamMapIntegrationTest<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
|
||||
}
|
|
@ -23,9 +23,7 @@
|
|||
*/
|
||||
package org.jclouds.aws.s3.integration;
|
||||
|
||||
import java.util.SortedSet;
|
||||
|
||||
import org.jclouds.aws.s3.S3BlobStore;
|
||||
import org.jclouds.aws.s3.S3Connection;
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
|
@ -37,18 +35,6 @@ import org.testng.annotations.Test;
|
|||
*/
|
||||
@Test(groups = { "integration", "live" }, testName = "s3.S3ServiceIntegrationTest")
|
||||
public class S3ServiceIntegrationTest extends
|
||||
BaseServiceIntegrationTest<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
BaseServiceIntegrationTest<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
|
||||
void containerExists() throws Exception {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
SortedSet<BucketMetadata> list = context.getApi().listContainers();
|
||||
BucketMetadata firstContainer = list.first();
|
||||
BucketMetadata toMatch = new BucketMetadata(containerName);
|
||||
toMatch.setOwner(firstContainer.getOwner());
|
||||
assert list.contains(toMatch);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
*/
|
||||
package org.jclouds.aws.s3.integration;
|
||||
|
||||
import org.jclouds.aws.s3.S3BlobStore;
|
||||
import org.jclouds.aws.s3.S3Connection;
|
||||
import org.jclouds.aws.s3.S3ContextBuilder;
|
||||
import org.jclouds.aws.s3.S3ContextFactory;
|
||||
import org.jclouds.aws.s3.config.StubS3BlobStoreModule;
|
||||
|
@ -42,10 +42,10 @@ import com.google.inject.Module;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
public class S3TestInitializer extends
|
||||
BaseTestInitializer<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
BaseTestInitializer<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
|
||||
@Override
|
||||
protected BlobStoreContext<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> createLiveContext(
|
||||
protected BlobStoreContext<S3Connection, BucketMetadata, ObjectMetadata, S3Object> createLiveContext(
|
||||
Module configurationModule, String url, String app, String account, String key) {
|
||||
BaseBlobStoreIntegrationTest.SANITY_CHECK_RETURNED_BUCKET_NAME = true;
|
||||
return new S3ContextBuilder(account, key).withSaxDebug().relaxSSLHostname().withModules(
|
||||
|
@ -53,7 +53,7 @@ public class S3TestInitializer extends
|
|||
}
|
||||
|
||||
@Override
|
||||
protected BlobStoreContext<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> createStubContext() {
|
||||
protected BlobStoreContext<S3Connection, BucketMetadata, ObjectMetadata, S3Object> createStubContext() {
|
||||
return S3ContextFactory.createContext("user", "pass", new StubS3BlobStoreModule());
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ import javax.inject.Inject;
|
|||
import javax.inject.Provider;
|
||||
|
||||
import org.jclouds.aws.s3.S3BlobStore;
|
||||
import org.jclouds.aws.s3.S3Connection;
|
||||
import org.jclouds.aws.s3.domain.AccessControlList;
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
|
||||
|
@ -70,11 +71,11 @@ import com.google.inject.internal.Nullable;
|
|||
* @author Adrian Cole
|
||||
* @author James Murty
|
||||
*/
|
||||
public class StubS3BlobStore extends StubBlobStore<BucketMetadata, ObjectMetadata, S3Object>
|
||||
implements S3BlobStore {
|
||||
public class StubS3Connection extends StubBlobStore<BucketMetadata, ObjectMetadata, S3Object>
|
||||
implements S3Connection {
|
||||
|
||||
@Inject
|
||||
protected StubS3BlobStore(Map<String, Map<String, S3Object>> containerToBlobs,
|
||||
protected StubS3Connection(Map<String, Map<String, S3Object>> containerToBlobs,
|
||||
DateService dateService, Provider<BucketMetadata> containerMetaProvider,
|
||||
Provider<S3Object> blobProvider) {
|
||||
super(containerToBlobs, dateService, containerMetaProvider, blobProvider);
|
||||
|
@ -91,16 +92,18 @@ public class StubS3BlobStore extends StubBlobStore<BucketMetadata, ObjectMetadat
|
|||
|
||||
public static final String DEFAULT_OWNER_ID = "abc123";
|
||||
|
||||
public Future<Boolean> createContainer(String name, @Nullable PutBucketOptions nullableOptions) {
|
||||
final PutBucketOptions options = (nullableOptions == null) ? new PutBucketOptions()
|
||||
: nullableOptions;
|
||||
public Future<Boolean> putBucketIfNotExists(String name, PutBucketOptions... optionsList) {
|
||||
final PutBucketOptions options = (optionsList.length == 0) ? new PutBucketOptions()
|
||||
: optionsList[0];
|
||||
if (options.getLocationConstraint() != null)
|
||||
bucketToLocation.put(name, options.getLocationConstraint());
|
||||
keyToAcl.put(name, options.getAcl());
|
||||
return super.createContainer(name);
|
||||
}
|
||||
|
||||
public Future<ListBucketResponse> listBlobs(final String name, final ListBucketOptions options) {
|
||||
public Future<ListBucketResponse> listBucket(final String name, ListBucketOptions... optionsList) {
|
||||
final ListBucketOptions options = (optionsList.length == 0) ? new ListBucketOptions()
|
||||
: optionsList[0];
|
||||
return new FutureBase<ListBucketResponse>() {
|
||||
public ListBucketResponse get() throws InterruptedException, ExecutionException {
|
||||
final Map<String, S3Object> realContents = getContainerToBlobs().get(name);
|
||||
|
@ -172,11 +175,11 @@ public class StubS3BlobStore extends StubBlobStore<BucketMetadata, ObjectMetadat
|
|||
};
|
||||
}
|
||||
|
||||
public Future<ObjectMetadata> copyBlob(final String sourceBucket, final String sourceObject,
|
||||
public Future<ObjectMetadata> copyObject(final String sourceBucket, final String sourceObject,
|
||||
final String destinationBucket, final String destinationObject,
|
||||
@Nullable CopyObjectOptions nullableOptions) {
|
||||
final CopyObjectOptions options = (nullableOptions == null) ? new CopyObjectOptions()
|
||||
: nullableOptions;
|
||||
CopyObjectOptions... nullableOptions) {
|
||||
final CopyObjectOptions options = (nullableOptions.length == 0) ? new CopyObjectOptions()
|
||||
: nullableOptions[0];
|
||||
return new FutureBase<ObjectMetadata>() {
|
||||
public ObjectMetadata get() throws InterruptedException, ExecutionException {
|
||||
Map<String, S3Object> source = getContainerToBlobs().get(sourceBucket);
|
||||
|
@ -223,7 +226,7 @@ public class StubS3BlobStore extends StubBlobStore<BucketMetadata, ObjectMetadat
|
|||
};
|
||||
}
|
||||
|
||||
public Future<byte[]> putBlob(final String bucketName, final S3Object object,
|
||||
public Future<byte[]> putObject(final String bucketName, final S3Object object,
|
||||
@Nullable PutObjectOptions nullableOptions) {
|
||||
final PutObjectOptions options = (nullableOptions == null) ? new PutObjectOptions()
|
||||
: nullableOptions;
|
||||
|
@ -248,7 +251,7 @@ public class StubS3BlobStore extends StubBlobStore<BucketMetadata, ObjectMetadat
|
|||
return acl;
|
||||
}
|
||||
|
||||
public Future<AccessControlList> getContainerACL(final String bucket) {
|
||||
public Future<AccessControlList> getBucketACL(final String bucket) {
|
||||
return new FutureBase<AccessControlList>() {
|
||||
public AccessControlList get() throws InterruptedException, ExecutionException {
|
||||
return getACLforS3Item(bucket);
|
||||
|
@ -256,7 +259,7 @@ public class StubS3BlobStore extends StubBlobStore<BucketMetadata, ObjectMetadat
|
|||
};
|
||||
}
|
||||
|
||||
public Future<AccessControlList> getBlobACL(final String bucket, final String objectKey) {
|
||||
public Future<AccessControlList> getObjectACL(final String bucket, final String objectKey) {
|
||||
return new FutureBase<AccessControlList>() {
|
||||
public AccessControlList get() throws InterruptedException, ExecutionException {
|
||||
return getACLforS3Item(bucket + "/" + objectKey);
|
||||
|
@ -287,7 +290,7 @@ public class StubS3BlobStore extends StubBlobStore<BucketMetadata, ObjectMetadat
|
|||
return acl;
|
||||
}
|
||||
|
||||
public Future<Boolean> putContainerACL(final String bucket, final AccessControlList acl) {
|
||||
public Future<Boolean> putBucketACL(final String bucket, final AccessControlList acl) {
|
||||
return new FutureBase<Boolean>() {
|
||||
public Boolean get() throws InterruptedException, ExecutionException {
|
||||
keyToAcl.put(bucket, sanitizeUploadedACL(acl));
|
||||
|
@ -296,7 +299,7 @@ public class StubS3BlobStore extends StubBlobStore<BucketMetadata, ObjectMetadat
|
|||
};
|
||||
}
|
||||
|
||||
public Future<Boolean> putBlobACL(final String bucket, final String objectKey,
|
||||
public Future<Boolean> putObjectACL(final String bucket, final String objectKey,
|
||||
final AccessControlList acl) {
|
||||
return new FutureBase<Boolean>() {
|
||||
public Boolean get() throws InterruptedException, ExecutionException {
|
||||
|
@ -306,27 +309,33 @@ public class StubS3BlobStore extends StubBlobStore<BucketMetadata, ObjectMetadat
|
|||
};
|
||||
}
|
||||
|
||||
public Future<ObjectMetadata> copyBlob(String sourceBucket, String sourceObject,
|
||||
String destinationBucket, String destinationObject) {
|
||||
return copyBlob(sourceBucket, sourceObject, destinationBucket, destinationObject,
|
||||
CopyObjectOptions.NONE);
|
||||
public Future<S3Object> getObject(String bucketName, String key, GetOptions... optionsList) {
|
||||
return super.getBlob(bucketName, key, optionsList.length != 0 ? optionsList[0] : null);
|
||||
}
|
||||
|
||||
public Future<Boolean> createContainer(String bucketName) {
|
||||
return createContainer(bucketName, PutBucketOptions.NONE);
|
||||
public Future<byte[]> putObject(String bucketName, S3Object object,
|
||||
PutObjectOptions... optionsList) {
|
||||
return putObject(bucketName, object, optionsList.length != 0 ? optionsList[0] : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<S3Object> getBlob(String bucketName, String key) {
|
||||
return getBlob(bucketName, key, GetOptions.NONE);
|
||||
public boolean bucketExists(String bucketName) {
|
||||
return super.containerExists(bucketName);
|
||||
}
|
||||
|
||||
public Future<ListBucketResponse> listBlobs(String bucketName) {
|
||||
return listBlobs(bucketName, ListBucketOptions.NONE);
|
||||
public Future<Boolean> deleteBucketIfEmpty(String bucketName) {
|
||||
return super.deleteContainerImpl(bucketName);
|
||||
}
|
||||
|
||||
public Future<byte[]> putBlob(String bucketName, S3Object object) {
|
||||
return putBlob(bucketName, object, PutObjectOptions.NONE);
|
||||
public Future<Void> deleteObject(String bucketName, String key) {
|
||||
return super.removeBlob(bucketName, key);
|
||||
}
|
||||
|
||||
public ObjectMetadata headObject(String bucketName, String key) {
|
||||
return super.blobMetadata(bucketName, key);
|
||||
}
|
||||
|
||||
public SortedSet<BucketMetadata> listOwnedBuckets() {
|
||||
return super.listContainers();
|
||||
}
|
||||
|
||||
}
|
|
@ -33,6 +33,7 @@ import java.util.SortedSet;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.aws.s3.S3BlobStore;
|
||||
import org.jclouds.aws.s3.S3Connection;
|
||||
import org.jclouds.aws.s3.S3ContextFactory;
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.ListBucketResponse;
|
||||
|
@ -65,8 +66,8 @@ public class JCloudsS3Service extends S3Service {
|
|||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final BlobStoreContext<S3BlobStore, BucketMetadata, ObjectMetadata, org.jclouds.aws.s3.domain.S3Object> context;
|
||||
private final S3BlobStore connection;
|
||||
private final BlobStoreContext<S3Connection, BucketMetadata, ObjectMetadata, org.jclouds.aws.s3.domain.S3Object> context;
|
||||
private final S3Connection connection;
|
||||
|
||||
private final long requestTimeoutMilliseconds = 10000;
|
||||
|
||||
|
@ -106,7 +107,7 @@ public class JCloudsS3Service extends S3Service {
|
|||
try {
|
||||
CopyObjectOptions options = Util.convertCopyObjectOptions(acl, destinationMetadata,
|
||||
ifModifiedSince, ifUnmodifiedSince, ifMatchTags, ifNoneMatchTags);
|
||||
org.jclouds.aws.s3.domain.ObjectMetadata jcObjectMetadata = connection.copyBlob(
|
||||
org.jclouds.aws.s3.domain.ObjectMetadata jcObjectMetadata = connection.copyObject(
|
||||
sourceBucketName, sourceObjectKey, destinationBucketName, destinationObjectKey,
|
||||
options).get(requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
|
||||
|
||||
|
@ -130,7 +131,7 @@ public class JCloudsS3Service extends S3Service {
|
|||
throw new UnsupportedOperationException("Bucket ACL is not yet supported");
|
||||
|
||||
try {
|
||||
if (connection.createContainer(bucketName).get(requestTimeoutMilliseconds,
|
||||
if (connection.putBucketIfNotExists(bucketName).get(requestTimeoutMilliseconds,
|
||||
TimeUnit.MILLISECONDS)) {
|
||||
// Bucket created.
|
||||
}
|
||||
|
@ -149,7 +150,7 @@ public class JCloudsS3Service extends S3Service {
|
|||
@Override
|
||||
protected void deleteBucketImpl(String bucketName) throws S3ServiceException {
|
||||
try {
|
||||
connection.deleteContainer(bucketName).get(requestTimeoutMilliseconds,
|
||||
connection.deleteBucketIfEmpty(bucketName).get(requestTimeoutMilliseconds,
|
||||
TimeUnit.MILLISECONDS);
|
||||
} catch (Exception e) {
|
||||
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
||||
|
@ -165,7 +166,7 @@ public class JCloudsS3Service extends S3Service {
|
|||
@Override
|
||||
protected void deleteObjectImpl(String bucketName, String objectKey) throws S3ServiceException {
|
||||
try {
|
||||
connection.removeBlob(bucketName, objectKey).get(requestTimeoutMilliseconds,
|
||||
connection.deleteObject(bucketName, objectKey).get(requestTimeoutMilliseconds,
|
||||
TimeUnit.MILLISECONDS);
|
||||
} catch (Exception e) {
|
||||
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
||||
|
@ -177,7 +178,7 @@ public class JCloudsS3Service extends S3Service {
|
|||
@Override
|
||||
protected AccessControlList getBucketAclImpl(String bucketName) throws S3ServiceException {
|
||||
try {
|
||||
org.jclouds.aws.s3.domain.AccessControlList jcACL = connection.getContainerACL(bucketName)
|
||||
org.jclouds.aws.s3.domain.AccessControlList jcACL = connection.getBucketACL(bucketName)
|
||||
.get(requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
|
||||
return Util.convertAccessControlList(jcACL);
|
||||
} catch (Exception e) {
|
||||
|
@ -203,7 +204,7 @@ public class JCloudsS3Service extends S3Service {
|
|||
protected AccessControlList getObjectAclImpl(String bucketName, String objectKey)
|
||||
throws S3ServiceException {
|
||||
try {
|
||||
org.jclouds.aws.s3.domain.AccessControlList jcACL = connection.getBlobACL(bucketName,
|
||||
org.jclouds.aws.s3.domain.AccessControlList jcACL = connection.getObjectACL(bucketName,
|
||||
objectKey).get(requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
|
||||
return Util.convertAccessControlList(jcACL);
|
||||
} catch (Exception e) {
|
||||
|
@ -226,7 +227,7 @@ public class JCloudsS3Service extends S3Service {
|
|||
if (ifNoneMatchTags != null)
|
||||
throw new IllegalArgumentException("ifNoneMatchTags");
|
||||
|
||||
return Util.convertObjectHead(connection.blobMetadata(bucketName, objectKey));
|
||||
return Util.convertObjectHead(connection.headObject(bucketName, objectKey));
|
||||
} catch (Exception e) {
|
||||
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
||||
throw new S3ServiceException(String.format("error retrieving object head: %1$s:%2$s",
|
||||
|
@ -241,7 +242,7 @@ public class JCloudsS3Service extends S3Service {
|
|||
try {
|
||||
GetOptions options = Util.convertGetObjectOptions(ifModifiedSince, ifUnmodifiedSince,
|
||||
ifMatchTags, ifNoneMatchTags);
|
||||
return Util.convertObject(connection.getBlob(bucketName, objectKey, options).get(
|
||||
return Util.convertObject(connection.getObject(bucketName, objectKey, options).get(
|
||||
requestTimeoutMilliseconds, TimeUnit.MILLISECONDS));
|
||||
} catch (Exception e) {
|
||||
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
||||
|
@ -265,7 +266,8 @@ public class JCloudsS3Service extends S3Service {
|
|||
@Override
|
||||
protected S3Bucket[] listAllBucketsImpl() throws S3ServiceException {
|
||||
try {
|
||||
SortedSet<org.jclouds.aws.s3.domain.BucketMetadata> jcBucketList = connection.listContainers();
|
||||
SortedSet<org.jclouds.aws.s3.domain.BucketMetadata> jcBucketList = connection
|
||||
.listOwnedBuckets();
|
||||
return Util.convertBuckets(jcBucketList);
|
||||
} catch (Exception e) {
|
||||
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
||||
|
@ -285,7 +287,7 @@ public class JCloudsS3Service extends S3Service {
|
|||
ListBucketOptions options = Util.convertListObjectOptions(prefix, priorLastKey,
|
||||
delimiter, maxListingLength);
|
||||
|
||||
jcBucket = connection.listBlobs(bucketName, options).get(requestTimeoutMilliseconds,
|
||||
jcBucket = connection.listBucket(bucketName, options).get(requestTimeoutMilliseconds,
|
||||
TimeUnit.MILLISECONDS);
|
||||
|
||||
jsObjects.addAll(Arrays.asList(Util.convertObjectHeads(jcBucket)));
|
||||
|
@ -325,7 +327,7 @@ public class JCloudsS3Service extends S3Service {
|
|||
throws S3ServiceException {
|
||||
try {
|
||||
org.jclouds.aws.s3.domain.AccessControlList jcACL = Util.convertAccessControlList(jsACL);
|
||||
connection.putContainerACL(bucketName, jcACL).get(requestTimeoutMilliseconds,
|
||||
connection.putBucketACL(bucketName, jcACL).get(requestTimeoutMilliseconds,
|
||||
TimeUnit.MILLISECONDS);
|
||||
} catch (Exception e) {
|
||||
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
||||
|
@ -338,7 +340,7 @@ public class JCloudsS3Service extends S3Service {
|
|||
throws S3ServiceException {
|
||||
try {
|
||||
org.jclouds.aws.s3.domain.AccessControlList jcACL = Util.convertAccessControlList(jsACL);
|
||||
connection.putBlobACL(bucketName, objectKey, jcACL).get(requestTimeoutMilliseconds,
|
||||
connection.putObjectACL(bucketName, objectKey, jcACL).get(requestTimeoutMilliseconds,
|
||||
TimeUnit.MILLISECONDS);
|
||||
} catch (Exception e) {
|
||||
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
||||
|
@ -351,7 +353,7 @@ public class JCloudsS3Service extends S3Service {
|
|||
try {
|
||||
PutObjectOptions options = Util.convertPutObjectOptions(jsObject.getAcl());
|
||||
org.jclouds.aws.s3.domain.S3Object jcObject = Util.convertObject(jsObject);
|
||||
byte eTag[] = connection.putBlob(bucketName, jcObject, options).get(
|
||||
byte eTag[] = connection.putObject(bucketName, jcObject, options).get(
|
||||
requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
|
||||
jsObject.setMd5Hash(eTag);
|
||||
return jsObject;
|
||||
|
|
|
@ -44,7 +44,7 @@ import java.util.concurrent.TimeoutException;
|
|||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jclouds.aws.s3.S3BlobStore;
|
||||
import org.jclouds.aws.s3.S3Connection;
|
||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.ListBucketResponse;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
|
@ -82,7 +82,7 @@ import com.google.common.collect.Iterators;
|
|||
@Test(groups = { "live" }, testName = "jets3t.JCloudsS3ServiceIntegrationTest")
|
||||
public class JCloudsS3ServiceLiveTest
|
||||
extends
|
||||
BaseBlobStoreIntegrationTest<S3BlobStore, BucketMetadata, ObjectMetadata, org.jclouds.aws.s3.domain.S3Object> {
|
||||
BaseBlobStoreIntegrationTest<S3Connection, BucketMetadata, ObjectMetadata, org.jclouds.aws.s3.domain.S3Object> {
|
||||
AWSCredentials credentials;
|
||||
S3Service service;
|
||||
|
||||
|
@ -112,7 +112,7 @@ public class JCloudsS3ServiceLiveTest
|
|||
try {
|
||||
S3Bucket bucket = service.createBucket(new S3Bucket(bucketName));
|
||||
assertEquals(bucket.getName(), bucketName);
|
||||
assertTrue(context.getApi().containerExists(bucketName));
|
||||
assertTrue(context.getApi().bucketExists(bucketName));
|
||||
} finally {
|
||||
returnContainer(bucketName);
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ public class JCloudsS3ServiceLiveTest
|
|||
service.deleteBucket(bucketName);
|
||||
assertEventually(new Runnable() {
|
||||
public void run() {
|
||||
assertFalse(context.getApi().containerExists(bucketName));
|
||||
assertFalse(context.getApi().bucketExists(bucketName));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ public class JCloudsS3ServiceLiveTest
|
|||
S3Bucket[] jsBuckets = service.listAllBuckets();
|
||||
|
||||
SortedSet<org.jclouds.aws.s3.domain.BucketMetadata> jcBuckets = context.getApi()
|
||||
.listContainers();
|
||||
.listOwnedBuckets();
|
||||
|
||||
assert jsBuckets.length == jcBuckets.size();
|
||||
|
||||
|
@ -363,7 +363,7 @@ public class JCloudsS3ServiceLiveTest
|
|||
// Upload empty object
|
||||
requestObject = new S3Object(objectKey);
|
||||
jsResultObject = service.putObject(new S3Bucket(bucketName), requestObject);
|
||||
jcObject = context.getApi().getBlob(bucketName, objectKey).get(10, TimeUnit.SECONDS);
|
||||
jcObject = context.getApi().getObject(bucketName, objectKey).get(10, TimeUnit.SECONDS);
|
||||
// TODO null keys from s3object! assertEquals(jcObject.getKey(), objectKey);
|
||||
assertEquals(jcObject.getMetadata().getSize(), 0);
|
||||
assertEquals(jcObject.getMetadata().getContentType(), MediaType.APPLICATION_OCTET_STREAM);
|
||||
|
@ -374,7 +374,7 @@ public class JCloudsS3ServiceLiveTest
|
|||
// Upload unicode-named object
|
||||
requestObject = new S3Object("Ÿn’<EFBFBD>˜dŽ-object");
|
||||
jsResultObject = service.putObject(new S3Bucket(bucketName), requestObject);
|
||||
jcObject = context.getApi().getBlob(bucketName, requestObject.getKey()).get(10,
|
||||
jcObject = context.getApi().getObject(bucketName, requestObject.getKey()).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
// TODO null keys from s3object! assertEquals(jcObject.getKey(), requestObject.getKey());
|
||||
assertEquals(jcObject.getMetadata().getSize(), 0);
|
||||
|
@ -387,7 +387,7 @@ public class JCloudsS3ServiceLiveTest
|
|||
String data = "This is my Ÿn’<6E>˜dŽ data";
|
||||
requestObject = new S3Object(objectKey, data);
|
||||
jsResultObject = service.putObject(new S3Bucket(bucketName), requestObject);
|
||||
jcObject = context.getApi().getBlob(bucketName, objectKey).get(10, TimeUnit.SECONDS);
|
||||
jcObject = context.getApi().getObject(bucketName, objectKey).get(10, TimeUnit.SECONDS);
|
||||
assertEquals(jcObject.getMetadata().getSize(), data.getBytes("UTF-8").length);
|
||||
assertTrue(jcObject.getMetadata().getContentType().startsWith("text/plain"));
|
||||
assertEquals(jsResultObject.getContentLength(), data.getBytes("UTF-8").length);
|
||||
|
@ -397,7 +397,7 @@ public class JCloudsS3ServiceLiveTest
|
|||
requestObject = new S3Object(objectKey);
|
||||
requestObject.addMetadata("x-amz-meta-" + "my-metadata-1", "value-1");
|
||||
jsResultObject = service.putObject(new S3Bucket(bucketName), requestObject);
|
||||
jcObject = context.getApi().getBlob(bucketName, objectKey).get(10, TimeUnit.SECONDS);
|
||||
jcObject = context.getApi().getObject(bucketName, objectKey).get(10, TimeUnit.SECONDS);
|
||||
assertEquals(Iterables.getLast(jcObject.getMetadata().getUserMetadata().get(
|
||||
"my-metadata-1")), "value-1");
|
||||
assertEquals(jsResultObject.getMetadata("x-amz-meta-" + "my-metadata-1"), "value-1");
|
||||
|
@ -406,7 +406,7 @@ public class JCloudsS3ServiceLiveTest
|
|||
requestObject = new S3Object(objectKey);
|
||||
requestObject.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ);
|
||||
jsResultObject = service.putObject(new S3Bucket(bucketName), requestObject);
|
||||
org.jclouds.aws.s3.domain.AccessControlList jcACL = context.getApi().getBlobACL(
|
||||
org.jclouds.aws.s3.domain.AccessControlList jcACL = context.getApi().getObjectACL(
|
||||
bucketName, objectKey).get(10, TimeUnit.SECONDS);
|
||||
assertTrue(jcACL.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ));
|
||||
assertTrue(jcACL.hasPermission(jcACL.getOwner().getId(), Permission.FULL_CONTROL));
|
||||
|
@ -422,7 +422,7 @@ public class JCloudsS3ServiceLiveTest
|
|||
data = "Here is some d‡tˆ for you";
|
||||
requestObject.setDataInputStream(new ByteArrayInputStream(data.getBytes("UTF-8")));
|
||||
jsResultObject = service.putObject(new S3Bucket(bucketName), requestObject);
|
||||
jcObject = context.getApi().getBlob(bucketName, objectKey).get(10, TimeUnit.SECONDS);
|
||||
jcObject = context.getApi().getObject(bucketName, objectKey).get(10, TimeUnit.SECONDS);
|
||||
assertTrue(jsResultObject.verifyData(data.getBytes("UTF-8")));
|
||||
assertEquals(jsResultObject.getMd5HashAsHex(), HttpUtils.toHexString(jcObject
|
||||
.getMetadata().getETag()));
|
||||
|
@ -458,7 +458,7 @@ public class JCloudsS3ServiceLiveTest
|
|||
destinationObject = new S3Object(destinationObjectKey);
|
||||
copyResult = service.copyObject(bucketName, sourceObjectKey, bucketName,
|
||||
destinationObject, false);
|
||||
jcDestinationObject = context.getApi().getBlob(bucketName, destinationObject.getKey())
|
||||
jcDestinationObject = context.getApi().getObject(bucketName, destinationObject.getKey())
|
||||
.get(10, TimeUnit.SECONDS);
|
||||
// TODO null keys from s3object! assertEquals(jcDestinationObject.getKey(),
|
||||
// destinationObjectKey);
|
||||
|
@ -467,7 +467,7 @@ public class JCloudsS3ServiceLiveTest
|
|||
assertEquals(copyResult.get("ETag"), HttpUtils.toHexString(jcDestinationObject
|
||||
.getMetadata().getETag()));
|
||||
// Test destination ACL is unchanged (ie private)
|
||||
org.jclouds.aws.s3.domain.AccessControlList jcACL = context.getApi().getBlobACL(
|
||||
org.jclouds.aws.s3.domain.AccessControlList jcACL = context.getApi().getObjectACL(
|
||||
bucketName, destinationObject.getKey()).get(10, TimeUnit.SECONDS);
|
||||
assertEquals(jcACL.getGrants().size(), 1);
|
||||
assertTrue(jcACL.hasPermission(jcACL.getOwner().getId(), Permission.FULL_CONTROL));
|
||||
|
@ -477,12 +477,12 @@ public class JCloudsS3ServiceLiveTest
|
|||
destinationObject.addMetadata("x-amz-meta-" + metadataName, destinationMetadataValue);
|
||||
copyResult = service.copyObject(bucketName, sourceObjectKey, bucketName,
|
||||
destinationObject, true);
|
||||
jcDestinationObject = context.getApi().getBlob(bucketName, destinationObject.getKey())
|
||||
jcDestinationObject = context.getApi().getObject(bucketName, destinationObject.getKey())
|
||||
.get(10, TimeUnit.SECONDS);
|
||||
assertEquals(Iterators.getLast(jcDestinationObject.getMetadata().getUserMetadata().get(
|
||||
metadataName).iterator()), destinationMetadataValue);
|
||||
// Test destination ACL is unchanged (ie private)
|
||||
jcACL = context.getApi().getBlobACL(bucketName, destinationObject.getKey()).get(10,
|
||||
jcACL = context.getApi().getObjectACL(bucketName, destinationObject.getKey()).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
assertEquals(jcACL.getGrants().size(), 1);
|
||||
assertTrue(jcACL.hasPermission(jcACL.getOwner().getId(), Permission.FULL_CONTROL));
|
||||
|
@ -493,7 +493,7 @@ public class JCloudsS3ServiceLiveTest
|
|||
copyResult = service.copyObject(bucketName, sourceObjectKey, bucketName,
|
||||
destinationObject, false);
|
||||
// Test destination ACL is changed (ie public-read)
|
||||
jcACL = context.getApi().getBlobACL(bucketName, destinationObject.getKey()).get(10,
|
||||
jcACL = context.getApi().getObjectACL(bucketName, destinationObject.getKey()).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
assertEquals(jcACL.getGrants().size(), 2);
|
||||
assertTrue(jcACL.hasPermission(jcACL.getOwner().getId(), Permission.FULL_CONTROL));
|
||||
|
@ -673,7 +673,7 @@ public class JCloudsS3ServiceLiveTest
|
|||
multiService.putObjects(bucket, objects);
|
||||
|
||||
assertEquals(countOfUploadCompletions[0], OBJECT_COUNT);
|
||||
ListBucketResponse theBucket = context.getApi().listBlobs(bucketName).get(10,
|
||||
ListBucketResponse theBucket = context.getApi().listBucket(bucketName).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
assertEquals(theBucket.size(), OBJECT_COUNT);
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ public abstract class BaseJCloudsPerformanceLiveTest extends BasePerformanceLive
|
|||
org.jclouds.aws.s3.domain.S3Object object = new org.jclouds.aws.s3.domain.S3Object(key);
|
||||
object.getMetadata().setContentType(contentType);
|
||||
object.setData(data);
|
||||
return context.getApi().putBlob(bucket, object).get(120, TimeUnit.SECONDS) != null;
|
||||
return context.getApi().putObject(bucket, object).get(120, TimeUnit.SECONDS) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,7 +66,7 @@ public abstract class BaseJCloudsPerformanceLiveTest extends BasePerformanceLive
|
|||
org.jclouds.aws.s3.domain.S3Object object = new org.jclouds.aws.s3.domain.S3Object(key);
|
||||
object.getMetadata().setContentType(contentType);
|
||||
object.setData(data);
|
||||
return context.getApi().putBlob(bucket, object).get(120, TimeUnit.SECONDS) != null;
|
||||
return context.getApi().putObject(bucket, object).get(120, TimeUnit.SECONDS) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -76,7 +76,7 @@ public abstract class BaseJCloudsPerformanceLiveTest extends BasePerformanceLive
|
|||
object.getMetadata().setContentType(contentType);
|
||||
object.setData(data);
|
||||
object.getMetadata().setSize(data.available());
|
||||
return context.getApi().putBlob(bucket, object).get(120, TimeUnit.SECONDS) != null;
|
||||
return context.getApi().putObject(bucket, object).get(120, TimeUnit.SECONDS) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -85,6 +85,6 @@ public abstract class BaseJCloudsPerformanceLiveTest extends BasePerformanceLive
|
|||
org.jclouds.aws.s3.domain.S3Object object = new org.jclouds.aws.s3.domain.S3Object(key);
|
||||
object.getMetadata().setContentType(contentType);
|
||||
object.setData(data);
|
||||
return context.getApi().putBlob(bucket, object).get(120, TimeUnit.SECONDS) != null;
|
||||
return context.getApi().putObject(bucket, object).get(120, TimeUnit.SECONDS) != null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ import org.testng.annotations.Test;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
public abstract class BasePerformanceLiveTest extends
|
||||
BaseBlobStoreIntegrationTest<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
BaseBlobStoreIntegrationTest<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||
protected int timeoutSeconds = 10;
|
||||
protected int loopCount = 100;
|
||||
protected ExecutorService exec;
|
||||
|
@ -94,7 +94,7 @@ public abstract class BasePerformanceLiveTest extends
|
|||
protected String createScratchContainerInEU() throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
String containerName = getScratchContainerName();
|
||||
context.getApi().createContainer(containerName, createIn(LocationConstraint.EU)).get(30,
|
||||
context.getApi().putBucketIfNotExists(containerName, createIn(LocationConstraint.EU)).get(30,
|
||||
TimeUnit.SECONDS);
|
||||
return containerName;
|
||||
}
|
||||
|
|
|
@ -66,14 +66,14 @@ public class MainApp {
|
|||
try {
|
||||
|
||||
// Create Bucket
|
||||
((S3Context) context).getApi().createContainer(bucketName).get(10, TimeUnit.SECONDS);
|
||||
((S3Context) context).getApi().putBucketIfNotExists(bucketName).get(10, TimeUnit.SECONDS);
|
||||
BlobMap blobMap = context.createBlobMap(bucketName);
|
||||
Blob blob = context.newBlob("test");
|
||||
blob.setData("testdata");
|
||||
blobMap.put("test", blob);
|
||||
|
||||
// List bucket
|
||||
for (BucketMetadata bucketObj : ((S3Context) context).getApi().listContainers()) {
|
||||
for (BucketMetadata bucketObj : ((S3Context) context).getApi().listOwnedBuckets()) {
|
||||
System.out.println(String.format(" %1$s", bucketObj));
|
||||
System.out.println(String.format(": %1$s entries%n", context.createInputStreamMap(
|
||||
bucketObj.getName()).size()));
|
||||
|
|
|
@ -86,7 +86,7 @@ public class GetAllBucketsController extends HttpServlet {
|
|||
private void addMyBucketsToRequest(HttpServletRequest request) throws InterruptedException,
|
||||
ExecutionException, TimeoutException {
|
||||
System.err.println(context.getAccount() + ":" + context.getEndPoint());
|
||||
SortedSet<BucketMetadata> myBucketMetadata = context.getApi().listContainers();
|
||||
SortedSet<BucketMetadata> myBucketMetadata = context.getApi().listOwnedBuckets();
|
||||
SortedSet<BucketResult> myBuckets = Sets.newTreeSet(Iterables.transform(myBucketMetadata,
|
||||
metadataToBucketResultProvider.get()));
|
||||
request.setAttribute("buckets", myBuckets);
|
||||
|
|
|
@ -108,14 +108,14 @@ public class JCloudsServlet extends HttpServlet {
|
|||
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
try {
|
||||
SortedSet<BucketMetadata> myBucketMetadata = context.getApi().listContainers();
|
||||
SortedSet<BucketMetadata> myBucketMetadata = context.getApi().listOwnedBuckets();
|
||||
SortedSet<BucketResult> myBuckets = Sets.newTreeSet();
|
||||
for (BucketMetadata metadata : myBucketMetadata) {
|
||||
BucketResult result = new BucketResult();
|
||||
result.setName(metadata.getName());
|
||||
try {
|
||||
try {
|
||||
ListBucketResponse bucket = context.getApi().listBlobs(metadata.getName()).get(
|
||||
ListBucketResponse bucket = context.getApi().listBucket(metadata.getName()).get(
|
||||
10, TimeUnit.SECONDS);
|
||||
result.setSize(bucket.size() + "");
|
||||
} catch (ContainerNotFoundException ex) {
|
||||
|
|
|
@ -0,0 +1,316 @@
|
|||
/**
|
||||
*
|
||||
* 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.azure.storage.blob;
|
||||
|
||||
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.azure.storage.AzureBlob;
|
||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ListBlobsResponse;
|
||||
import org.jclouds.azure.storage.blob.functions.ParseBlobFromHeadersAndHttpContent;
|
||||
import org.jclouds.azure.storage.blob.functions.ParseBlobMetadataFromHeaders;
|
||||
import org.jclouds.azure.storage.blob.functions.ParseContainerMetadataFromHeaders;
|
||||
import org.jclouds.azure.storage.blob.functions.ReturnTrueIfContainerAlreadyExists;
|
||||
import org.jclouds.azure.storage.blob.options.CreateContainerOptions;
|
||||
import org.jclouds.azure.storage.blob.options.ListBlobsOptions;
|
||||
import org.jclouds.azure.storage.blob.xml.AccountNameEnumerationResultsHandler;
|
||||
import org.jclouds.azure.storage.blob.xml.ContainerNameEnumerationResultsHandler;
|
||||
import org.jclouds.azure.storage.domain.BoundedSortedSet;
|
||||
import org.jclouds.azure.storage.filters.SharedKeyAuthentication;
|
||||
import org.jclouds.azure.storage.options.ListOptions;
|
||||
import org.jclouds.azure.storage.reference.AzureStorageHeaders;
|
||||
import org.jclouds.blobstore.binders.BlobBinder;
|
||||
import org.jclouds.blobstore.binders.UserMetadataBinder;
|
||||
import org.jclouds.blobstore.functions.BlobKey;
|
||||
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
|
||||
import org.jclouds.http.functions.ParseETagHeader;
|
||||
import org.jclouds.http.functions.ReturnTrueOn404;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
import org.jclouds.rest.Endpoint;
|
||||
import org.jclouds.rest.EntityParam;
|
||||
import org.jclouds.rest.ExceptionParser;
|
||||
import org.jclouds.rest.Headers;
|
||||
import org.jclouds.rest.ParamParser;
|
||||
import org.jclouds.rest.QueryParams;
|
||||
import org.jclouds.rest.RequestFilters;
|
||||
import org.jclouds.rest.ResponseParser;
|
||||
import org.jclouds.rest.SkipEncoding;
|
||||
import org.jclouds.rest.XMLResponseParser;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
* Provides access to Azure Blob via their REST API.
|
||||
* <p/>
|
||||
* All commands return a Future of the result from Azure Blob. Any exceptions incurred during
|
||||
* processing will be wrapped in an {@link ExecutionException} as documented in {@link Future#get()}.
|
||||
*
|
||||
* @see <a href="http://msdn.microsoft.com/en-us/library/dd135733.aspx" />
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@SkipEncoding('/')
|
||||
@RequestFilters(SharedKeyAuthentication.class)
|
||||
@Headers(keys = AzureStorageHeaders.VERSION, values = "2009-07-17")
|
||||
@Endpoint(AzureBlob.class)
|
||||
public interface AzureBlobConnection {
|
||||
|
||||
/**
|
||||
* The List Containers operation returns a list of the containers under the specified account.
|
||||
* <p />
|
||||
* The 2009-07-17 version of the List Containers operation times out after 30 seconds.
|
||||
*
|
||||
* @param listOptions
|
||||
* controls the number or type of results requested
|
||||
* @see ListOptions
|
||||
*/
|
||||
@GET
|
||||
@XMLResponseParser(AccountNameEnumerationResultsHandler.class)
|
||||
@Path("/")
|
||||
@QueryParams(keys = "comp", values = "list")
|
||||
BoundedSortedSet<ContainerMetadata> listContainers(ListOptions... listOptions);
|
||||
|
||||
/**
|
||||
* The Create Container operation creates a new container under the specified account. If the
|
||||
* container with the same name already exists, the operation fails.
|
||||
* <p/>
|
||||
* The container resource includes metadata and properties for that container. It does not
|
||||
* include a list of the blobs contained by the container.
|
||||
*
|
||||
* @see CreateContainerOptions
|
||||
*
|
||||
*/
|
||||
@PUT
|
||||
@Path("{container}")
|
||||
@ExceptionParser(ReturnTrueIfContainerAlreadyExists.class)
|
||||
@QueryParams(keys = "restype", values = "container")
|
||||
Future<Boolean> createContainer(@PathParam("container") String container,
|
||||
CreateContainerOptions... options);
|
||||
|
||||
/**
|
||||
* The Get Container Properties operation returns all user-defined metadata and system properties
|
||||
* for the specified container. The data returned does not include the container's list of blobs.
|
||||
*/
|
||||
@HEAD
|
||||
@Path("{container}")
|
||||
@QueryParams(keys = "restype", values = "container")
|
||||
@ResponseParser(ParseContainerMetadataFromHeaders.class)
|
||||
ContainerMetadata getContainerProperties(@PathParam("container") String container);
|
||||
|
||||
/**
|
||||
* The Set Container Metadata operation sets one or more user-defined name/value pairs for the
|
||||
* specified container. <h4>Remarks</h4>
|
||||
*
|
||||
*
|
||||
* Calling the Set Container Metadata operation overwrites all existing metadata that is
|
||||
* associated with the container. It's not possible to modify an individual name/value pair.
|
||||
* <p/>
|
||||
* You may also set metadata for a container at the time it is created.
|
||||
* <p/>
|
||||
* Calling Set Container Metadata updates the ETag for the container.
|
||||
*/
|
||||
@PUT
|
||||
@Path("{container}")
|
||||
@QueryParams(keys = { "restype", "comp" }, values = { "container", "metadata" })
|
||||
void setContainerMetadata(@PathParam("container") String container,
|
||||
@EntityParam(UserMetadataBinder.class) Multimap<String, String> metadata);
|
||||
|
||||
/**
|
||||
* The Delete Container operation marks the specified container for deletion. The container and
|
||||
* any blobs contained within it are later deleted during garbage collection.
|
||||
* <p/>
|
||||
* When a container is deleted, a container with the same name cannot be created for at least 30
|
||||
* seconds; the container may not be available for more than 30 seconds if the service is still
|
||||
* processing the request. While the container is being deleted, attempts to create a container
|
||||
* of the same name will fail with status code 409 (Conflict), with the service returning
|
||||
* additional error information indicating that the container is being deleted. All other
|
||||
* operations, including operations on any blobs under the container, will fail with status code
|
||||
* 404 (Not Found) while the container is being deleted.
|
||||
*
|
||||
*/
|
||||
@DELETE
|
||||
@Path("{container}")
|
||||
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
||||
@QueryParams(keys = "restype", values = "container")
|
||||
Future<Void> deleteContainer(@PathParam("container") String container);
|
||||
|
||||
/**
|
||||
* The root container is a default container that may be inferred from a URL requesting a blob
|
||||
* resource. The root container makes it possible to reference a blob from the top level of the
|
||||
* storage account hierarchy, without referencing the container name.
|
||||
* <p/>
|
||||
* The container resource includes metadata and properties for that container. It does not
|
||||
* include a list of the blobs contained by the container.
|
||||
*
|
||||
* @see CreateContainerOptions
|
||||
*
|
||||
*/
|
||||
@PUT
|
||||
@Path("$root")
|
||||
@ExceptionParser(ReturnTrueIfContainerAlreadyExists.class)
|
||||
@QueryParams(keys = "restype", values = "container")
|
||||
Future<Boolean> createRootContainer(CreateContainerOptions... options);
|
||||
|
||||
/**
|
||||
* The Delete Container operation marks the specified container for deletion. The container and
|
||||
* any blobs contained within it are later deleted during garbage collection. <h4>Remarks</h4>
|
||||
* When a container is deleted, a container with the same name cannot be created for at least 30
|
||||
* seconds; the container may not be available for more than 30 seconds if the service is still
|
||||
* processing the request. While the container is being deleted, attempts to create a container
|
||||
* of the same name will fail with status code 409 (Conflict), with the service returning
|
||||
* additional error information indicating that the container is being deleted. All other
|
||||
* operations, including operations on any blobs under the container, will fail with status code
|
||||
* 404 (Not Found) while the container is being deleted.
|
||||
*
|
||||
* @see deleteContainer(String)
|
||||
* @see createRootContainer(CreateContainerOptions)
|
||||
*/
|
||||
@DELETE
|
||||
@Path("$root")
|
||||
@ExceptionParser(ReturnTrueOn404.class)
|
||||
@QueryParams(keys = "restype", values = "container")
|
||||
Future<Boolean> deleteRootContainer();
|
||||
|
||||
/**
|
||||
* The List Blobs operation enumerates the list of blobs under the specified container.
|
||||
* <p/>
|
||||
* <h4>Authorization</h4>
|
||||
*
|
||||
* If the container's access control list (ACL) is set to allow anonymous access, any client may
|
||||
* call this operation.
|
||||
* <h4>Remarks</h4>
|
||||
*
|
||||
* If you specify a value for the maxresults parameter and the number of blobs to return exceeds
|
||||
* this value, or exceeds the default value for maxresults, the response body will contain a
|
||||
* NextMarker element that indicates the next blob to return on a subsequent request. To return
|
||||
* the next set of items, specify the value of NextMarker as the marker parameter on the URI for
|
||||
* the subsequent request.
|
||||
* <p/>
|
||||
* Note that the value of NextMarker should be treated as opaque.
|
||||
* <p/>
|
||||
* The delimiter parameter enables the caller to traverse the blob namespace by using a
|
||||
* user-configured delimiter. The delimiter may be a single character or a string. When the
|
||||
* request includes this parameter, the operation returns a BlobPrefix element. The BlobPrefix
|
||||
* element is returned in place of all blobs whose names begin with the same substring up to the
|
||||
* appearance of the delimiter character. The value of the BlobPrefix element is
|
||||
* substring+delimiter, where substring is the common substring that begins one or more blob
|
||||
* names, and delimiter is the value of the delimiter parameter.
|
||||
* <p/>
|
||||
* You can use the value of BlobPrefix to make a subsequent call to list the blobs that begin
|
||||
* with this prefix, by specifying the value of BlobPrefix for the prefix parameter on the
|
||||
* request URI. In this way, you can traverse a virtual hierarchy of blobs as though it were a
|
||||
* file system.
|
||||
* <p/>
|
||||
* Note that each BlobPrefix element returned counts toward the maximum result, just as each Blob
|
||||
* element does.
|
||||
* <p/>
|
||||
* Blobs are listed in alphabetical order in the response body.
|
||||
*/
|
||||
@GET
|
||||
@XMLResponseParser(ContainerNameEnumerationResultsHandler.class)
|
||||
@Path("{container}")
|
||||
@QueryParams(keys = { "restype", "comp" }, values = { "container", "list" })
|
||||
Future<ListBlobsResponse> listBlobs(@PathParam("container") String container,
|
||||
ListBlobsOptions... options);
|
||||
|
||||
@GET
|
||||
@XMLResponseParser(ContainerNameEnumerationResultsHandler.class)
|
||||
@Path("$root")
|
||||
@QueryParams(keys = { "restype", "comp" }, values = { "container", "list" })
|
||||
Future<ListBlobsResponse> listBlobs(ListBlobsOptions... options);
|
||||
|
||||
/**
|
||||
* The Put Blob operation creates a new blob or updates the content of an existing blob.
|
||||
* <p/>
|
||||
* Updating an existing blob overwrites any existing metadata on the blob. Partial updates are
|
||||
* not supported; the content of the existing blob is overwritten with the content of the new
|
||||
* blob.
|
||||
* <p/>
|
||||
* <h4>Remarks</h4>
|
||||
* The maximum upload size for a blob is 64 MB. If your blob is larger than 64 MB, you may upload
|
||||
* it as a set of blocks. For more information, see the Put Block and Put Block List operations.
|
||||
* <p/>
|
||||
* If you attempt to upload a blob that is larger than 64 MB, the service returns status code 413
|
||||
* (Request Entity Too Large). The Blob service also returns additional information about the
|
||||
* error in the response, including the maximum blob size permitted in bytes.
|
||||
* <p/>
|
||||
* A Put Blob operation is permitted 10 minutes per MB to complete. If the operation is taking
|
||||
* longer than 10 minutes per MB on average, the operation will timeout.
|
||||
*/
|
||||
@PUT
|
||||
@Path("{container}/{key}")
|
||||
@ResponseParser(ParseETagHeader.class)
|
||||
Future<byte[]> putBlob(@PathParam("container") String container,
|
||||
@PathParam("key") @ParamParser(BlobKey.class) @EntityParam(BlobBinder.class) Blob object);
|
||||
|
||||
/**
|
||||
* The Get Blob operation reads or downloads a blob from the system, including its metadata and
|
||||
* properties.
|
||||
*/
|
||||
@GET
|
||||
@ResponseParser(ParseBlobFromHeadersAndHttpContent.class)
|
||||
@ExceptionParser(ThrowKeyNotFoundOn404.class)
|
||||
@Path("{container}/{key}")
|
||||
Future<Blob> getBlob(@PathParam("container") String container, @PathParam("key") String key,
|
||||
GetOptions... options);
|
||||
|
||||
/**
|
||||
* The Get Blob Properties operation returns all user-defined metadata, standard HTTP properties,
|
||||
* and system properties for the blob. It does not return the content of the blob.
|
||||
*/
|
||||
@GET
|
||||
@Headers(keys = "Range", values = "bytes=0-0")
|
||||
// should use HEAD, this is a hack per http://code.google.com/p/jclouds/issues/detail?id=92
|
||||
@ResponseParser(ParseBlobMetadataFromHeaders.class)
|
||||
@ExceptionParser(ThrowKeyNotFoundOn404.class)
|
||||
@Path("{container}/{key}")
|
||||
BlobMetadata getBlobProperties(@PathParam("container") String container,
|
||||
@PathParam("key") String key);
|
||||
|
||||
@PUT
|
||||
@Path("{container}/{key}")
|
||||
@QueryParams(keys = { "comp" }, values = { "metadata" })
|
||||
void setBlobMetadata(@PathParam("container") String container, @PathParam("key") String key,
|
||||
@EntityParam(UserMetadataBinder.class) Multimap<String, String> metadata);
|
||||
|
||||
/**
|
||||
* The Delete Blob operation marks the specified blob for deletion. The blob is later deleted
|
||||
* during garbage collection.
|
||||
*/
|
||||
@DELETE
|
||||
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
||||
@Path("{container}/{key}")
|
||||
Future<Void> deleteBlob(@PathParam("container") String container, @PathParam("key") String key);
|
||||
|
||||
}
|
|
@ -39,6 +39,6 @@ import org.jclouds.cloud.CloudContext;
|
|||
*
|
||||
*/
|
||||
public interface AzureBlobContext extends
|
||||
BlobStoreContext<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> {
|
||||
BlobStoreContext<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> {
|
||||
|
||||
}
|
|
@ -60,7 +60,7 @@ import com.google.inject.TypeLiteral;
|
|||
* @see AzureBlobContext
|
||||
*/
|
||||
public class AzureBlobContextBuilder extends
|
||||
BlobStoreContextBuilder<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> {
|
||||
BlobStoreContextBuilder<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> {
|
||||
|
||||
@Override
|
||||
public AzureBlobContext buildContext() {
|
||||
|
@ -68,7 +68,7 @@ public class AzureBlobContextBuilder extends
|
|||
}
|
||||
|
||||
public AzureBlobContextBuilder(Properties props) {
|
||||
super(new TypeLiteral<AzureBlobStore>() {
|
||||
super(new TypeLiteral<AzureBlobConnection>() {
|
||||
}, new TypeLiteral<ContainerMetadata>() {
|
||||
}, new TypeLiteral<BlobMetadata>() {
|
||||
}, new TypeLiteral<Blob>() {
|
||||
|
@ -78,6 +78,12 @@ public class AzureBlobContextBuilder extends
|
|||
"https://{account}.blob.core.windows.net");
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected void addBlobStoreModule(List<Module> modules) {
|
||||
// modules.add(BlobStoreMapsModule.Builder.newBuilder(containerMetadataType, blobMetadataType,
|
||||
// blobType).withClearContainerStrategy(RecreateClearContainerStrategy.class).build());
|
||||
// }
|
||||
|
||||
public AzureBlobContextBuilder(String id, String secret) {
|
||||
this(new Properties());
|
||||
properties.setProperty(AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT, checkNotNull(id,
|
||||
|
@ -152,7 +158,7 @@ public class AzureBlobContextBuilder extends
|
|||
|
||||
@Override
|
||||
public AzureBlobContextBuilder withSaxDebug() {
|
||||
return (AzureBlobContextBuilder) (AzureBlobContextBuilder) super.withSaxDebug();
|
||||
return (AzureBlobContextBuilder) super.withSaxDebug();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -39,24 +39,22 @@ import org.jclouds.azure.storage.blob.domain.Blob;
|
|||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ListBlobsResponse;
|
||||
import org.jclouds.azure.storage.blob.functions.MD5EnforcingBlobBinder;
|
||||
import org.jclouds.azure.storage.blob.functions.ParseBlobFromHeadersAndHttpContent;
|
||||
import org.jclouds.azure.storage.blob.functions.ParseBlobMetadataFromHeaders;
|
||||
import org.jclouds.azure.storage.blob.functions.ReturnTrueIfContainerAlreadyExists;
|
||||
import org.jclouds.azure.storage.blob.options.CreateContainerOptions;
|
||||
import org.jclouds.azure.storage.blob.xml.AccountNameEnumerationResultsHandler;
|
||||
import org.jclouds.azure.storage.blob.xml.ContainerNameEnumerationResultsHandler;
|
||||
import org.jclouds.azure.storage.domain.BoundedSortedSet;
|
||||
import org.jclouds.azure.storage.blob.xml.AddMD5ToListBlobsResponse;
|
||||
import org.jclouds.azure.storage.filters.SharedKeyAuthentication;
|
||||
import org.jclouds.azure.storage.options.CreateOptions;
|
||||
import org.jclouds.azure.storage.options.ListOptions;
|
||||
import org.jclouds.azure.storage.reference.AzureStorageHeaders;
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.binders.BlobBinder;
|
||||
import org.jclouds.blobstore.functions.BlobKey;
|
||||
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
|
||||
import org.jclouds.http.functions.ParseETagHeader;
|
||||
import org.jclouds.http.functions.ReturnFalseOn404;
|
||||
import org.jclouds.http.functions.ReturnTrueOn404;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
import org.jclouds.rest.Endpoint;
|
||||
import org.jclouds.rest.EntityParam;
|
||||
|
@ -99,12 +97,6 @@ public interface AzureBlobStore extends BlobStore<ContainerMetadata, BlobMetadat
|
|||
@QueryParams(keys = "comp", values = "list")
|
||||
SortedSet<ContainerMetadata> listContainers();
|
||||
|
||||
@GET
|
||||
@XMLResponseParser(AccountNameEnumerationResultsHandler.class)
|
||||
@Path("/")
|
||||
@QueryParams(keys = "comp", values = "list")
|
||||
BoundedSortedSet<ContainerMetadata> listContainers(ListOptions listOptions);
|
||||
|
||||
@HEAD
|
||||
@Path("{container}")
|
||||
@ExceptionParser(ReturnFalseOn404.class)
|
||||
|
@ -127,13 +119,6 @@ public interface AzureBlobStore extends BlobStore<ContainerMetadata, BlobMetadat
|
|||
@QueryParams(keys = "restype", values = "container")
|
||||
Future<Boolean> createContainer(@PathParam("container") String container);
|
||||
|
||||
@PUT
|
||||
@Path("{container}")
|
||||
@QueryParams(keys = "restype", values = "container")
|
||||
@ExceptionParser(ReturnTrueIfContainerAlreadyExists.class)
|
||||
Future<Boolean> createContainer(@PathParam("container") String container,
|
||||
CreateContainerOptions options);
|
||||
|
||||
/**
|
||||
* The Delete Container operation marks the specified container for deletion. The container and
|
||||
* any blobs contained within it are later deleted during garbage collection.
|
||||
|
@ -149,68 +134,22 @@ public interface AzureBlobStore extends BlobStore<ContainerMetadata, BlobMetadat
|
|||
*/
|
||||
@DELETE
|
||||
@Path("{container}")
|
||||
@ExceptionParser(ReturnTrueOn404.class)
|
||||
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
||||
@QueryParams(keys = "restype", values = "container")
|
||||
Future<Boolean> deleteContainer(@PathParam("container") String container);
|
||||
|
||||
/**
|
||||
* The root container is a default container that may be inferred from a URL requesting a blob
|
||||
* resource. The root container makes it possible to reference a blob from the top level of the
|
||||
* storage account hierarchy, without referencing the container name.
|
||||
* <p/>
|
||||
* The container resource includes metadata and properties for that container. It does not
|
||||
* include a list of the blobs contained by the container.
|
||||
*
|
||||
* @see CreateContainerOptions
|
||||
*
|
||||
*/
|
||||
@PUT
|
||||
@Path("$root")
|
||||
@ExceptionParser(ReturnTrueIfContainerAlreadyExists.class)
|
||||
@QueryParams(keys = "restype", values = "container")
|
||||
Future<Boolean> createRootContainer();
|
||||
|
||||
@PUT
|
||||
@Path("$root")
|
||||
@ExceptionParser(ReturnTrueIfContainerAlreadyExists.class)
|
||||
@QueryParams(keys = "restype", values = "container")
|
||||
Future<Boolean> createRootContainer(CreateOptions options);
|
||||
|
||||
/**
|
||||
*
|
||||
* @see deleteContainer(String)
|
||||
* @see createRootContainer(CreateContainerOptions)
|
||||
*/
|
||||
@DELETE
|
||||
@Path("$root")
|
||||
@ExceptionParser(ReturnTrueOn404.class)
|
||||
@QueryParams(keys = "restype", values = "container")
|
||||
Future<Boolean> deleteRootContainer();
|
||||
Future<Void> deleteContainer(@PathParam("container") String container);
|
||||
|
||||
@GET
|
||||
@XMLResponseParser(ContainerNameEnumerationResultsHandler.class)
|
||||
@XMLResponseParser(AddMD5ToListBlobsResponse.class)
|
||||
@Path("{container}")
|
||||
@QueryParams(keys = { "restype", "comp" }, values = { "container", "list" })
|
||||
Future<ListBlobsResponse> listBlobs(@PathParam("container") String container);
|
||||
|
||||
@GET
|
||||
@XMLResponseParser(ContainerNameEnumerationResultsHandler.class)
|
||||
@Path("$root")
|
||||
@QueryParams(keys = { "restype", "comp" }, values = { "container", "list" })
|
||||
Future<ListBlobsResponse> listBlobs();
|
||||
|
||||
// @GET
|
||||
// @XMLResponseParser(ContainerNameEnumerationResultsHandler.class)
|
||||
// @Path("{container}")
|
||||
// @QueryParams(keys = { "restype", "comp" }, values = { "container", "list" })
|
||||
// Future<ListBlobsResponse> listBlobs(@PathParam("container") String container,
|
||||
// ListBlobsOptions options);
|
||||
|
||||
@PUT
|
||||
@Path("{container}/{key}")
|
||||
@ResponseParser(ParseETagHeader.class)
|
||||
Future<byte[]> putBlob(@PathParam("container") String container,
|
||||
@PathParam("key") @ParamParser(BlobKey.class) @EntityParam(BlobBinder.class) Blob object);
|
||||
Future<byte[]> putBlob(
|
||||
@PathParam("container") String container,
|
||||
@PathParam("key") @ParamParser(BlobKey.class) @EntityParam(MD5EnforcingBlobBinder.class) Blob object);
|
||||
|
||||
@GET
|
||||
@ResponseParser(ParseBlobFromHeadersAndHttpContent.class)
|
||||
|
@ -234,8 +173,8 @@ public interface AzureBlobStore extends BlobStore<ContainerMetadata, BlobMetadat
|
|||
BlobMetadata blobMetadata(@PathParam("container") String container, @PathParam("key") String key);
|
||||
|
||||
@DELETE
|
||||
@ExceptionParser(ReturnTrueOn404.class)
|
||||
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
||||
@Path("{container}/{key}")
|
||||
Future<Boolean> removeBlob(@PathParam("container") String container, @PathParam("key") String key);
|
||||
Future<Void> removeBlob(@PathParam("container") String container, @PathParam("key") String key);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
*
|
||||
* 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.azure.storage.blob;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
|
||||
import org.jclouds.azure.storage.filters.SharedKeyAuthentication;
|
||||
import org.jclouds.azure.storage.reference.AzureStorageHeaders;
|
||||
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
|
||||
import org.jclouds.http.functions.ParseContentMD5FromHeaders;
|
||||
import org.jclouds.rest.Endpoint;
|
||||
import org.jclouds.rest.ExceptionParser;
|
||||
import org.jclouds.rest.Headers;
|
||||
import org.jclouds.rest.RequestFilters;
|
||||
import org.jclouds.rest.ResponseParser;
|
||||
import org.jclouds.rest.SkipEncoding;
|
||||
|
||||
/**
|
||||
* Helper functions needed to to derive BlobStore values
|
||||
* <p/>
|
||||
*
|
||||
* @see <a href="http://msdn.microsoft.com/en-us/library/dd135733.aspx" />
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@SkipEncoding('/')
|
||||
@RequestFilters(SharedKeyAuthentication.class)
|
||||
@Headers(keys = AzureStorageHeaders.VERSION, values = "2009-07-17")
|
||||
public interface AzureBlobUtil {
|
||||
|
||||
@GET
|
||||
@Headers(keys = "Range", values = "bytes=0-0")
|
||||
// should use HEAD, this is a hack per http://code.google.com/p/jclouds/issues/detail?id=92
|
||||
@ResponseParser(ParseContentMD5FromHeaders.class)
|
||||
@ExceptionParser(ThrowKeyNotFoundOn404.class)
|
||||
@Path("{key}")
|
||||
byte[] getMD5(@Endpoint URI container, @PathParam("key") String key);
|
||||
|
||||
}
|
|
@ -44,7 +44,8 @@ public class BlobBinder extends org.jclouds.blobstore.binders.BlobBinder {
|
|||
public void addEntityToRequest(Object entity, HttpRequest request) {
|
||||
Blob<?> object = (Blob<?>) entity;
|
||||
checkArgument(object.getMetadata().getSize() >= 0, "size must be set");
|
||||
|
||||
checkArgument(object.getContentLength() <= 64 * 1024 * 1024,
|
||||
"maximum size for put Blob is 64MB");
|
||||
if (object.getMetadata() instanceof BlobMetadata) {
|
||||
BlobMetadata md = (BlobMetadata) object.getMetadata();
|
||||
|
||||
|
|
|
@ -30,12 +30,14 @@ import javax.inject.Named;
|
|||
import javax.inject.Provider;
|
||||
|
||||
import org.jclouds.azure.storage.AzureBlob;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobContext;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||
import org.jclouds.azure.storage.reference.AzureStorageConstants;
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.BlobStoreContextImpl;
|
||||
import org.jclouds.blobstore.BlobMap.Factory;
|
||||
import org.jclouds.lifecycle.Closer;
|
||||
|
@ -55,16 +57,17 @@ public class AzureBlobContextModule extends AbstractModule {
|
|||
}
|
||||
|
||||
public static class AzureBlobContextImpl extends
|
||||
BlobStoreContextImpl<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> implements
|
||||
AzureBlobContext {
|
||||
BlobStoreContextImpl<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob>
|
||||
implements AzureBlobContext {
|
||||
@Inject
|
||||
AzureBlobContextImpl(Factory<BlobMetadata, Blob> blobMapFactory,
|
||||
org.jclouds.blobstore.InputStreamMap.Factory<BlobMetadata> inputStreamMapFactory,
|
||||
Closer closer, Provider<Blob> blobProvider, AzureBlobStore defaultApi,
|
||||
@AzureBlob URI endPoint,
|
||||
Closer closer, Provider<Blob> blobProvider,
|
||||
BlobStore<ContainerMetadata, BlobMetadata, Blob> blobStore,
|
||||
AzureBlobConnection defaultApi, @AzureBlob URI endPoint,
|
||||
@Named(AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT) String account) {
|
||||
super(blobMapFactory, inputStreamMapFactory, closer, blobProvider, defaultApi, endPoint,
|
||||
account);
|
||||
super(blobMapFactory, inputStreamMapFactory, closer, blobProvider, blobStore, defaultApi,
|
||||
endPoint, account);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,11 +29,20 @@ import javax.inject.Named;
|
|||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.azure.storage.AzureBlob;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobUtil;
|
||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||
import org.jclouds.azure.storage.blob.handlers.AzureBlobClientErrorRetryHandler;
|
||||
import org.jclouds.azure.storage.blob.reference.AzureBlobConstants;
|
||||
import org.jclouds.azure.storage.config.RestAzureStorageConnectionModule;
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.cloud.ConfiguresCloudConnection;
|
||||
import org.jclouds.http.HttpRetryHandler;
|
||||
import org.jclouds.http.RequiresHttp;
|
||||
import org.jclouds.http.annotation.ClientError;
|
||||
import org.jclouds.rest.RestClientFactory;
|
||||
|
||||
import com.google.inject.Provides;
|
||||
|
@ -62,8 +71,26 @@ public class RestAzureBlobStoreModule extends RestAzureStorageConnectionModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected AzureBlobStore provideAzureBlobStore(RestClientFactory factory) {
|
||||
protected AzureBlobUtil provideAzureBlobUtil(RestClientFactory factory) {
|
||||
return factory.create(AzureBlobUtil.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected AzureBlobConnection provideAzureBlobConnection(RestClientFactory factory) {
|
||||
return factory.create(AzureBlobConnection.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected BlobStore<ContainerMetadata, BlobMetadata, Blob> provideAzureBlobStore(
|
||||
RestClientFactory factory) {
|
||||
return factory.create(AzureBlobStore.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bindRetryHandlers() {
|
||||
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(
|
||||
AzureBlobClientErrorRetryHandler.class);
|
||||
}
|
||||
}
|
|
@ -28,6 +28,9 @@ import java.util.Arrays;
|
|||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
|
@ -37,21 +40,22 @@ public class ContainerMetadata extends org.jclouds.blobstore.domain.ContainerMet
|
|||
private URI url;
|
||||
private DateTime lastModified;
|
||||
private byte[] eTag;
|
||||
private Multimap<String, String> userMetadata = HashMultimap.create();
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + Arrays.hashCode(eTag);
|
||||
result = prime * result + ((lastModified == null) ? 0 : lastModified.hashCode());
|
||||
result = prime * result + ((url == null) ? 0 : url.hashCode());
|
||||
result = prime * result + ((getLastModified() == null) ? 0 : getLastModified().hashCode());
|
||||
result = prime * result + ((getUrl() == null) ? 0 : getUrl().hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ContainerMetadata [eTag=" + Arrays.toString(eTag) + ", lastModified=" + lastModified
|
||||
+ ", url=" + url + ", name=" + name + "]";
|
||||
return "ContainerMetadata [eTag=" + Arrays.toString(eTag) + ", lastModified="
|
||||
+ getLastModified() + ", url=" + getUrl() + ", name=" + name + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -65,22 +69,22 @@ public class ContainerMetadata extends org.jclouds.blobstore.domain.ContainerMet
|
|||
ContainerMetadata other = (ContainerMetadata) obj;
|
||||
if (!Arrays.equals(eTag, other.eTag))
|
||||
return false;
|
||||
if (lastModified == null) {
|
||||
if (other.lastModified != null)
|
||||
if (getLastModified() == null) {
|
||||
if (other.getLastModified() != null)
|
||||
return false;
|
||||
} else if (!lastModified.equals(other.lastModified))
|
||||
} else if (!getLastModified().equals(other.getLastModified()))
|
||||
return false;
|
||||
if (url == null) {
|
||||
if (other.url != null)
|
||||
if (getUrl() == null) {
|
||||
if (other.getUrl() != null)
|
||||
return false;
|
||||
} else if (!url.equals(other.url))
|
||||
} else if (!getUrl().equals(other.getUrl()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public ContainerMetadata(URI url, DateTime lastModified, byte[] eTag) {
|
||||
super(url.getPath().substring(1));
|
||||
this.url = url;
|
||||
this.setUrl(url);
|
||||
this.lastModified = lastModified;
|
||||
this.eTag = eTag;
|
||||
}
|
||||
|
@ -105,4 +109,24 @@ public class ContainerMetadata extends org.jclouds.blobstore.domain.ContainerMet
|
|||
return eTag;
|
||||
}
|
||||
|
||||
public void setUserMetadata(Multimap<String, String> userMetadata) {
|
||||
this.userMetadata = userMetadata;
|
||||
}
|
||||
|
||||
public Multimap<String, String> getUserMetadata() {
|
||||
return userMetadata;
|
||||
}
|
||||
|
||||
public void setLastModified(DateTime lastModified) {
|
||||
this.lastModified = lastModified;
|
||||
}
|
||||
|
||||
public void setETag(byte[] eTag) {
|
||||
this.eTag = eTag;
|
||||
}
|
||||
|
||||
public void setUrl(URI url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
*
|
||||
* 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.azure.storage.blob.functions;
|
||||
|
||||
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.azure.storage.blob.binders.BlobBinder;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
|
||||
public class MD5EnforcingBlobBinder extends BlobBinder {
|
||||
|
||||
@Inject
|
||||
public MD5EnforcingBlobBinder(@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) {
|
||||
super(metadataPrefix);
|
||||
}
|
||||
|
||||
public void addEntityToRequest(Object entity, HttpRequest request) {
|
||||
Blob<?> object = (Blob<?>) entity;
|
||||
if (object.getMetadata().getContentMD5() == null) {
|
||||
try {
|
||||
object.generateMD5();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Could not generate MD5 for " + object.getKey(), e);
|
||||
}
|
||||
}
|
||||
super.addEntityToRequest(entity, request);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
/**
|
||||
*
|
||||
* 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.azure.storage.blob.functions;
|
||||
|
||||
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||
import org.jclouds.http.HttpException;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.rest.RestContext;
|
||||
import org.jclouds.util.DateService;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* This parses @{link {@link org.jclouds.azure.storage.blob.domain.ContainerMetadata} from HTTP
|
||||
* headers.
|
||||
*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ParseContainerMetadataFromHeaders implements
|
||||
Function<HttpResponse, ContainerMetadata>, RestContext {
|
||||
|
||||
private final DateService dateParser;
|
||||
private final String metadataPrefix;
|
||||
private HttpRequest request;
|
||||
private Object[] args;
|
||||
|
||||
@Inject
|
||||
public ParseContainerMetadataFromHeaders(DateService dateParser,
|
||||
@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) {
|
||||
this.dateParser = dateParser;
|
||||
this.metadataPrefix = metadataPrefix;
|
||||
}
|
||||
|
||||
public ContainerMetadata apply(HttpResponse from) {
|
||||
ContainerMetadata to = new ContainerMetadata(getArgs()[0].toString());
|
||||
addUserMetadataTo(from, to);
|
||||
parseLastModifiedOrThrowException(from, to);
|
||||
addETagTo(from, to);
|
||||
to.setUrl(getRequest().getEndpoint());
|
||||
return to;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void addUserMetadataTo(HttpResponse from, ContainerMetadata metadata) {
|
||||
for (Entry<String, String> header : from.getHeaders().entries()) {
|
||||
if (header.getKey() != null && header.getKey().startsWith(metadataPrefix))
|
||||
metadata.getUserMetadata().put(
|
||||
(header.getKey().substring(metadataPrefix.length())).toLowerCase(),
|
||||
header.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void parseLastModifiedOrThrowException(HttpResponse from, ContainerMetadata metadata)
|
||||
throws HttpException {
|
||||
String lastModified = from.getFirstHeaderOrNull(HttpHeaders.LAST_MODIFIED);
|
||||
if (lastModified == null)
|
||||
throw new HttpException(HttpHeaders.LAST_MODIFIED + " header not present in response: "
|
||||
+ from);
|
||||
metadata.setLastModified(dateParser.rfc822DateParse(lastModified));
|
||||
if (metadata.getLastModified() == null)
|
||||
throw new HttpException("could not parse: " + HttpHeaders.LAST_MODIFIED + ": "
|
||||
+ lastModified);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void addETagTo(HttpResponse from, ContainerMetadata metadata) {
|
||||
String eTag = from.getFirstHeaderOrNull(HttpHeaders.ETAG);
|
||||
if (metadata.getETag() == null && eTag != null) {
|
||||
metadata.setETag(HttpUtils.fromHexString(eTag.replaceAll("\"", "")));
|
||||
}
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public HttpRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public void setContext(HttpRequest request, Object[] args) {
|
||||
this.request = request;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/**
|
||||
*
|
||||
* 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.azure.storage.blob.handlers;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.azure.storage.domain.AzureStorageError;
|
||||
import org.jclouds.azure.storage.util.AzureStorageUtils;
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpConstants;
|
||||
import org.jclouds.http.HttpException;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpRetryHandler;
|
||||
import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
/**
|
||||
* Handles Retryable responses with error codes in the 4xx range
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AzureBlobClientErrorRetryHandler implements HttpRetryHandler {
|
||||
|
||||
@Inject(optional = true)
|
||||
@Named(HttpConstants.PROPERTY_HTTP_MAX_RETRIES)
|
||||
private int retryCountLimit = 5;
|
||||
|
||||
private final AzureStorageUtils utils;
|
||||
private final BackoffLimitedRetryHandler backoffHandler;
|
||||
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
@Inject
|
||||
public AzureBlobClientErrorRetryHandler(BackoffLimitedRetryHandler backoffHandler,
|
||||
AzureStorageUtils utils) {
|
||||
this.backoffHandler = backoffHandler;
|
||||
this.utils = utils;
|
||||
}
|
||||
|
||||
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
|
||||
byte[] content = Utils.closeConnectionButKeepContentStream(response);
|
||||
command.incrementFailureCount();
|
||||
if (!command.isReplayable()) {
|
||||
logger.warn("Cannot retry after server error, command is not replayable: %1$s", command);
|
||||
return false;
|
||||
} else if (command.getFailureCount() > retryCountLimit) {
|
||||
logger.warn(
|
||||
"Cannot retry after server error, command has exceeded retry limit %1$d: %2$s",
|
||||
retryCountLimit, command);
|
||||
return false;
|
||||
} else if (response.getStatusCode() == 409) {
|
||||
try {
|
||||
AzureStorageError error = utils.parseAzureStorageErrorFromContent(command, response,
|
||||
new String(content));
|
||||
if ("ContainerBeingDeleted".equals(error.getCode())) {
|
||||
backoffHandler.imposeBackoffExponentialDelay(100L, 3, command.getFailureCount(),
|
||||
command.toString());
|
||||
return true;
|
||||
}
|
||||
} catch (HttpException e) {
|
||||
logger.warn(e, "error parsing response: %s", new String(content));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
*
|
||||
* 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.azure.storage.blob.xml;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.azure.storage.blob.AzureBlobUtil;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ListBlobsResponse;
|
||||
import org.jclouds.util.DateService;
|
||||
|
||||
/**
|
||||
* adds the Content-MD5 value to the blob metadata.
|
||||
*
|
||||
* @see <a href="http://msdn.microsoft.com/en-us/library/dd135734.aspx#samplerequestandresponse" />
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AddMD5ToListBlobsResponse extends ContainerNameEnumerationResultsHandler {
|
||||
|
||||
private final AzureBlobUtil util;
|
||||
|
||||
@Inject
|
||||
public AddMD5ToListBlobsResponse(AzureBlobUtil util, DateService dateParser) {
|
||||
super(dateParser);
|
||||
this.util = util;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListBlobsResponse getResult() {
|
||||
ListBlobsResponse response = super.getResult();
|
||||
checkNotNull(response.getContainerUrl(), "containerUrl");
|
||||
for (BlobMetadata md : response) {
|
||||
checkNotNull(md.getKey(), "key");
|
||||
md.setContentMD5(util.getMD5(response.getContainerUrl(), md.getKey()));
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
|
@ -61,10 +61,10 @@ import com.google.common.collect.Iterables;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "live", sequential = true, testName = "cloudservers.AzureBlobStoreLiveTest")
|
||||
public class AzureBlobStoreLiveTest {
|
||||
@Test(groups = "live", sequential = true, testName = "azureblob.AzureBlobConnectionLiveTest")
|
||||
public class AzureBlobConnectionLiveTest {
|
||||
|
||||
protected AzureBlobStore connection;
|
||||
protected AzureBlobConnection connection;
|
||||
|
||||
private String containerPrefix = System.getProperty("user.name") + "-azureblob";
|
||||
|
||||
|
@ -215,14 +215,14 @@ public class AzureBlobStoreLiveTest {
|
|||
|
||||
@Test
|
||||
public void testDeleteOneContainer() throws Exception {
|
||||
assertTrue(connection.deleteContainer("does-not-exist").get(10, TimeUnit.SECONDS));
|
||||
connection.deleteContainer("does-not-exist").get(10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = { "testListOwnedContainers",
|
||||
"testObjectOperations" })
|
||||
public void testDeleteContainer() throws Exception {
|
||||
assert connection.deleteContainer(privateContainer).get(10, TimeUnit.SECONDS);
|
||||
assert connection.deleteContainer(publicContainer).get(10, TimeUnit.SECONDS);
|
||||
connection.deleteContainer(privateContainer).get(10, TimeUnit.SECONDS);
|
||||
connection.deleteContainer(publicContainer).get(10, TimeUnit.SECONDS);
|
||||
// TODO loop for up to 30 seconds checking if they are really gone
|
||||
}
|
||||
|
||||
|
@ -245,14 +245,14 @@ public class AzureBlobStoreLiveTest {
|
|||
|
||||
// Test HEAD of missing object
|
||||
try {
|
||||
connection.blobMetadata(privateContainer, "non-existent-object");
|
||||
connection.getBlobProperties(privateContainer, "non-existent-object");
|
||||
assert false;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Test HEAD of object
|
||||
BlobMetadata metadata = connection.blobMetadata(privateContainer, object.getKey());
|
||||
BlobMetadata metadata = connection.getBlobProperties(privateContainer, object.getKey());
|
||||
// TODO assertEquals(metadata.getKey(), object.getKey());
|
||||
// we can't check this while hacking around lack of content-md5, as GET of the first byte will
|
||||
// show incorrect length 1, the returned size, as opposed to the real length. This is an ok
|
||||
|
@ -344,9 +344,8 @@ public class AzureBlobStoreLiveTest {
|
|||
// TimeUnit.SECONDS);
|
||||
// assertEquals(IOUtils.toString((InputStream) getBlob.getData()), data.substring(8));
|
||||
|
||||
assertTrue(connection.removeBlob(privateContainer, "object").get(10, TimeUnit.SECONDS));
|
||||
assertTrue(connection.removeBlob(privateContainer, "chunked-object")
|
||||
.get(10, TimeUnit.SECONDS));
|
||||
connection.deleteBlob(privateContainer, "object").get(10, TimeUnit.SECONDS);
|
||||
connection.deleteBlob(privateContainer, "chunked-object").get(10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,357 @@
|
|||
/**
|
||||
*
|
||||
* 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.azure.storage.blob;
|
||||
|
||||
import static org.jclouds.azure.storage.blob.options.CreateContainerOptions.Builder.withPublicAcl;
|
||||
import static org.jclouds.azure.storage.options.ListOptions.Builder.maxResults;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.ws.rs.HttpMethod;
|
||||
|
||||
import org.jclouds.azure.storage.AzureBlob;
|
||||
import org.jclouds.azure.storage.blob.functions.ParseContainerMetadataFromHeaders;
|
||||
import org.jclouds.azure.storage.blob.functions.ReturnTrueIfContainerAlreadyExists;
|
||||
import org.jclouds.azure.storage.blob.options.CreateContainerOptions;
|
||||
import org.jclouds.azure.storage.blob.options.ListBlobsOptions;
|
||||
import org.jclouds.azure.storage.options.ListOptions;
|
||||
import org.jclouds.azure.storage.reference.AzureStorageConstants;
|
||||
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.blobstore.reference.BlobStoreConstants;
|
||||
import org.jclouds.concurrent.WithinThreadExecutorService;
|
||||
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
import org.jclouds.http.functions.ReturnTrueIf2xx;
|
||||
import org.jclouds.http.functions.ReturnTrueOn404;
|
||||
import org.jclouds.http.functions.ReturnVoidIf2xx;
|
||||
import org.jclouds.rest.JaxrsAnnotationProcessor;
|
||||
import org.jclouds.rest.config.JaxrsModule;
|
||||
import org.jclouds.util.Jsr330;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code AzureBlobConnection}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "azureblob.AzureBlobConnectionTest")
|
||||
public class AzureBlobConnectionTest {
|
||||
|
||||
public void testListContainers() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobConnection.class.getMethod("listContainers", Array.newInstance(
|
||||
ListOptions.class, 0).getClass());
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] {});
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "comp=list");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
|
||||
assertEquals(httpMethod.getHeaders().size(), 1);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ParseSax.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
}
|
||||
|
||||
public void testListContainersOptions() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobConnection.class.getMethod("listContainers", Array.newInstance(
|
||||
ListOptions.class, 0).getClass());
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] { maxResults(1).marker(
|
||||
"marker").prefix("prefix") });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/");
|
||||
assert httpMethod.getEndpoint().getQuery().contains("comp=list");
|
||||
assert httpMethod.getEndpoint().getQuery().contains("marker=marker");
|
||||
assert httpMethod.getEndpoint().getQuery().contains("maxresults=1");
|
||||
assert httpMethod.getEndpoint().getQuery().contains("prefix=prefix");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
|
||||
assertEquals(httpMethod.getHeaders().size(), 1);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ParseSax.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
}
|
||||
|
||||
public void testCreateContainer() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobConnection.class.getMethod("createContainer", String.class, Array
|
||||
.newInstance(CreateContainerOptions.class, 0).getClass());
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "container" });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/container");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
|
||||
assertEquals(httpMethod.getHeaders().size(), 2);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(httpMethod.getHeaders().get("Content-Length"), Collections.singletonList("0"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
|
||||
ReturnTrueIfContainerAlreadyExists.class);
|
||||
}
|
||||
|
||||
public void testDeleteContainer() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobConnection.class.getMethod("deleteContainer", String.class);
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "container" });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/container");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.DELETE);
|
||||
assertEquals(httpMethod.getHeaders().size(), 1);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ReturnVoidIf2xx.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
|
||||
ReturnVoidOnNotFoundOr404.class);
|
||||
}
|
||||
|
||||
public void testCreateContainerOptions() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobConnection.class.getMethod("createContainer", String.class, Array
|
||||
.newInstance(CreateContainerOptions.class, 0).getClass());
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "container",
|
||||
withPublicAcl().withMetadata(ImmutableMultimap.of("foo", "bar")) });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/container");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
|
||||
assertEquals(httpMethod.getHeaders().size(), 4);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-meta-foo"), Collections.singletonList("bar"));
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-prop-publicaccess"), Collections
|
||||
.singletonList("true"));
|
||||
assertEquals(httpMethod.getHeaders().get("Content-Length"), Collections.singletonList("0"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
|
||||
ReturnTrueIfContainerAlreadyExists.class);
|
||||
}
|
||||
|
||||
public void testCreateRootContainer() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobConnection.class.getMethod("createRootContainer", Array.newInstance(
|
||||
CreateContainerOptions.class, 0).getClass());
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] {});
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/$root");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
|
||||
assertEquals(httpMethod.getHeaders().size(), 2);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(httpMethod.getHeaders().get("Content-Length"), Collections.singletonList("0"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
|
||||
ReturnTrueIfContainerAlreadyExists.class);
|
||||
}
|
||||
|
||||
public void testDeleteRootContainer() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobConnection.class.getMethod("deleteRootContainer");
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] {});
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/$root");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.DELETE);
|
||||
assertEquals(httpMethod.getHeaders().size(), 1);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
|
||||
ReturnTrueOn404.class);
|
||||
}
|
||||
|
||||
public void testCreateRootContainerOptions() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobConnection.class.getMethod("createRootContainer", Array.newInstance(
|
||||
CreateContainerOptions.class, 0).getClass());
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] { withPublicAcl()
|
||||
.withMetadata(ImmutableMultimap.of("foo", "bar")) });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/$root");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
|
||||
assertEquals(httpMethod.getHeaders().size(), 4);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-meta-foo"), Collections.singletonList("bar"));
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-prop-publicaccess"), Collections
|
||||
.singletonList("true"));
|
||||
assertEquals(httpMethod.getHeaders().get("Content-Length"), Collections.singletonList("0"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
|
||||
ReturnTrueIfContainerAlreadyExists.class);
|
||||
}
|
||||
|
||||
public void testListBlobs() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobConnection.class.getMethod("listBlobs", String.class, Array
|
||||
.newInstance(ListBlobsOptions.class, 0).getClass());
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "container" });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/container");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container&comp=list");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
|
||||
assertEquals(httpMethod.getHeaders().size(), 1);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ParseSax.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
}
|
||||
|
||||
public void testListRootBlobs() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobConnection.class.getMethod("listBlobs", Array.newInstance(
|
||||
ListBlobsOptions.class, 0).getClass());
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] {});
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/$root");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container&comp=list");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
|
||||
assertEquals(httpMethod.getHeaders().size(), 1);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ParseSax.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
}
|
||||
|
||||
public void testContainerProperties() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobConnection.class.getMethod("getContainerProperties", String.class);
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "container" });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/container");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.HEAD);
|
||||
assertEquals(httpMethod.getHeaders().size(), 1);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ParseContainerMetadataFromHeaders.class);
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
}
|
||||
|
||||
public void testSetContainerMetadata() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobConnection.class.getMethod("setContainerMetadata", String.class,
|
||||
Multimap.class);
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "container",
|
||||
ImmutableMultimap.of("key", "value") });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/container");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container&comp=metadata");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
|
||||
assertEquals(httpMethod.getHeaders().size(), 2);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-meta-key"), Collections.singletonList("value"));
|
||||
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ReturnVoidIf2xx.class);
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
}
|
||||
|
||||
public void testSetBlobMetadata() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobConnection.class.getMethod("setBlobMetadata", String.class,
|
||||
String.class, Multimap.class);
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "container", "blob",
|
||||
ImmutableMultimap.of("key", "value") });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/container/blob");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "comp=metadata");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
|
||||
assertEquals(httpMethod.getHeaders().size(), 2);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-meta-key"), Collections.singletonList("value"));
|
||||
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ReturnVoidIf2xx.class);
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
void setupFactory() {
|
||||
Injector injector = Guice.createInjector(new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(URI.class).annotatedWith(AzureBlob.class).toInstance(
|
||||
URI.create("http://myaccount.blob.core.windows.net"));
|
||||
bindConstant().annotatedWith(
|
||||
Jsr330.named(AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT)).to(
|
||||
"myaccount");
|
||||
bindConstant().annotatedWith(
|
||||
Jsr330.named(AzureStorageConstants.PROPERTY_AZURESTORAGE_KEY)).to(
|
||||
HttpUtils.toBase64String("key".getBytes()));
|
||||
bindConstant().annotatedWith(
|
||||
Jsr330.named(BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX)).to(
|
||||
"x-ms-meta-");
|
||||
}
|
||||
}, new JaxrsModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
|
||||
new JavaUrlHttpCommandExecutorServiceModule());
|
||||
processor = injector.getInstance(Key
|
||||
.get(new TypeLiteral<JaxrsAnnotationProcessor<AzureBlobConnection>>() {
|
||||
}));
|
||||
}
|
||||
|
||||
JaxrsAnnotationProcessor<AzureBlobConnection> processor;
|
||||
}
|
|
@ -34,8 +34,10 @@ import org.jclouds.azure.storage.blob.config.AzureBlobContextModule;
|
|||
import org.jclouds.azure.storage.blob.config.RestAzureBlobStoreModule;
|
||||
import org.jclouds.azure.storage.blob.config.StubAzureBlobStoreModule;
|
||||
import org.jclouds.azure.storage.blob.config.AzureBlobContextModule.AzureBlobContextImpl;
|
||||
import org.jclouds.azure.storage.blob.internal.StubAzureBlobConnection;
|
||||
import org.jclouds.azure.storage.reference.AzureStorageConstants;
|
||||
import org.jclouds.cloud.CloudContext;
|
||||
import org.jclouds.blobstore.integration.internal.StubBlobStore;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.Injector;
|
||||
|
@ -60,22 +62,26 @@ public class AzureBlobContextBuilderTest {
|
|||
}
|
||||
|
||||
public void testBuildContext() {
|
||||
CloudContext<AzureBlobStore> context = new AzureBlobContextBuilder("id", "secret")
|
||||
.withModules(new StubAzureBlobStoreModule()).buildContext();
|
||||
AzureBlobContext context = new AzureBlobContextBuilder("id", HttpUtils
|
||||
.toBase64String("secret".getBytes())).withModules(new StubAzureBlobStoreModule())
|
||||
.buildContext();
|
||||
assertEquals(context.getClass(), AzureBlobContextImpl.class);
|
||||
assertEquals(context.getApi().getClass(), StubAzureBlobConnection.class);
|
||||
assertEquals(context.getBlobStore().getClass(), StubBlobStore.class);
|
||||
assertEquals(context.getAccount(), "id");
|
||||
assertEquals(context.getEndPoint(), URI.create("https://id.blob.core.windows.net"));
|
||||
}
|
||||
|
||||
public void testBuildInjector() {
|
||||
Injector i = new AzureBlobContextBuilder("id", "secret").withModules(
|
||||
new StubAzureBlobStoreModule()).buildInjector();
|
||||
Injector i = new AzureBlobContextBuilder("id", HttpUtils.toBase64String("secret".getBytes()))
|
||||
.withModules(new StubAzureBlobStoreModule()).buildInjector();
|
||||
assert i.getInstance(AzureBlobContext.class) != null;
|
||||
}
|
||||
|
||||
protected void testAddContextModule() {
|
||||
List<Module> modules = new ArrayList<Module>();
|
||||
AzureBlobContextBuilder builder = new AzureBlobContextBuilder("id", "secret");
|
||||
AzureBlobContextBuilder builder = new AzureBlobContextBuilder("id", HttpUtils
|
||||
.toBase64String("secret".getBytes()));
|
||||
builder.addContextModule(modules);
|
||||
assertEquals(modules.size(), 1);
|
||||
assertEquals(modules.get(0).getClass(), AzureBlobContextModule.class);
|
||||
|
@ -83,7 +89,8 @@ public class AzureBlobContextBuilderTest {
|
|||
|
||||
protected void addConnectionModule() {
|
||||
List<Module> modules = new ArrayList<Module>();
|
||||
AzureBlobContextBuilder builder = new AzureBlobContextBuilder("id", "secret");
|
||||
AzureBlobContextBuilder builder = new AzureBlobContextBuilder("id", HttpUtils
|
||||
.toBase64String("secret".getBytes()));
|
||||
builder.addConnectionModule(modules);
|
||||
assertEquals(modules.size(), 1);
|
||||
assertEquals(modules.get(0).getClass(), RestAzureBlobStoreModule.class);
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
*
|
||||
* 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.azure.storage.blob;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import org.jclouds.azure.storage.blob.config.AzureBlobContextModule;
|
||||
import org.jclouds.azure.storage.blob.config.StubAzureBlobStoreModule;
|
||||
import org.jclouds.azure.storage.blob.config.AzureBlobContextModule.AzureBlobContextImpl;
|
||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||
import org.jclouds.azure.storage.blob.reference.AzureBlobConstants;
|
||||
import org.jclouds.blobstore.BlobStoreMapsModule;
|
||||
import org.jclouds.util.Jsr330;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "azureblob.AzureBlobContextModuleTest")
|
||||
public class AzureBlobContextModuleTest {
|
||||
|
||||
Injector createInjector() {
|
||||
return Guice.createInjector(new StubAzureBlobStoreModule(), BlobStoreMapsModule.Builder
|
||||
.newBuilder(new TypeLiteral<ContainerMetadata>() {
|
||||
}, new TypeLiteral<BlobMetadata>() {
|
||||
}, new TypeLiteral<Blob>() {
|
||||
}).build(), new AzureBlobContextModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bindConstant().annotatedWith(
|
||||
Jsr330.named(AzureBlobConstants.PROPERTY_AZURESTORAGE_ACCOUNT)).to("user");
|
||||
bindConstant()
|
||||
.annotatedWith(Jsr330.named(AzureBlobConstants.PROPERTY_AZURESTORAGE_KEY)).to(
|
||||
"key");
|
||||
bindConstant().annotatedWith(
|
||||
Jsr330.named(AzureBlobConstants.PROPERTY_AZUREBLOB_ENDPOINT)).to(
|
||||
"http://localhost");
|
||||
super.configure();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testContextImpl() {
|
||||
AzureBlobContext handler = createInjector().getInstance(AzureBlobContext.class);
|
||||
assertEquals(handler.getClass(), AzureBlobContextImpl.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -23,41 +23,43 @@
|
|||
*/
|
||||
package org.jclouds.azure.storage.blob;
|
||||
|
||||
import static org.jclouds.azure.storage.blob.options.CreateContainerOptions.Builder.withPublicAcl;
|
||||
import static org.jclouds.azure.storage.options.ListOptions.Builder.maxResults;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.HttpMethod;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
||||
import org.jclouds.azure.storage.AzureBlob;
|
||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||
import org.jclouds.azure.storage.blob.functions.ReturnTrueIfContainerAlreadyExists;
|
||||
import org.jclouds.azure.storage.blob.options.CreateContainerOptions;
|
||||
import org.jclouds.azure.storage.options.CreateOptions;
|
||||
import org.jclouds.azure.storage.options.ListOptions;
|
||||
import org.jclouds.azure.storage.reference.AzureStorageConstants;
|
||||
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.blobstore.reference.BlobStoreConstants;
|
||||
import org.jclouds.concurrent.WithinThreadExecutorService;
|
||||
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
||||
import org.jclouds.http.functions.ParseETagHeader;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
import org.jclouds.http.functions.ReturnTrueIf2xx;
|
||||
import org.jclouds.http.functions.ReturnTrueOn404;
|
||||
import org.jclouds.http.functions.ReturnVoidIf2xx;
|
||||
import org.jclouds.rest.JaxrsAnnotationProcessor;
|
||||
import org.jclouds.rest.config.JaxrsModule;
|
||||
import org.jclouds.util.Jsr330;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
|
@ -65,7 +67,7 @@ import com.google.inject.TypeLiteral;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "cloudservers.AzureBlobStoreTest")
|
||||
@Test(groups = "unit", testName = "azureblob.AzureBlobStoreTest")
|
||||
public class AzureBlobStoreTest {
|
||||
|
||||
public void testListContainers() throws SecurityException, NoSuchMethodException {
|
||||
|
@ -85,27 +87,6 @@ public class AzureBlobStoreTest {
|
|||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
}
|
||||
|
||||
public void testListContainersOptions() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobStore.class.getMethod("listContainers", ListOptions.class);
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] { maxResults(1).marker(
|
||||
"marker").prefix("prefix") });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/");
|
||||
assert httpMethod.getEndpoint().getQuery().contains("comp=list");
|
||||
assert httpMethod.getEndpoint().getQuery().contains("marker=marker");
|
||||
assert httpMethod.getEndpoint().getQuery().contains("maxresults=1");
|
||||
assert httpMethod.getEndpoint().getQuery().contains("prefix=prefix");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
|
||||
assertEquals(httpMethod.getHeaders().size(), 1);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ParseSax.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
}
|
||||
|
||||
public void testCreateContainer() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobStore.class.getMethod("createContainer", String.class);
|
||||
|
||||
|
@ -137,94 +118,10 @@ public class AzureBlobStoreTest {
|
|||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
ReturnVoidIf2xx.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
|
||||
ReturnTrueOn404.class);
|
||||
}
|
||||
|
||||
public void testCreateContainerOptions() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobStore.class.getMethod("createContainer", String.class,
|
||||
CreateContainerOptions.class);
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "container",
|
||||
withPublicAcl().withMetadata(ImmutableMultimap.of("foo", "bar")) });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/container");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
|
||||
assertEquals(httpMethod.getHeaders().size(), 4);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-meta-foo"), Collections.singletonList("bar"));
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-prop-publicaccess"), Collections
|
||||
.singletonList("true"));
|
||||
assertEquals(httpMethod.getHeaders().get("Content-Length"), Collections.singletonList("0"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
|
||||
ReturnTrueIfContainerAlreadyExists.class);
|
||||
}
|
||||
|
||||
public void testCreateRootContainer() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobStore.class.getMethod("createRootContainer");
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] {});
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/$root");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
|
||||
assertEquals(httpMethod.getHeaders().size(), 2);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(httpMethod.getHeaders().get("Content-Length"), Collections.singletonList("0"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
|
||||
ReturnTrueIfContainerAlreadyExists.class);
|
||||
}
|
||||
|
||||
public void testDeleteRootContainer() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobStore.class.getMethod("deleteRootContainer");
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] {});
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/$root");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.DELETE);
|
||||
assertEquals(httpMethod.getHeaders().size(), 1);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
|
||||
ReturnTrueOn404.class);
|
||||
}
|
||||
|
||||
public void testCreateRootContainerOptions() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobStore.class.getMethod("createRootContainer", CreateOptions.class);
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] { withPublicAcl()
|
||||
.withMetadata(ImmutableMultimap.of("foo", "bar")) });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/$root");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
|
||||
assertEquals(httpMethod.getHeaders().size(), 4);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-meta-foo"), Collections.singletonList("bar"));
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-prop-publicaccess"), Collections
|
||||
.singletonList("true"));
|
||||
assertEquals(httpMethod.getHeaders().get("Content-Length"), Collections.singletonList("0"));
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
|
||||
ReturnTrueIfContainerAlreadyExists.class);
|
||||
ReturnVoidOnNotFoundOr404.class);
|
||||
}
|
||||
|
||||
public void testListBlobs() throws SecurityException, NoSuchMethodException {
|
||||
|
@ -244,21 +141,29 @@ public class AzureBlobStoreTest {
|
|||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
}
|
||||
|
||||
public void testListRootBlobs() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobStore.class.getMethod("listBlobs");
|
||||
public void testPutBlob() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = AzureBlobStore.class.getMethod("putBlob", String.class, Blob.class);
|
||||
|
||||
HttpRequest httpMethod = processor.createRequest(method, new Object[] {});
|
||||
Blob blob = new Blob("test");
|
||||
blob.setData("test");
|
||||
HttpRequest httpMethod = processor
|
||||
.createRequest(method, new Object[] { "mycontainer", blob });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "myaccount.blob.core.windows.net");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/$root");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container&comp=list");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
|
||||
assertEquals(httpMethod.getHeaders().size(), 1);
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/mycontainer/test");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), null);
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
|
||||
assertEquals(httpMethod.getHeaders().size(), 4);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_LENGTH), Collections
|
||||
.singletonList("test".length() + ""));
|
||||
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_TYPE), Collections
|
||||
.singletonList("application/octet-stream"));
|
||||
assertEquals(httpMethod.getHeaders().get("Content-MD5"), Collections.singletonList(HttpUtils
|
||||
.toBase64String(HttpUtils.md5("test"))));
|
||||
assertEquals(httpMethod.getEntity(), "test");
|
||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||
ParseSax.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
ParseETagHeader.class);
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
|
@ -274,7 +179,22 @@ public class AzureBlobStoreTest {
|
|||
bindConstant().annotatedWith(
|
||||
Jsr330.named(AzureStorageConstants.PROPERTY_AZURESTORAGE_KEY)).to(
|
||||
HttpUtils.toBase64String("key".getBytes()));
|
||||
bindConstant().annotatedWith(
|
||||
Jsr330.named(BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX)).to("prefix");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Provides
|
||||
@Singleton
|
||||
AzureBlobUtil getAzureBlobUtil() {
|
||||
return new AzureBlobUtil() {
|
||||
|
||||
public byte[] getMD5(URI container, String key) {
|
||||
return HttpUtils.fromHexString("01");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}, new JaxrsModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
|
||||
new JavaUrlHttpCommandExecutorServiceModule());
|
||||
processor = injector.getInstance(Key
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
*
|
||||
* 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.azure.storage.blob.config;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import org.jclouds.azure.storage.blob.handlers.AzureBlobClientErrorRetryHandler;
|
||||
import org.jclouds.azure.storage.blob.reference.AzureBlobConstants;
|
||||
import org.jclouds.azure.storage.handlers.ParseAzureStorageErrorFromXmlContent;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.http.functions.config.ParserModule;
|
||||
import org.jclouds.http.handlers.DelegatingErrorHandler;
|
||||
import org.jclouds.http.handlers.DelegatingRetryHandler;
|
||||
import org.jclouds.http.handlers.RedirectionRetryHandler;
|
||||
import org.jclouds.util.Jsr330;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "s3.RestAzureBlobConnectionModuleTest")
|
||||
public class RestAzureBlobConnectionModuleTest {
|
||||
|
||||
Injector createInjector() {
|
||||
return Guice.createInjector(new RestAzureBlobStoreModule(), new ParserModule(),
|
||||
new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bindConstant().annotatedWith(
|
||||
Jsr330.named(AzureBlobConstants.PROPERTY_AZURESTORAGE_ACCOUNT)).to(
|
||||
"user");
|
||||
bindConstant().annotatedWith(
|
||||
Jsr330.named(AzureBlobConstants.PROPERTY_AZURESTORAGE_KEY)).to(
|
||||
HttpUtils.toBase64String("secret".getBytes()));
|
||||
bindConstant().annotatedWith(
|
||||
Jsr330.named(AzureBlobConstants.PROPERTY_AZUREBLOB_ENDPOINT)).to(
|
||||
"http://localhost");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testServerErrorHandler() {
|
||||
DelegatingErrorHandler handler = createInjector().getInstance(DelegatingErrorHandler.class);
|
||||
assertEquals(handler.getServerErrorHandler().getClass(),
|
||||
ParseAzureStorageErrorFromXmlContent.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testClientErrorHandler() {
|
||||
DelegatingErrorHandler handler = createInjector().getInstance(DelegatingErrorHandler.class);
|
||||
assertEquals(handler.getClientErrorHandler().getClass(),
|
||||
ParseAzureStorageErrorFromXmlContent.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testClientRetryHandler() {
|
||||
DelegatingRetryHandler handler = createInjector().getInstance(DelegatingRetryHandler.class);
|
||||
assertEquals(handler.getClientErrorRetryHandler().getClass(),
|
||||
AzureBlobClientErrorRetryHandler.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRedirectionRetryHandler() {
|
||||
DelegatingRetryHandler handler = createInjector().getInstance(DelegatingRetryHandler.class);
|
||||
assertEquals(handler.getRedirectionRetryHandler().getClass(), RedirectionRetryHandler.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -28,9 +28,13 @@ import java.util.Map;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.jclouds.azure.storage.AzureBlob;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||
import org.jclouds.azure.storage.blob.internal.StubAzureBlobStore;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||
import org.jclouds.azure.storage.blob.internal.StubAzureBlobConnection;
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.integration.internal.StubBlobStore;
|
||||
import org.jclouds.cloud.ConfiguresCloudConnection;
|
||||
import org.jclouds.http.functions.config.ParserModule;
|
||||
|
||||
|
@ -51,7 +55,10 @@ public class StubAzureBlobStoreModule extends AbstractModule {
|
|||
install(new ParserModule());
|
||||
bind(new TypeLiteral<Map<String, Map<String, Blob>>>() {
|
||||
}).toInstance(map);
|
||||
bind(AzureBlobStore.class).to(StubAzureBlobStore.class).asEagerSingleton();
|
||||
bind(new TypeLiteral<BlobStore<ContainerMetadata, BlobMetadata, Blob>>() {
|
||||
}).to(new TypeLiteral<StubBlobStore<ContainerMetadata, BlobMetadata, Blob>>() {
|
||||
}).asEagerSingleton();
|
||||
bind(AzureBlobConnection.class).to(StubAzureBlobConnection.class).asEagerSingleton();
|
||||
bind(URI.class).annotatedWith(AzureBlob.class).toInstance(
|
||||
URI.create("https://id.blob.core.windows.net"));
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
*/
|
||||
package org.jclouds.azure.storage.blob.integration;
|
||||
|
||||
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||
|
@ -33,11 +33,8 @@ import org.testng.annotations.Test;
|
|||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = { "integration", "live" }, testName = "cloudfiles.AzureBlobContainerIntegrationTest")
|
||||
@Test(groups = { "integration", "live" }, testName = "azureblob.AzureBlobContainerIntegrationTest")
|
||||
public class AzureBlobContainerIntegrationTest extends
|
||||
BaseContainerIntegrationTest<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> {
|
||||
@Test(groups = { "integration", "live" }, enabled = false)
|
||||
public void deleteContainerIfEmptyButHasContents() throws Exception {
|
||||
// azure recursively deletes containers in the background.
|
||||
}
|
||||
BaseContainerIntegrationTest<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> {
|
||||
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
*/
|
||||
package org.jclouds.azure.storage.blob.integration;
|
||||
|
||||
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||
|
@ -33,8 +33,8 @@ import org.testng.annotations.Test;
|
|||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = { "live" }, testName = "cloudfiles.AzureBlobContainerLiveTest")
|
||||
@Test(groups = { "live" }, testName = "azureblob.AzureBlobContainerLiveTest")
|
||||
public class AzureBlobContainerLiveTest extends
|
||||
BaseContainerLiveTest<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> {
|
||||
BaseContainerLiveTest<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> {
|
||||
|
||||
}
|
|
@ -23,10 +23,7 @@
|
|||
*/
|
||||
package org.jclouds.azure.storage.blob.integration;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||
|
@ -36,31 +33,9 @@ import org.testng.annotations.Test;
|
|||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = { "integration", "live" }, testName = "cloudfiles.AzureBlobInputStreamMapIntegrationTest")
|
||||
public class AzureBlobInputStreamMapIntegrationTest extends
|
||||
BaseInputStreamMapIntegrationTest<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> {
|
||||
@Test(groups = { "integration", "live" }, testName = "azureblob.AzureBlobInputStreamMapIntegrationTest")
|
||||
public class AzureBlobInputStreamMapIntegrationTest
|
||||
extends
|
||||
BaseInputStreamMapIntegrationTest<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> {
|
||||
|
||||
@Override
|
||||
public void testContainsBytesValue() throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
// http://code.google.com/p/jclouds/issues/detail?id=90
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testContainsFileValue() throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
// http://code.google.com/p/jclouds/issues/detail?id=90
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testContainsInputStreamValue() throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
// http://code.google.com/p/jclouds/issues/detail?id=90
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testContainsStringValue() throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
// http://code.google.com/p/jclouds/issues/detail?id=90
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ import java.util.Collections;
|
|||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||
|
@ -41,9 +41,9 @@ import org.testng.annotations.Test;
|
|||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = { "integration", "live" }, testName = "cloudfiles.AzureBlobIntegrationTest")
|
||||
@Test(groups = { "integration", "live" }, testName = "azureblob.AzureBlobIntegrationTest")
|
||||
public class AzureBlobIntegrationTest extends
|
||||
BaseBlobIntegrationTest<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> {
|
||||
BaseBlobIntegrationTest<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> {
|
||||
|
||||
@Override
|
||||
@Test(enabled = false)
|
||||
|
@ -68,7 +68,7 @@ public class AzureBlobIntegrationTest extends
|
|||
|
||||
protected void validateMetadata(BlobMetadata metadata) {
|
||||
assertEquals(metadata.getContentType(), "text/plain");
|
||||
// we can't check this while hacking around lack of content-md5, as GET of the first byte will
|
||||
// we can't check this while hacking around HEAD being broken, as GET of the first byte will
|
||||
// show incorrect length 1, the returned size, as opposed to the real length. This is an ok
|
||||
// tradeoff, as a container list will contain the correct size of the objects in an
|
||||
// inexpensive fashion
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
*/
|
||||
package org.jclouds.azure.storage.blob.integration;
|
||||
|
||||
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||
|
@ -33,8 +33,8 @@ import org.testng.annotations.Test;
|
|||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = { "live" }, testName = "cloudfiles.AzureBlobLiveTest")
|
||||
@Test(groups = { "live" }, testName = "azureblob.AzureBlobLiveTest")
|
||||
public class AzureBlobLiveTest extends
|
||||
BaseBlobLiveTest<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> {
|
||||
BaseBlobLiveTest<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> {
|
||||
|
||||
}
|
|
@ -23,10 +23,7 @@
|
|||
*/
|
||||
package org.jclouds.azure.storage.blob.integration;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||
|
@ -36,12 +33,8 @@ import org.testng.annotations.Test;
|
|||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = { "integration", "live" }, testName = "cloudfiles.AzureBlobMapIntegrationTest")
|
||||
@Test(groups = { "integration", "live" }, testName = "azureblob.AzureBlobMapIntegrationTest")
|
||||
public class AzureBlobMapIntegrationTest extends
|
||||
BaseBlobMapIntegrationTest<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> {
|
||||
BaseBlobMapIntegrationTest<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> {
|
||||
|
||||
@Override
|
||||
public void testContains() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
// http://code.google.com/p/jclouds/issues/detail?id=90
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
*/
|
||||
package org.jclouds.azure.storage.blob.integration;
|
||||
|
||||
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||
|
@ -33,8 +33,8 @@ import org.testng.annotations.Test;
|
|||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = { "integration", "live" }, testName = "cloudfiles.AzureBlobServiceIntegrationTest")
|
||||
@Test(groups = { "integration", "live" }, testName = "azureblob.AzureBlobServiceIntegrationTest")
|
||||
public class AzureBlobServiceIntegrationTest extends
|
||||
BaseServiceIntegrationTest<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> {
|
||||
BaseServiceIntegrationTest<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> {
|
||||
|
||||
}
|
|
@ -23,9 +23,9 @@
|
|||
*/
|
||||
package org.jclouds.azure.storage.blob.integration;
|
||||
|
||||
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobContextBuilder;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobContextFactory;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
||||
import org.jclouds.azure.storage.blob.config.StubAzureBlobStoreModule;
|
||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
|
@ -41,17 +41,17 @@ import com.google.inject.Module;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
public class AzureBlobTestInitializer extends
|
||||
BaseTestInitializer<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> {
|
||||
BaseTestInitializer<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> {
|
||||
|
||||
@Override
|
||||
protected BlobStoreContext<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> createLiveContext(
|
||||
protected BlobStoreContext<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> createLiveContext(
|
||||
Module configurationModule, String url, String app, String account, String key) {
|
||||
return new AzureBlobContextBuilder(account, key).withSaxDebug().relaxSSLHostname()
|
||||
.withModules(configurationModule, new Log4JLoggingModule()).buildContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlobStoreContext<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> createStubContext() {
|
||||
protected BlobStoreContext<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> createStubContext() {
|
||||
return AzureBlobContextFactory.createContext("user", "pass", new StubAzureBlobStoreModule());
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ import java.util.concurrent.Future;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
|
@ -39,15 +40,17 @@ import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
|||
import org.jclouds.azure.storage.blob.domain.ListBlobsResponse;
|
||||
import org.jclouds.azure.storage.blob.domain.TreeSetListBlobsResponse;
|
||||
import org.jclouds.azure.storage.blob.options.CreateContainerOptions;
|
||||
import org.jclouds.azure.storage.blob.options.ListBlobsOptions;
|
||||
import org.jclouds.azure.storage.domain.BoundedSortedSet;
|
||||
import org.jclouds.azure.storage.options.CreateOptions;
|
||||
import org.jclouds.azure.storage.options.ListOptions;
|
||||
import org.jclouds.blobstore.ContainerNotFoundException;
|
||||
import org.jclouds.blobstore.integration.internal.StubBlobStore;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
import org.jclouds.util.DateService;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
|
@ -55,40 +58,16 @@ import com.google.common.collect.Sets;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class StubAzureBlobStore extends StubBlobStore<ContainerMetadata, BlobMetadata, Blob>
|
||||
implements AzureBlobStore {
|
||||
public class StubAzureBlobConnection extends StubBlobStore<ContainerMetadata, BlobMetadata, Blob>
|
||||
implements AzureBlobConnection {
|
||||
|
||||
@Inject
|
||||
protected StubAzureBlobStore(Map<String, Map<String, Blob>> containerToBlobs,
|
||||
protected StubAzureBlobConnection(Map<String, Map<String, Blob>> containerToBlobs,
|
||||
DateService dateService, Provider<ContainerMetadata> containerMetaProvider,
|
||||
Provider<Blob> blobProvider) {
|
||||
super(containerToBlobs, dateService, containerMetaProvider, blobProvider);
|
||||
}
|
||||
|
||||
public BoundedSortedSet<ContainerMetadata> listContainers(ListOptions options) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Future<Boolean> createContainer(String container, CreateContainerOptions options) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Future<Boolean> createRootContainer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Future<Boolean> createRootContainer(CreateOptions options) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Future<Boolean> deleteRootContainer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Future<ListBlobsResponse> listBlobs() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Future<ListBlobsResponse> listBlobs(final String name) {
|
||||
return new FutureBase<ListBlobsResponse>() {
|
||||
public ListBlobsResponse get() throws InterruptedException, ExecutionException {
|
||||
|
@ -109,4 +88,51 @@ public class StubAzureBlobStore extends StubBlobStore<ContainerMetadata, BlobMet
|
|||
};
|
||||
}
|
||||
|
||||
public Future<Boolean> createContainer(String container, CreateContainerOptions... options) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Future<Void> deleteBlob(String container, String key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Future<Boolean> deleteRootContainer() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Future<Blob> getBlob(String container, String key, GetOptions... options) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public BlobMetadata getBlobProperties(String container, String key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Future<ListBlobsResponse> listBlobs(String container, ListBlobsOptions... options) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Future<ListBlobsResponse> listBlobs(ListBlobsOptions... options) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public BoundedSortedSet<ContainerMetadata> listContainers(ListOptions... listOptions) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Future<Boolean> createRootContainer(CreateContainerOptions... options) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public ContainerMetadata getContainerProperties(String container) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void setContainerMetadata(String container, Multimap<String, String> metadata) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void setBlobMetadata(String container, String key, Multimap<String, String> metadata) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
*
|
||||
* 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.azure.storage.blob.xml;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.azure.storage.blob.AzureBlobUtil;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ListBlobsResponse;
|
||||
import org.jclouds.azure.storage.blob.domain.TreeSetListBlobsResponse;
|
||||
import org.jclouds.azure.storage.domain.BoundedSortedSet;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.http.functions.BaseHandlerTest;
|
||||
import org.jclouds.util.DateService;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code AddMD5ToListBlobsResponse}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "azureblob.AddMD5ToListBlobsResponseTest")
|
||||
public class AddMD5ToListBlobsResponseTest extends BaseHandlerTest {
|
||||
private DateService dateService;
|
||||
|
||||
@BeforeTest
|
||||
@Override
|
||||
protected void setUpInjector() {
|
||||
super.setUpInjector();
|
||||
injector = injector.createChildInjector(new AbstractModule() {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Provides
|
||||
@Singleton
|
||||
AzureBlobUtil getAzureBlobUtil() {
|
||||
return new AzureBlobUtil() {
|
||||
|
||||
public byte[] getMD5(URI container, String key) {
|
||||
if (key.equals("blob1.txt")) {
|
||||
return HttpUtils.fromHexString("01");
|
||||
} else if (key.equals("blob2.txt")) {
|
||||
return HttpUtils.fromHexString("02");
|
||||
} else if (key.equals("newblob1.txt")) {
|
||||
return HttpUtils.fromHexString("03");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
dateService = injector.getInstance(DateService.class);
|
||||
assert dateService != null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testApplyInputStream() {
|
||||
InputStream is = getClass().getResourceAsStream("/test_list_blobs.xml");
|
||||
ListBlobsResponse list = new TreeSetListBlobsResponse(
|
||||
URI.create("http://myaccount.blob.core.windows.net/mycontainer"),
|
||||
ImmutableSortedSet
|
||||
.of(
|
||||
new BlobMetadata(
|
||||
"blob1.txt",
|
||||
URI
|
||||
.create("http://myaccount.blob.core.windows.net/mycontainer/blob1.txt"),
|
||||
dateService
|
||||
.rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"),
|
||||
HttpUtils.fromHexString("0x8CAE7D55D050B8B"), 8,
|
||||
"text/plain; charset=UTF-8", HttpUtils
|
||||
.fromHexString("01"), null, null),
|
||||
new BlobMetadata(
|
||||
"blob2.txt",
|
||||
URI
|
||||
.create("http://myaccount.blob.core.windows.net/mycontainer/blob2.txt"),
|
||||
dateService
|
||||
.rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"),
|
||||
HttpUtils.fromHexString("0x8CAE7D55CF6C339"), 14,
|
||||
"text/plain; charset=UTF-8", HttpUtils
|
||||
.fromHexString("02"), null, null),
|
||||
new BlobMetadata(
|
||||
"newblob1.txt",
|
||||
URI
|
||||
.create("http://myaccount.blob.core.windows.net/mycontainer/newblob1.txt"),
|
||||
dateService
|
||||
.rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"),
|
||||
HttpUtils.fromHexString("0x8CAE7D55CF6C339"), 25,
|
||||
"text/plain; charset=UTF-8", HttpUtils
|
||||
.fromHexString("03"), null, null)
|
||||
|
||||
), null, null, 4, "newblob2.txt", null, "myfolder/");
|
||||
|
||||
BoundedSortedSet<ListBlobsResponse> result = (BoundedSortedSet<ListBlobsResponse>) factory
|
||||
.create(injector.getInstance(ContainerNameEnumerationResultsHandler.class))
|
||||
.parse(is);
|
||||
|
||||
assertEquals(result, list);
|
||||
}
|
||||
}
|
|
@ -84,9 +84,11 @@ public class AzureQueueConnectionLiveTest {
|
|||
created = connection.createQueue(privateQueue, CreateOptions.Builder
|
||||
.withMetadata(ImmutableMultimap.of("foo", "bar")));
|
||||
} catch (UndeclaredThrowableException e) {
|
||||
if (e.getCause().getCause() instanceof HttpResponseException) {
|
||||
HttpResponseException htpe = (HttpResponseException) e.getCause().getCause();
|
||||
if (htpe.getResponse().getStatusCode() == 409)
|
||||
continue;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,13 +42,11 @@ public interface BlobStore<C extends ContainerMetadata, M extends BlobMetadata,
|
|||
Future<Boolean> createContainer(String container);
|
||||
|
||||
/**
|
||||
* if supported, this will delete a container recursively. Otherwise, it will return false, if
|
||||
* the container could not be deleted because it is not empty.
|
||||
* This will delete a container recursively.
|
||||
*
|
||||
* @param container
|
||||
* @return false if container cannot be deleted because it is not empty
|
||||
*/
|
||||
Future<Boolean> deleteContainer(String container);
|
||||
Future<Void> deleteContainer(String container);
|
||||
|
||||
Future<? extends SortedSet<M>> listBlobs(String container);
|
||||
|
||||
|
@ -60,6 +58,6 @@ public interface BlobStore<C extends ContainerMetadata, M extends BlobMetadata,
|
|||
|
||||
M blobMetadata(String container, String key);
|
||||
|
||||
Future<Boolean> removeBlob(String container, String key);
|
||||
Future<Void> removeBlob(String container, String key);
|
||||
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ import com.google.inject.ImplementedBy;
|
|||
*
|
||||
*/
|
||||
@ImplementedBy(BlobStoreContextImpl.class)
|
||||
public interface BlobStoreContext<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
public interface BlobStoreContext<S, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
extends CloudContext<S> {
|
||||
|
||||
/**
|
||||
|
@ -55,5 +55,7 @@ public interface BlobStoreContext<S extends BlobStore<C, M, B>, C extends Contai
|
|||
*/
|
||||
BlobMap<M, B> createBlobMap(String container);
|
||||
|
||||
BlobStore<C, M, B> getBlobStore();
|
||||
|
||||
B newBlob(String key);
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.jclouds.blobstore;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
|
@ -39,7 +40,7 @@ import com.google.inject.util.Types;
|
|||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public abstract class BlobStoreContextBuilder<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
public abstract class BlobStoreContextBuilder<S, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
extends CloudContextBuilder<S> {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
|
@ -141,8 +142,12 @@ public abstract class BlobStoreContextBuilder<S extends BlobStore<C, M, B>, C ex
|
|||
this.containerMetadataType = containerMetadataType;
|
||||
this.blobMetadataType = blobMetadataType;
|
||||
this.blobType = blobType;
|
||||
modules.add(BlobStoreMapsModule.Builder.newBuilder(connectionType,
|
||||
containerMetadataType, blobMetadataType, blobType).build());
|
||||
addBlobStoreModule(modules);
|
||||
}
|
||||
|
||||
protected void addBlobStoreModule(List<Module> modules) {
|
||||
modules.add(BlobStoreMapsModule.Builder.newBuilder(containerMetadataType, blobMetadataType,
|
||||
blobType).build());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -36,19 +36,22 @@ import org.jclouds.lifecycle.Closer;
|
|||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class BlobStoreContextImpl<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
public class BlobStoreContextImpl<S, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
extends CloudContextImpl<S> implements BlobStoreContext<S, C, M, B> {
|
||||
private final BlobMap.Factory<M, B> blobMapFactory;
|
||||
private final InputStreamMap.Factory<M> inputStreamMapFactory;
|
||||
private final Provider<B> blobProvider;
|
||||
private final BlobStore<C, M, B> blobStore;
|
||||
|
||||
public BlobStoreContextImpl(BlobMap.Factory<M, B> blobMapFactory,
|
||||
InputStreamMap.Factory<M> inputStreamMapFactory, Closer closer,
|
||||
Provider<B> blobProvider, S defaultApi, URI endPoint, String account) {
|
||||
Provider<B> blobProvider, BlobStore<C, M, B> blobStore, S defaultApi, URI endPoint,
|
||||
String account) {
|
||||
super(closer, defaultApi, endPoint, account);
|
||||
this.blobMapFactory = blobMapFactory;
|
||||
this.inputStreamMapFactory = inputStreamMapFactory;
|
||||
this.blobProvider = blobProvider;
|
||||
this.blobStore = blobStore;
|
||||
}
|
||||
|
||||
public BlobMap<M, B> createBlobMap(String container) {
|
||||
|
@ -66,4 +69,8 @@ public class BlobStoreContextImpl<S extends BlobStore<C, M, B>, C extends Contai
|
|||
blob.getMetadata().setKey(key);
|
||||
return blob;
|
||||
}
|
||||
|
||||
public BlobStore<C, M, B> getBlobStore() {
|
||||
return blobStore;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,16 +23,26 @@
|
|||
*/
|
||||
package org.jclouds.blobstore;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
import org.jclouds.blobstore.internal.BlobMapImpl;
|
||||
import org.jclouds.blobstore.internal.InputStreamMapImpl;
|
||||
import org.jclouds.blobstore.strategy.ClearContainerStrategy;
|
||||
import org.jclouds.blobstore.strategy.ContainerCountStrategy;
|
||||
import org.jclouds.blobstore.strategy.ContainsValueStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetAllBlobMetadataStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
||||
import org.jclouds.blobstore.strategy.internal.ContainerListGetAllBlobMetadataStrategy;
|
||||
import org.jclouds.blobstore.strategy.internal.ContentMD5ContainsValueStrategy;
|
||||
import org.jclouds.blobstore.strategy.internal.DeleteAllKeysClearContainerStrategy;
|
||||
import org.jclouds.blobstore.strategy.internal.KeyCountStrategy;
|
||||
import org.jclouds.blobstore.strategy.internal.RetryOnNotFoundGetAllBlobsStrategy;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Scopes;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
@ -47,17 +57,12 @@ public class BlobStoreMapsModule extends AbstractModule {
|
|||
@SuppressWarnings("unchecked")
|
||||
private BlobStoreMapsModule(TypeLiteral blobMapFactoryType, TypeLiteral blobMapImplType,
|
||||
TypeLiteral inputStreamMapFactoryType, TypeLiteral inputStreamMapImplType,
|
||||
TypeLiteral getAllBlobsStrategyType, TypeLiteral getAllBlobsStrategyImplType,
|
||||
TypeLiteral getAllBlobMetadataStrategyType,
|
||||
TypeLiteral getAllBlobMetadataStrategyImplType) {
|
||||
Map<TypeLiteral, TypeLiteral> strategyImplMap) {
|
||||
this.blobMapFactoryType = blobMapFactoryType;
|
||||
this.blobMapImplType = blobMapImplType;
|
||||
this.inputStreamMapFactoryType = inputStreamMapFactoryType;
|
||||
this.inputStreamMapImplType = inputStreamMapImplType;
|
||||
this.getAllBlobsStrategyType = getAllBlobsStrategyType;
|
||||
this.getAllBlobsStrategyImplType = getAllBlobsStrategyImplType;
|
||||
this.getAllBlobMetadataStrategyType = getAllBlobMetadataStrategyType;
|
||||
this.getAllBlobMetadataStrategyImplType = getAllBlobMetadataStrategyImplType;
|
||||
this.strategyImplMap = strategyImplMap;
|
||||
}
|
||||
|
||||
// code is unchecked here as we are getting types at runtime. Due to type erasure, we cannot pass
|
||||
|
@ -71,17 +76,9 @@ public class BlobStoreMapsModule extends AbstractModule {
|
|||
@SuppressWarnings("unchecked")
|
||||
protected final TypeLiteral inputStreamMapImplType;
|
||||
@SuppressWarnings("unchecked")
|
||||
protected final TypeLiteral getAllBlobsStrategyType;
|
||||
@SuppressWarnings("unchecked")
|
||||
protected final TypeLiteral getAllBlobsStrategyImplType;
|
||||
@SuppressWarnings("unchecked")
|
||||
protected final TypeLiteral getAllBlobMetadataStrategyType;
|
||||
@SuppressWarnings("unchecked")
|
||||
protected final TypeLiteral getAllBlobMetadataStrategyImplType;
|
||||
protected final Map<TypeLiteral, TypeLiteral> strategyImplMap;
|
||||
|
||||
public static class Builder<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>> {
|
||||
@SuppressWarnings("unused")
|
||||
private final TypeLiteral<S> connectionType;
|
||||
public static class Builder<S, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>> {
|
||||
private final TypeLiteral<C> containerMetadataType;
|
||||
private final TypeLiteral<M> blobMetadataType;
|
||||
private final TypeLiteral<B> blobType;
|
||||
|
@ -101,23 +98,33 @@ public class BlobStoreMapsModule extends AbstractModule {
|
|||
private TypeLiteral getAllBlobMetadataStrategyType;
|
||||
@SuppressWarnings("unchecked")
|
||||
private TypeLiteral getAllBlobMetadataStrategyImplType;
|
||||
@SuppressWarnings("unchecked")
|
||||
private TypeLiteral containsValueStrategyType;
|
||||
@SuppressWarnings("unchecked")
|
||||
private TypeLiteral containsValueStrategyImplType;
|
||||
@SuppressWarnings("unchecked")
|
||||
private TypeLiteral clearContainerStrategyType;
|
||||
@SuppressWarnings("unchecked")
|
||||
private TypeLiteral clearContainerStrategyImplType;
|
||||
@SuppressWarnings("unchecked")
|
||||
private TypeLiteral containerCountStrategyType;
|
||||
@SuppressWarnings("unchecked")
|
||||
private TypeLiteral containerCountStrategyImplType;
|
||||
|
||||
private Builder(TypeLiteral<S> connectionType, TypeLiteral<C> containerMetadataType,
|
||||
TypeLiteral<M> blobMetadataType, TypeLiteral<B> blobType) {
|
||||
this.connectionType = connectionType;
|
||||
private Builder(TypeLiteral<C> containerMetadataType, TypeLiteral<M> blobMetadataType,
|
||||
TypeLiteral<B> blobType) {
|
||||
this.containerMetadataType = containerMetadataType;
|
||||
this.blobMetadataType = blobMetadataType;
|
||||
this.blobType = blobType;
|
||||
blobMapFactoryType = TypeLiteral.get(Types.newParameterizedTypeWithOwner(BlobMap.class,
|
||||
BlobMap.Factory.class, blobMetadataType.getType(), blobType.getType()));
|
||||
blobMapImplType = TypeLiteral.get(Types.newParameterizedType(BlobMapImpl.class,
|
||||
connectionType.getType(), containerMetadataType.getType(), blobMetadataType
|
||||
.getType(), blobType.getType()));
|
||||
containerMetadataType.getType(), blobMetadataType.getType(), blobType.getType()));
|
||||
inputStreamMapFactoryType = TypeLiteral.get(Types.newParameterizedTypeWithOwner(
|
||||
InputStreamMap.class, InputStreamMap.Factory.class, blobMetadataType.getType()));
|
||||
inputStreamMapImplType = TypeLiteral.get(Types.newParameterizedType(
|
||||
InputStreamMapImpl.class, connectionType.getType(), containerMetadataType
|
||||
.getType(), blobMetadataType.getType(), blobType.getType()));
|
||||
InputStreamMapImpl.class, containerMetadataType.getType(), blobMetadataType
|
||||
.getType(), blobType.getType()));
|
||||
getAllBlobsStrategyType = TypeLiteral.get(Types.newParameterizedType(
|
||||
GetAllBlobsStrategy.class, containerMetadataType.getType(), blobMetadataType
|
||||
.getType(), blobType.getType()));
|
||||
|
@ -126,35 +133,95 @@ public class BlobStoreMapsModule extends AbstractModule {
|
|||
getAllBlobMetadataStrategyType = TypeLiteral.get(Types.newParameterizedType(
|
||||
GetAllBlobMetadataStrategy.class, containerMetadataType.getType(),
|
||||
blobMetadataType.getType(), blobType.getType()));
|
||||
getAllBlobMetadataStrategyImplType = TypeLiteral.get(Types.newParameterizedType(
|
||||
ContainerListGetAllBlobMetadataStrategy.class, containerMetadataType.getType(),
|
||||
blobMetadataType.getType(), blobType.getType()));
|
||||
setGetAllBlobMetadataStrategyImpl(ContainerListGetAllBlobMetadataStrategy.class);
|
||||
|
||||
containsValueStrategyType = TypeLiteral.get(Types.newParameterizedType(
|
||||
ContainsValueStrategy.class, containerMetadataType.getType(), blobMetadataType
|
||||
.getType(), blobType.getType()));
|
||||
setContainsValueStrategyImpl(ContentMD5ContainsValueStrategy.class);
|
||||
|
||||
clearContainerStrategyType = TypeLiteral.get(Types.newParameterizedType(
|
||||
ClearContainerStrategy.class, containerMetadataType.getType(), blobMetadataType
|
||||
.getType(), blobType.getType()));
|
||||
setClearContainerStrategyImpl(DeleteAllKeysClearContainerStrategy.class);
|
||||
containerCountStrategyType = TypeLiteral.get(Types.newParameterizedType(
|
||||
ContainerCountStrategy.class, containerMetadataType.getType(), blobMetadataType
|
||||
.getType(), blobType.getType()));
|
||||
setContainerCountStrategyImpl(KeyCountStrategy.class);
|
||||
}
|
||||
|
||||
Builder<S, C, M, B> withGetAllBlobsStrategy(Class<?> getAllBlobsStrategyImplClass) {
|
||||
public Builder<S, C, M, B> withGetAllBlobsStrategy(Class<?> getAllBlobsStrategyImplClass) {
|
||||
setGetAllBlobsStrategyImpl(getAllBlobsStrategyImplClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<S, C, M, B> withGetAllBlobMetadataStrategy(
|
||||
Class<?> getAllBlobMetadataStrategyImplClass) {
|
||||
setGetAllBlobMetadataStrategyImpl(getAllBlobMetadataStrategyImplClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<S, C, M, B> withContainsValueStrategy(Class<?> containsValueStrategyImplClass) {
|
||||
setContainsValueStrategyImpl(containsValueStrategyImplClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<S, C, M, B> withClearContainerStrategy(Class<?> clearContainerStrategyImplClass) {
|
||||
setClearContainerStrategyImpl(clearContainerStrategyImplClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<S, C, M, B> withContainerCountStrategy(Class<?> containerCountStrategyImplClass) {
|
||||
setContainerCountStrategyImpl(containerCountStrategyImplClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void setGetAllBlobsStrategyImpl(Class<?> getAllBlobsStrategyImplClass) {
|
||||
getAllBlobsStrategyImplType = TypeLiteral.get(Types.newParameterizedType(
|
||||
getAllBlobsStrategyImplClass, containerMetadataType.getType(), blobMetadataType
|
||||
.getType(), blobType.getType()));
|
||||
}
|
||||
|
||||
public static <S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>> Builder<S, C, M, B> newBuilder(
|
||||
TypeLiteral<S> connectionType, TypeLiteral<C> containerMetadataType,
|
||||
TypeLiteral<M> blobMetadataType, TypeLiteral<B> blobType) {
|
||||
return new Builder<S, C, M, B>(connectionType, containerMetadataType, blobMetadataType,
|
||||
blobType);
|
||||
private void setGetAllBlobMetadataStrategyImpl(Class<?> getAllBlobMetadataStrategyImplClass) {
|
||||
getAllBlobMetadataStrategyImplType = TypeLiteral.get(Types.newParameterizedType(
|
||||
getAllBlobMetadataStrategyImplClass, containerMetadataType.getType(),
|
||||
blobMetadataType.getType(), blobType.getType()));
|
||||
}
|
||||
|
||||
public BlobStoreMapsModule build() {
|
||||
private void setContainsValueStrategyImpl(Class<?> containsValueStrategyClass) {
|
||||
containsValueStrategyImplType = TypeLiteral.get(Types.newParameterizedType(
|
||||
containsValueStrategyClass, containerMetadataType.getType(), blobMetadataType
|
||||
.getType(), blobType.getType()));
|
||||
}
|
||||
|
||||
private void setClearContainerStrategyImpl(Class<?> clearContainerStrategyClass) {
|
||||
clearContainerStrategyImplType = TypeLiteral.get(Types.newParameterizedType(
|
||||
clearContainerStrategyClass, containerMetadataType.getType(), blobMetadataType
|
||||
.getType(), blobType.getType()));
|
||||
}
|
||||
|
||||
private void setContainerCountStrategyImpl(Class<?> containerCountStrategyClass) {
|
||||
containerCountStrategyImplType = TypeLiteral.get(Types.newParameterizedType(
|
||||
containerCountStrategyClass, containerMetadataType.getType(), blobMetadataType
|
||||
.getType(), blobType.getType()));
|
||||
}
|
||||
|
||||
public static <S, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>> Builder<S, C, M, B> newBuilder(
|
||||
TypeLiteral<C> containerMetadataType, TypeLiteral<M> blobMetadataType,
|
||||
TypeLiteral<B> blobType) {
|
||||
return new Builder<S, C, M, B>(containerMetadataType, blobMetadataType, blobType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public BlobStoreMapsModule build() {
|
||||
Map<TypeLiteral, TypeLiteral> strategyImplMap = Maps.newHashMap();
|
||||
strategyImplMap.put(getAllBlobsStrategyType, getAllBlobsStrategyImplType);
|
||||
strategyImplMap.put(getAllBlobMetadataStrategyType, getAllBlobMetadataStrategyImplType);
|
||||
strategyImplMap.put(containsValueStrategyType, containsValueStrategyImplType);
|
||||
strategyImplMap.put(clearContainerStrategyType, clearContainerStrategyImplType);
|
||||
strategyImplMap.put(containerCountStrategyType, containerCountStrategyImplType);
|
||||
return new BlobStoreMapsModule(blobMapFactoryType, blobMapImplType,
|
||||
inputStreamMapFactoryType, inputStreamMapImplType, getAllBlobsStrategyType,
|
||||
getAllBlobsStrategyImplType, getAllBlobMetadataStrategyType,
|
||||
getAllBlobMetadataStrategyImplType);
|
||||
inputStreamMapFactoryType, inputStreamMapImplType, strategyImplMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,9 +234,9 @@ public class BlobStoreMapsModule extends AbstractModule {
|
|||
bind(inputStreamMapFactoryType).toProvider(
|
||||
FactoryProvider.newFactory(inputStreamMapFactoryType, inputStreamMapImplType)).in(
|
||||
Scopes.SINGLETON);
|
||||
bind(getAllBlobsStrategyType).to(getAllBlobsStrategyImplType).in(Scopes.SINGLETON);
|
||||
bind(getAllBlobMetadataStrategyType).to(getAllBlobMetadataStrategyImplType).in(
|
||||
Scopes.SINGLETON);
|
||||
for (Entry<TypeLiteral, TypeLiteral> entry : strategyImplMap.entrySet()) {
|
||||
bind(entry.getKey()).to(entry.getValue()).in(Scopes.SINGLETON);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
*/
|
||||
package org.jclouds.blobstore.binders;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.*;
|
||||
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
@ -45,6 +45,7 @@ public class BlobBinder implements EntityBinder {
|
|||
|
||||
public void addEntityToRequest(Object entity, HttpRequest request) {
|
||||
Blob<?> object = (Blob<?>) entity;
|
||||
|
||||
for (String key : object.getMetadata().getUserMetadata().keySet()) {
|
||||
request.getHeaders().putAll(key.startsWith(metadataPrefix) ? key : metadataPrefix + key,
|
||||
object.getMetadata().getUserMetadata().get(key));
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
*
|
||||
* 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.blobstore.functions;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
import org.jclouds.blobstore.internal.BlobRuntimeException;
|
||||
import org.jclouds.blobstore.reference.BlobStoreConstants;
|
||||
import org.jclouds.blobstore.strategy.ClearContainerStrategy;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.rest.RestContext;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
public class ClearAndDeleteIfNotEmpty<C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
implements Function<Exception, Void>, RestContext {
|
||||
static final Void v;
|
||||
static {
|
||||
Constructor<Void> cv;
|
||||
try {
|
||||
cv = Void.class.getDeclaredConstructor();
|
||||
cv.setAccessible(true);
|
||||
v = cv.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new Error("Error setting up class", e);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* maximum duration of an blob Request
|
||||
*/
|
||||
@Inject(optional = true)
|
||||
@Named(BlobStoreConstants.PROPERTY_BLOBSTORE_TIMEOUT)
|
||||
protected long requestTimeoutMilliseconds = 30000;
|
||||
private Object[] args;
|
||||
private HttpRequest request;
|
||||
|
||||
private final ClearContainerStrategy<C, M, B> clear;
|
||||
private final BlobStore<C, M, B> connection;
|
||||
|
||||
@Inject
|
||||
protected
|
||||
ClearAndDeleteIfNotEmpty(ClearContainerStrategy<C, M, B> clear, BlobStore<C, M, B> connection) {
|
||||
this.clear = clear;
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
public Void apply(Exception from) {
|
||||
if (from instanceof HttpResponseException) {
|
||||
HttpResponseException responseException = (HttpResponseException) from;
|
||||
if (responseException.getResponse().getStatusCode() == 404) {
|
||||
return v;
|
||||
} else if (responseException.getResponse().getStatusCode() == 409) {
|
||||
clear.execute(connection, args[0].toString());
|
||||
try {
|
||||
connection.deleteContainer(args[0].toString()).get(requestTimeoutMilliseconds,
|
||||
TimeUnit.MILLISECONDS);
|
||||
return v;
|
||||
} catch (Exception e) {
|
||||
Utils.<BlobRuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
throw new BlobRuntimeException("Error deleting container: " + args[0].toString(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public HttpRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public void setContext(HttpRequest request, Object[] args) {
|
||||
this.request = request;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
*
|
||||
* 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.blobstore.functions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.internal.BlobRuntimeException;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
public class ObjectMD5<M extends BlobMetadata, B extends Blob<M>> implements
|
||||
Function<Object, byte[]> {
|
||||
|
||||
protected final Provider<B> blobFactory;
|
||||
|
||||
@Inject
|
||||
ObjectMD5(Provider<B> blobFactory) {
|
||||
this.blobFactory = blobFactory;
|
||||
}
|
||||
|
||||
public byte[] apply(Object from) {
|
||||
Blob<?> object;
|
||||
if (from instanceof Blob<?>) {
|
||||
object = (Blob<?>) from;
|
||||
} else {
|
||||
object = blobFactory.get();
|
||||
object.setData(from);
|
||||
}
|
||||
if (object.getMetadata().getContentMD5() == null)
|
||||
try {
|
||||
object.generateMD5();
|
||||
} catch (IOException e) {
|
||||
throw new BlobRuntimeException("couldn't get MD5 for: " + from, e);
|
||||
}
|
||||
return object.getMetadata().getContentMD5();
|
||||
}
|
||||
|
||||
}
|
|
@ -23,20 +23,35 @@
|
|||
*/
|
||||
package org.jclouds.blobstore.functions;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
import org.jclouds.blobstore.ContainerNotFoundException;
|
||||
import org.jclouds.blobstore.KeyNotFoundException;
|
||||
import org.jclouds.http.functions.ReturnTrueOn404;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
public class ReturnTrueOnNotFoundOr404 implements Function<Exception, Boolean> {
|
||||
public class ReturnVoidOnNotFoundOr404 implements Function<Exception, Void> {
|
||||
|
||||
static final Void v;
|
||||
static {
|
||||
Constructor<Void> cv;
|
||||
try {
|
||||
cv = Void.class.getDeclaredConstructor();
|
||||
cv.setAccessible(true);
|
||||
v = cv.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new Error("Error setting up class", e);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnTrueOn404 rto404 = new ReturnTrueOn404();
|
||||
|
||||
public Boolean apply(Exception from) {
|
||||
public Void apply(Exception from) {
|
||||
if (from instanceof KeyNotFoundException || from instanceof ContainerNotFoundException) {
|
||||
return true;
|
||||
return v;
|
||||
} else {
|
||||
return rto404.apply(from);
|
||||
return rto404.apply(from) ? v : null;
|
||||
}
|
||||
|
||||
}
|
|
@ -26,15 +26,8 @@ package org.jclouds.blobstore.internal;
|
|||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
@ -46,6 +39,9 @@ import org.jclouds.blobstore.domain.Blob;
|
|||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
import org.jclouds.blobstore.reference.BlobStoreConstants;
|
||||
import org.jclouds.blobstore.strategy.ClearContainerStrategy;
|
||||
import org.jclouds.blobstore.strategy.ContainerCountStrategy;
|
||||
import org.jclouds.blobstore.strategy.ContainsValueStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetAllBlobMetadataStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
||||
import org.jclouds.rest.BoundedSortedSet;
|
||||
|
@ -71,6 +67,9 @@ public abstract class BaseBlobMap<C extends ContainerMetadata, M extends BlobMet
|
|||
protected final Provider<B> blobFactory;
|
||||
protected final GetAllBlobsStrategy<C, M, B> getAllBlobs;
|
||||
protected final GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata;
|
||||
protected final ContainsValueStrategy<C, M, B> containsValueStrategy;
|
||||
protected final ClearContainerStrategy<C, M, B> clearContainerStrategy;
|
||||
protected final ContainerCountStrategy<C, M, B> containerCountStrategy;
|
||||
|
||||
/**
|
||||
* maximum duration of an blob Request
|
||||
|
@ -89,12 +88,18 @@ public abstract class BaseBlobMap<C extends ContainerMetadata, M extends BlobMet
|
|||
@Inject
|
||||
public BaseBlobMap(BlobStore<C, M, B> connection, Provider<B> blobFactory,
|
||||
GetAllBlobsStrategy<C, M, B> getAllBlobs,
|
||||
GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata, @Assisted String containerName) {
|
||||
GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata,
|
||||
ContainsValueStrategy<C, M, B> containsValueStrategy,
|
||||
ClearContainerStrategy<C, M, B> clearContainerStrategy,
|
||||
ContainerCountStrategy<C, M, B> containerCountStrategy, @Assisted String containerName) {
|
||||
this.connection = checkNotNull(connection, "connection");
|
||||
this.containerName = checkNotNull(containerName, "container");
|
||||
this.blobFactory = checkNotNull(blobFactory, "blobFactory");
|
||||
this.getAllBlobs = checkNotNull(getAllBlobs, "getAllBlobs");
|
||||
this.getAllBlobMetadata = checkNotNull(getAllBlobMetadata, "getAllBlobMetadata");
|
||||
this.containsValueStrategy = checkNotNull(containsValueStrategy, "containsValueStrategy");
|
||||
this.clearContainerStrategy = checkNotNull(clearContainerStrategy, "clearContainerStrategy");
|
||||
this.containerCountStrategy = checkNotNull(containerCountStrategy, "containerCountStrategy");
|
||||
checkArgument(!containerName.equals(""), "container name must not be a blank string!");
|
||||
}
|
||||
|
||||
|
@ -106,30 +111,7 @@ public abstract class BaseBlobMap<C extends ContainerMetadata, M extends BlobMet
|
|||
* @see BoundedSortedSet#getContents()
|
||||
*/
|
||||
public int size() {
|
||||
return getAllBlobMetadata.execute(connection, containerName).size();
|
||||
}
|
||||
|
||||
protected boolean containsETag(byte[] eTag) throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
for (BlobMetadata metadata : getAllBlobMetadata.execute(connection, containerName)) {
|
||||
if (Arrays.equals(eTag, metadata.getETag()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected byte[] getMD5(Object value) throws IOException, FileNotFoundException,
|
||||
InterruptedException, ExecutionException, TimeoutException {
|
||||
Blob<?> object;
|
||||
if (value instanceof Blob<?>) {
|
||||
object = (Blob<?>) value;
|
||||
} else {
|
||||
object = blobFactory.get();
|
||||
object.setData(value);
|
||||
}
|
||||
if (object.getMetadata().getContentMD5() == null)
|
||||
object.generateMD5();
|
||||
return object.getMetadata().getContentMD5();
|
||||
return (int) containerCountStrategy.execute(connection, containerName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -138,9 +120,7 @@ public abstract class BaseBlobMap<C extends ContainerMetadata, M extends BlobMet
|
|||
* @see BlobStore#getBlob(String, String)
|
||||
*/
|
||||
protected Set<B> getAllBlobs() {
|
||||
|
||||
return getAllBlobs.execute(connection, containerName);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -150,49 +130,11 @@ public abstract class BaseBlobMap<C extends ContainerMetadata, M extends BlobMet
|
|||
* method. To reuse data from InputStreams, pass {@link java.io.InputStream}s inside {@link Blob}s
|
||||
*/
|
||||
public boolean containsValue(Object value) {
|
||||
return eTagExistsMatchingMD5Of(value);
|
||||
}
|
||||
|
||||
private boolean eTagExistsMatchingMD5Of(Object value) {
|
||||
try {
|
||||
byte[] eTag = getMD5(value);
|
||||
return containsETag(eTag);
|
||||
} catch (Exception e) {
|
||||
Utils.<BlobRuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
throw new BlobRuntimeException(String.format(
|
||||
"Error searching for ETAG of value: [%2$s] in container:%1$s", containerName,
|
||||
value), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static class BlobRuntimeException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
BlobRuntimeException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public BlobRuntimeException(String s, Throwable throwable) {
|
||||
super(s, throwable);
|
||||
}
|
||||
return containsValueStrategy.execute(connection, containerName, value);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
Set<Future<Boolean>> deletes = Sets.newHashSet();
|
||||
for (M md : getAllBlobMetadata.execute(connection, containerName)) {
|
||||
deletes.add(connection.removeBlob(containerName, md.getKey()));
|
||||
}
|
||||
for (Future<Boolean> isdeleted : deletes) {
|
||||
try {
|
||||
if (!isdeleted.get(requestTimeoutMilliseconds, TimeUnit.MILLISECONDS)) {
|
||||
throw new BlobRuntimeException("Failed to delete blob in container: "
|
||||
+ containerName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Utils.<BlobRuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
throw new BlobRuntimeException("Error deleting blob in container: " + containerName, e);
|
||||
}
|
||||
}
|
||||
clearContainerStrategy.execute(connection, containerName);
|
||||
}
|
||||
|
||||
public Set<String> keySet() {
|
||||
|
|
|
@ -39,6 +39,9 @@ import org.jclouds.blobstore.KeyNotFoundException;
|
|||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
import org.jclouds.blobstore.strategy.ClearContainerStrategy;
|
||||
import org.jclouds.blobstore.strategy.ContainerCountStrategy;
|
||||
import org.jclouds.blobstore.strategy.ContainsValueStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetAllBlobMetadataStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
||||
import org.jclouds.util.Utils;
|
||||
|
@ -54,14 +57,18 @@ import com.google.inject.assistedinject.Assisted;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class BlobMapImpl<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
public class BlobMapImpl<C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
extends BaseBlobMap<C, M, B, B> implements BlobMap<M, B> {
|
||||
|
||||
@Inject
|
||||
public BlobMapImpl(S connection, Provider<B> blobFactory,
|
||||
public BlobMapImpl(BlobStore<C, M, B> connection, Provider<B> blobFactory,
|
||||
GetAllBlobsStrategy<C, M, B> getAllBlobs,
|
||||
GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata, @Assisted String containerName) {
|
||||
super(connection, blobFactory, getAllBlobs, getAllBlobMetadata, containerName);
|
||||
GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata,
|
||||
ContainsValueStrategy<C, M, B> containsValueStrategy,
|
||||
ClearContainerStrategy<C, M, B> clearContainerStrategy,
|
||||
ContainerCountStrategy<C, M, B> containerCountStrategy, @Assisted String containerName) {
|
||||
super(connection, blobFactory, getAllBlobs, getAllBlobMetadata, containsValueStrategy,
|
||||
clearContainerStrategy, containerCountStrategy, containerName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
*
|
||||
* 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.blobstore.internal;
|
||||
|
||||
public class BlobRuntimeException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public BlobRuntimeException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public BlobRuntimeException(String s, Throwable throwable) {
|
||||
super(s, throwable);
|
||||
}
|
||||
}
|
|
@ -42,6 +42,9 @@ import org.jclouds.blobstore.KeyNotFoundException;
|
|||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
import org.jclouds.blobstore.strategy.ClearContainerStrategy;
|
||||
import org.jclouds.blobstore.strategy.ContainerCountStrategy;
|
||||
import org.jclouds.blobstore.strategy.ContainsValueStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetAllBlobMetadataStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
||||
import org.jclouds.util.Utils;
|
||||
|
@ -59,14 +62,18 @@ import com.google.inject.assistedinject.Assisted;
|
|||
* @see InputStreamMap
|
||||
* @see BaseBlobMap
|
||||
*/
|
||||
public class InputStreamMapImpl<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
public class InputStreamMapImpl<C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
extends BaseBlobMap<C, M, B, InputStream> implements InputStreamMap<M> {
|
||||
|
||||
@Inject
|
||||
public InputStreamMapImpl(S connection, Provider<B> blobFactory,
|
||||
public InputStreamMapImpl(BlobStore<C, M, B> connection, Provider<B> blobFactory,
|
||||
GetAllBlobsStrategy<C, M, B> getAllBlobs,
|
||||
GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata, @Assisted String containerName) {
|
||||
super(connection, blobFactory, getAllBlobs, getAllBlobMetadata, containerName);
|
||||
GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata,
|
||||
ContainsValueStrategy<C, M, B> containsValueStrategy,
|
||||
ClearContainerStrategy<C, M, B> clearContainerStrategy,
|
||||
ContainerCountStrategy<C, M, B> containerCountStrategy, @Assisted String containerName) {
|
||||
super(connection, blobFactory, getAllBlobs, getAllBlobMetadata, containsValueStrategy,
|
||||
clearContainerStrategy, containerCountStrategy, containerName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
*
|
||||
* 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.blobstore.strategy;
|
||||
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
|
||||
/**
|
||||
* Clears a container
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public interface ClearContainerStrategy<C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>> {
|
||||
|
||||
void execute(BlobStore<C, M, B> connection, String containerName);
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
*
|
||||
* 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.blobstore.strategy;
|
||||
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
|
||||
/**
|
||||
* Number of objects in a container
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public interface ContainerCountStrategy<C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>> {
|
||||
|
||||
long execute(BlobStore<C, M, B> connection, String containerName);
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
*
|
||||
* 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.blobstore.strategy;
|
||||
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
|
||||
/**
|
||||
* Determines whether a value exists in the store
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public interface ContainsValueStrategy<C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>> {
|
||||
|
||||
boolean execute(BlobStore<C, M, B> connection, String containerName, Object value);
|
||||
|
||||
}
|
|
@ -33,7 +33,7 @@ import org.jclouds.blobstore.BlobStore;
|
|||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
import org.jclouds.blobstore.internal.BaseBlobMap.BlobRuntimeException;
|
||||
import org.jclouds.blobstore.internal.BlobRuntimeException;
|
||||
import org.jclouds.blobstore.reference.BlobStoreConstants;
|
||||
import org.jclouds.blobstore.strategy.GetAllBlobMetadataStrategy;
|
||||
import org.jclouds.util.Utils;
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
*
|
||||
* 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.blobstore.strategy.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
import org.jclouds.blobstore.functions.ObjectMD5;
|
||||
import org.jclouds.blobstore.internal.BlobRuntimeException;
|
||||
import org.jclouds.blobstore.strategy.ContainsValueStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetAllBlobMetadataStrategy;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
/**
|
||||
* Searches Content-MD5 tag for the value associated with the value
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ContentMD5ContainsValueStrategy<C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
implements ContainsValueStrategy<C, M, B> {
|
||||
|
||||
protected final ObjectMD5<M, B> objectMD5;
|
||||
protected final GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata;
|
||||
|
||||
@Inject
|
||||
private ContentMD5ContainsValueStrategy(ObjectMD5<M, B> objectMD5,
|
||||
GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata) {
|
||||
this.objectMD5 = objectMD5;
|
||||
this.getAllBlobMetadata = getAllBlobMetadata;
|
||||
}
|
||||
|
||||
public boolean execute(BlobStore<C, M, B> connection, String containerName, Object value) {
|
||||
try {
|
||||
byte[] toSearch = objectMD5.apply(value);
|
||||
for (BlobMetadata metadata : getAllBlobMetadata.execute(connection, containerName)) {
|
||||
if (Arrays.equals(toSearch, metadata.getContentMD5()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
Utils.<BlobRuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
throw new BlobRuntimeException(String.format(
|
||||
"Error searching for ETAG of value: [%2$s] in container:%1$s", containerName,
|
||||
value), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
*
|
||||
* 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.blobstore.strategy.internal;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
import org.jclouds.blobstore.internal.BlobRuntimeException;
|
||||
import org.jclouds.blobstore.reference.BlobStoreConstants;
|
||||
import org.jclouds.blobstore.strategy.ClearContainerStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetAllBlobMetadataStrategy;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* Deletes all keys in the container
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class DeleteAllKeysClearContainerStrategy<C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
implements ClearContainerStrategy<C, M, B> {
|
||||
/**
|
||||
* maximum duration of an blob Request
|
||||
*/
|
||||
@Inject(optional = true)
|
||||
@Named(BlobStoreConstants.PROPERTY_BLOBSTORE_TIMEOUT)
|
||||
protected long requestTimeoutMilliseconds = 30000;
|
||||
protected final GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata;
|
||||
|
||||
@Inject
|
||||
DeleteAllKeysClearContainerStrategy(GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata) {
|
||||
this.getAllBlobMetadata = getAllBlobMetadata;
|
||||
}
|
||||
|
||||
public void execute(BlobStore<C, M, B> connection, final String containerName) {
|
||||
Set<Future<Void>> deletes = Sets.newHashSet();
|
||||
for (M md : getAllBlobMetadata.execute(connection, containerName)) {
|
||||
deletes.add(connection.removeBlob(containerName, md.getKey()));
|
||||
}
|
||||
for (Future<Void> isdeleted : deletes) {
|
||||
try {
|
||||
isdeleted.get(requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
|
||||
} catch (Exception e) {
|
||||
Utils.<BlobRuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
throw new BlobRuntimeException("Error deleting blob in container: " + containerName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
*
|
||||
* 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.blobstore.strategy.internal;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
import org.jclouds.blobstore.strategy.ContainerCountStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetAllBlobMetadataStrategy;
|
||||
|
||||
/**
|
||||
* counts all blobs in the blobstore by the most efficient means possible.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class KeyCountStrategy<C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
implements ContainerCountStrategy<C, M, B> {
|
||||
protected final GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata;
|
||||
|
||||
@Inject
|
||||
KeyCountStrategy(GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata) {
|
||||
this.getAllBlobMetadata = getAllBlobMetadata;
|
||||
}
|
||||
|
||||
public long execute(BlobStore<C, M, B> connection, String container) {
|
||||
return getAllBlobMetadata.execute(connection, container).size();
|
||||
}
|
||||
|
||||
}
|
|
@ -40,7 +40,7 @@ import org.jclouds.blobstore.KeyNotFoundException;
|
|||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
import org.jclouds.blobstore.internal.BaseBlobMap.BlobRuntimeException;
|
||||
import org.jclouds.blobstore.internal.BlobRuntimeException;
|
||||
import org.jclouds.blobstore.reference.BlobStoreConstants;
|
||||
import org.jclouds.blobstore.strategy.GetAllBlobMetadataStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
||||
|
|
|
@ -32,9 +32,15 @@ import org.jclouds.blobstore.domain.ContainerMetadata;
|
|||
import org.jclouds.blobstore.integration.config.StubBlobStoreConnectionModule;
|
||||
import org.jclouds.blobstore.internal.BlobMapImpl;
|
||||
import org.jclouds.blobstore.internal.InputStreamMapImpl;
|
||||
import org.jclouds.blobstore.strategy.ClearContainerStrategy;
|
||||
import org.jclouds.blobstore.strategy.ContainerCountStrategy;
|
||||
import org.jclouds.blobstore.strategy.ContainsValueStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetAllBlobMetadataStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
||||
import org.jclouds.blobstore.strategy.internal.ContainerListGetAllBlobMetadataStrategy;
|
||||
import org.jclouds.blobstore.strategy.internal.ContentMD5ContainsValueStrategy;
|
||||
import org.jclouds.blobstore.strategy.internal.DeleteAllKeysClearContainerStrategy;
|
||||
import org.jclouds.blobstore.strategy.internal.KeyCountStrategy;
|
||||
import org.jclouds.blobstore.strategy.internal.RetryOnNotFoundGetAllBlobsStrategy;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
|
@ -48,51 +54,58 @@ public class BlobStoreMapsModuleTest {
|
|||
|
||||
public void testBuilderBuild() {
|
||||
BlobStoreMapsModule module = BlobStoreMapsModule.Builder.newBuilder(
|
||||
new TypeLiteral<BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
}, new TypeLiteral<ContainerMetadata>() {
|
||||
new TypeLiteral<ContainerMetadata>() {
|
||||
}, new TypeLiteral<BlobMetadata>() {
|
||||
}, new TypeLiteral<Blob<BlobMetadata>>() {
|
||||
}).build();
|
||||
assertEquals(module.blobMapFactoryType,
|
||||
new TypeLiteral<BlobMap.Factory<BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
});
|
||||
assertEquals(
|
||||
module.blobMapImplType,
|
||||
new TypeLiteral<BlobMapImpl<BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>, ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
assertEquals(module.blobMapImplType,
|
||||
new TypeLiteral<BlobMapImpl<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
});
|
||||
assertEquals(module.inputStreamMapFactoryType,
|
||||
new TypeLiteral<InputStreamMap.Factory<BlobMetadata>>() {
|
||||
});
|
||||
assertEquals(
|
||||
module.inputStreamMapImplType,
|
||||
new TypeLiteral<InputStreamMapImpl<BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>, ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
new TypeLiteral<InputStreamMapImpl<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
});
|
||||
assertEquals(
|
||||
module.getAllBlobsStrategyType,
|
||||
new TypeLiteral<GetAllBlobsStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
});
|
||||
assertEquals(
|
||||
module.getAllBlobsStrategyImplType,
|
||||
module.strategyImplMap
|
||||
.get(new TypeLiteral<GetAllBlobsStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
}),
|
||||
new TypeLiteral<RetryOnNotFoundGetAllBlobsStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
});
|
||||
assertEquals(
|
||||
module.getAllBlobMetadataStrategyType,
|
||||
new TypeLiteral<GetAllBlobMetadataStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
module.strategyImplMap
|
||||
.get(new TypeLiteral<GetAllBlobMetadataStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
}),
|
||||
new TypeLiteral<ContainerListGetAllBlobMetadataStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
});
|
||||
assertEquals(
|
||||
module.getAllBlobMetadataStrategyImplType,
|
||||
new TypeLiteral<ContainerListGetAllBlobMetadataStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
module.strategyImplMap
|
||||
.get(new TypeLiteral<ContainsValueStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
}),
|
||||
new TypeLiteral<ContentMD5ContainsValueStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
});
|
||||
assertEquals(
|
||||
module.strategyImplMap
|
||||
.get(new TypeLiteral<ClearContainerStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
}),
|
||||
new TypeLiteral<DeleteAllKeysClearContainerStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
});
|
||||
assertEquals(
|
||||
module.strategyImplMap
|
||||
.get(new TypeLiteral<ContainerCountStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
}),
|
||||
new TypeLiteral<KeyCountStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
});
|
||||
}
|
||||
|
||||
public void testInject() {
|
||||
Injector i = Guice
|
||||
.createInjector(
|
||||
new StubBlobStoreConnectionModule(),
|
||||
BlobStoreMapsModule.Builder
|
||||
.newBuilder(
|
||||
new TypeLiteral<BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||
}, new TypeLiteral<ContainerMetadata>() {
|
||||
Injector i = Guice.createInjector(new StubBlobStoreConnectionModule(),
|
||||
BlobStoreMapsModule.Builder.newBuilder(new TypeLiteral<ContainerMetadata>() {
|
||||
}, new TypeLiteral<BlobMetadata>() {
|
||||
}, new TypeLiteral<Blob<BlobMetadata>>() {
|
||||
}).build());
|
||||
|
|
|
@ -79,7 +79,7 @@ public class StubBlobStoreContextBuilder
|
|||
Provider<Blob<BlobMetadata>> blobProvider,
|
||||
BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>> api) {
|
||||
return new BlobStoreContextImpl<BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>, ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>(
|
||||
blobMapFactory, inputStreamMapFactory, closer, blobProvider, api, URI
|
||||
blobMapFactory, inputStreamMapFactory, closer, blobProvider, api, api, URI
|
||||
.create("http://localhost/blobstub"), "foo");
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.ContainerNotFoundException;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
|
@ -59,7 +58,7 @@ import org.testng.annotations.Test;
|
|||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
public class BaseBlobIntegrationTest<S, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
extends BaseBlobStoreIntegrationTest<S, C, M, B> {
|
||||
|
||||
@Test(groups = { "integration", "live" })
|
||||
|
@ -76,12 +75,12 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
|||
addObjectAndValidateContent(containerName, key);
|
||||
DateTime after = new DateTime().plusSeconds(1);
|
||||
|
||||
context.getApi().getBlob(containerName, key, ifModifiedSince(before)).get(10,
|
||||
context.getBlobStore().getBlob(containerName, key, ifModifiedSince(before)).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
validateContent(containerName, key);
|
||||
|
||||
try {
|
||||
context.getApi().getBlob(containerName, key, ifModifiedSince(after)).get(10,
|
||||
context.getBlobStore().getBlob(containerName, key, ifModifiedSince(after)).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
validateContent(containerName, key);
|
||||
} catch (ExecutionException e) {
|
||||
|
@ -112,12 +111,12 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
|||
addObjectAndValidateContent(containerName, key);
|
||||
DateTime after = new DateTime().plusSeconds(1);
|
||||
|
||||
context.getApi().getBlob(containerName, key, ifUnmodifiedSince(after)).get(10,
|
||||
context.getBlobStore().getBlob(containerName, key, ifUnmodifiedSince(after)).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
validateContent(containerName, key);
|
||||
|
||||
try {
|
||||
context.getApi().getBlob(containerName, key, ifUnmodifiedSince(before)).get(10,
|
||||
context.getBlobStore().getBlob(containerName, key, ifUnmodifiedSince(before)).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
validateContent(containerName, key);
|
||||
} catch (ExecutionException e) {
|
||||
|
@ -145,12 +144,12 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
|||
|
||||
addObjectAndValidateContent(containerName, key);
|
||||
|
||||
context.getApi().getBlob(containerName, key, ifETagMatches(goodETag)).get(10,
|
||||
context.getBlobStore().getBlob(containerName, key, ifETagMatches(goodETag)).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
validateContent(containerName, key);
|
||||
|
||||
try {
|
||||
context.getApi().getBlob(containerName, key, ifETagMatches(badETag)).get(10,
|
||||
context.getBlobStore().getBlob(containerName, key, ifETagMatches(badETag)).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
validateContent(containerName, key);
|
||||
} catch (ExecutionException e) {
|
||||
|
@ -178,12 +177,12 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
|||
|
||||
addObjectAndValidateContent(containerName, key);
|
||||
|
||||
context.getApi().getBlob(containerName, key, ifETagDoesntMatch(badETag)).get(10,
|
||||
context.getBlobStore().getBlob(containerName, key, ifETagDoesntMatch(badETag)).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
validateContent(containerName, key);
|
||||
|
||||
try {
|
||||
context.getApi().getBlob(containerName, key, ifETagDoesntMatch(goodETag)).get(10,
|
||||
context.getBlobStore().getBlob(containerName, key, ifETagDoesntMatch(goodETag)).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
validateContent(containerName, key);
|
||||
} catch (ExecutionException e) {
|
||||
|
@ -208,13 +207,13 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
|||
String key = "apples";
|
||||
|
||||
addObjectAndValidateContent(containerName, key);
|
||||
B object1 = context.getApi().getBlob(containerName, key, range(0, 5)).get(10,
|
||||
B object1 = context.getBlobStore().getBlob(containerName, key, range(0, 5)).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
assertEquals(BlobStoreUtils.getContentAsStringAndClose(object1), TEST_STRING.substring(0,
|
||||
6));
|
||||
|
||||
B object2 = context.getApi().getBlob(containerName, key, range(6, TEST_STRING.length()))
|
||||
.get(10, TimeUnit.SECONDS);
|
||||
B object2 = context.getBlobStore().getBlob(containerName, key,
|
||||
range(6, TEST_STRING.length())).get(10, TimeUnit.SECONDS);
|
||||
assertEquals(BlobStoreUtils.getContentAsStringAndClose(object2), TEST_STRING.substring(6,
|
||||
TEST_STRING.length()));
|
||||
} finally {
|
||||
|
@ -231,7 +230,7 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
|||
String key = "apples";
|
||||
|
||||
addObjectAndValidateContent(containerName, key);
|
||||
B object = context.getApi().getBlob(containerName, key,
|
||||
B object = context.getBlobStore().getBlob(containerName, key,
|
||||
range(0, 5).range(6, TEST_STRING.length())).get(10, TimeUnit.SECONDS);
|
||||
|
||||
assertEquals(BlobStoreUtils.getContentAsStringAndClose(object), TEST_STRING);
|
||||
|
@ -249,7 +248,8 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
|||
String key = "apples";
|
||||
|
||||
addObjectAndValidateContent(containerName, key);
|
||||
B object = context.getApi().getBlob(containerName, key, tail(5)).get(10, TimeUnit.SECONDS);
|
||||
B object = context.getBlobStore().getBlob(containerName, key, tail(5)).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
assertEquals(BlobStoreUtils.getContentAsStringAndClose(object), TEST_STRING
|
||||
.substring(TEST_STRING.length() - 5));
|
||||
assertEquals(object.getContentLength(), 5);
|
||||
|
@ -267,7 +267,7 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
|||
String key = "apples";
|
||||
|
||||
addObjectAndValidateContent(containerName, key);
|
||||
B object = context.getApi().getBlob(containerName, key, startAt(5)).get(10,
|
||||
B object = context.getBlobStore().getBlob(containerName, key, startAt(5)).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
assertEquals(BlobStoreUtils.getContentAsStringAndClose(object), TEST_STRING.substring(5,
|
||||
TEST_STRING.length()));
|
||||
|
@ -289,7 +289,7 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
|||
String containerName = getContainerName();
|
||||
String key = "test";
|
||||
try {
|
||||
assert context.getApi().removeBlob(containerName, key).get(10, TimeUnit.SECONDS);
|
||||
context.getBlobStore().removeBlob(containerName, key).get(10, TimeUnit.SECONDS);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
@ -305,7 +305,7 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
|||
String containerName = getContainerName();
|
||||
try {
|
||||
addBlobToContainer(containerName, key);
|
||||
assert context.getApi().removeBlob(containerName, key).get(10, TimeUnit.SECONDS);
|
||||
context.getBlobStore().removeBlob(containerName, key).get(10, TimeUnit.SECONDS);
|
||||
assertContainerEmptyDeleting(containerName, key);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
|
@ -314,7 +314,8 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
|||
|
||||
private void assertContainerEmptyDeleting(String containerName, String key)
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
SortedSet<M> listing = context.getApi().listBlobs(containerName).get(10, TimeUnit.SECONDS);
|
||||
SortedSet<M> listing = context.getBlobStore().listBlobs(containerName).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
assertEquals(listing.size(), 0, String.format(
|
||||
"deleting %s, we still have %s left in container %s, using encoding %s", key,
|
||||
listing.size(), containerName, LOCAL_ENCODING));
|
||||
|
@ -323,7 +324,7 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
|||
@Test(groups = { "integration", "live" })
|
||||
public void deleteObjectNoContainer() throws Exception {
|
||||
try {
|
||||
context.getApi().removeBlob("donb", "test").get(10, TimeUnit.SECONDS);
|
||||
context.getBlobStore().removeBlob("donb", "test").get(10, TimeUnit.SECONDS);
|
||||
} catch (ExecutionException e) {
|
||||
assert (e.getCause() instanceof HttpResponseException || e.getCause() instanceof ContainerNotFoundException);
|
||||
if (e.getCause() instanceof HttpResponseException)
|
||||
|
@ -352,12 +353,14 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
|||
}
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
assertNotNull(context.getApi().putBlob(containerName, object).get(10, TimeUnit.SECONDS));
|
||||
object = context.getApi().getBlob(containerName, object.getKey())
|
||||
.get(10, TimeUnit.SECONDS);
|
||||
assertNotNull(context.getBlobStore().putBlob(containerName, object).get(10,
|
||||
TimeUnit.SECONDS));
|
||||
object = context.getBlobStore().getBlob(containerName, object.getKey()).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
String returnedString = BlobStoreUtils.getContentAsStringAndClose(object);
|
||||
assertEquals(returnedString, realObject);
|
||||
assertEquals(context.getApi().listBlobs(containerName).get(10, TimeUnit.SECONDS).size(), 1);
|
||||
assertEquals(context.getBlobStore().listBlobs(containerName).get(10, TimeUnit.SECONDS)
|
||||
.size(), 1);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
@ -383,7 +386,7 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
|||
M metadata = newObject.getMetadata();
|
||||
|
||||
validateMetadata(metadata);
|
||||
validateMetadata(context.getApi().blobMetadata(containerName, key));
|
||||
validateMetadata(context.getBlobStore().blobMetadata(containerName, key));
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ import java.net.URL;
|
|||
import java.net.URLConnection;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
|
@ -48,7 +47,7 @@ import org.testng.annotations.Test;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = { "live" }, testName = "blobstore.BlobLiveTest")
|
||||
public class BaseBlobLiveTest<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
public class BaseBlobLiveTest<S, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
extends BaseBlobStoreIntegrationTest<S, C, M, B> {
|
||||
|
||||
private static final String sysHttpStreamUrl = System
|
||||
|
@ -82,8 +81,8 @@ public class BaseBlobLiveTest<S extends BlobStore<C, M, B>, C extends ContainerM
|
|||
object.getMetadata().setSize(length);
|
||||
String bucketName = getContainerName();
|
||||
try {
|
||||
context.getApi().putBlob(bucketName, object).get(180, TimeUnit.SECONDS);
|
||||
assertEquals(context.getApi().blobMetadata(bucketName, key).getContentMD5(), md5);
|
||||
context.getBlobStore().putBlob(bucketName, object).get(180, TimeUnit.SECONDS);
|
||||
assertEquals(context.getBlobStore().blobMetadata(bucketName, key).getContentMD5(), md5);
|
||||
} finally {
|
||||
returnContainer(bucketName);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ import java.util.concurrent.ExecutionException;
|
|||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.BlobStoreContext;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
|
@ -50,7 +49,7 @@ import org.testng.annotations.Test;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class BaseBlobMapIntegrationTest<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
public class BaseBlobMapIntegrationTest<S, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
extends BaseMapIntegrationTest<S, C, M, B, B> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,8 +27,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
|
@ -41,13 +39,11 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.BlobStoreContext;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
import org.jclouds.blobstore.util.BlobStoreUtils;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
||||
import org.jclouds.util.Utils;
|
||||
|
@ -62,7 +58,7 @@ import com.google.common.collect.Iterables;
|
|||
import com.google.common.collect.Sets;
|
||||
import com.google.inject.Module;
|
||||
|
||||
public class BaseBlobStoreIntegrationTest<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>> {
|
||||
public class BaseBlobStoreIntegrationTest<S, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>> {
|
||||
protected static final String LOCAL_ENCODING = System.getProperty("file.encoding");
|
||||
protected static final String TEST_STRING = "<apples><apple name=\"fuji\"></apple> </apples>";
|
||||
|
||||
|
@ -110,10 +106,10 @@ public class BaseBlobStoreIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
|||
protected ExecutorService exec;
|
||||
|
||||
/**
|
||||
* we are doing this at a class level, as the context.getApi() object is going to be shared for
|
||||
* all methods in the class. We don't want to do this for group, as some test classes may want to
|
||||
* have a different implementation of context.getApi(). For example, one class may want
|
||||
* non-blocking i/o and another class google appengine.
|
||||
* we are doing this at a class level, as the context.getBlobStore() object is going to be shared
|
||||
* for all methods in the class. We don't want to do this for group, as some test classes may
|
||||
* want to have a different implementation of context.getBlobStore(). For example, one class may
|
||||
* want non-blocking i/o and another class google appengine.
|
||||
*/
|
||||
@BeforeClass(groups = { "integration", "live" })
|
||||
public void setUpResourcesOnThisThread(ITestContext testContext) throws Exception {
|
||||
|
@ -182,7 +178,7 @@ public class BaseBlobStoreIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
|||
try {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Iterable<ContainerMetadata> testContainers = Iterables.filter(
|
||||
(SortedSet<ContainerMetadata>) context.getApi().listContainers(),
|
||||
(SortedSet<ContainerMetadata>) context.getBlobStore().listContainers(),
|
||||
new Predicate<ContainerMetadata>() {
|
||||
public boolean apply(ContainerMetadata input) {
|
||||
return input.getName().startsWith(CONTAINER_PREFIX.toLowerCase());
|
||||
|
@ -234,42 +230,8 @@ public class BaseBlobStoreIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
|||
protected static void createContainerAndEnsureEmpty(BlobStoreContext<?, ?, ?, ?> context,
|
||||
final String containerName) throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
attemptToCreateContainerButRetryOn409(context, containerName);
|
||||
emptyContainer(context, containerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 409 could be a resolvable conflict, ex. container delete in progress. FIXME Comment this
|
||||
*
|
||||
* @param context
|
||||
* .getApi()
|
||||
* @param containerName
|
||||
* @throws InterruptedException
|
||||
* @throws TimeoutException
|
||||
* @throws ExecutionException
|
||||
*/
|
||||
private static void attemptToCreateContainerButRetryOn409(
|
||||
BlobStoreContext<? extends BlobStore<?, ?, ?>, ?, ?, ?> context,
|
||||
final String containerName) throws InterruptedException, TimeoutException,
|
||||
ExecutionException {
|
||||
ExecutionException error = null;
|
||||
OUTER: for (int i = 0; i < 10; i++) {
|
||||
try {
|
||||
context.getApi().createContainer(containerName).get(10, TimeUnit.SECONDS);
|
||||
break OUTER;
|
||||
} catch (ExecutionException e) {
|
||||
error = e;
|
||||
if (e.getCause() instanceof HttpResponseException) {
|
||||
HttpResponseException ex = (HttpResponseException) e.getCause();
|
||||
if (ex.getResponse().getStatusCode() != 409) {
|
||||
break OUTER;
|
||||
}
|
||||
}
|
||||
}
|
||||
Thread.sleep(INCONSISTENCY_WINDOW / 10);
|
||||
}
|
||||
if (error != null)
|
||||
throw error;
|
||||
context.getBlobStore().createContainer(containerName).get(30, TimeUnit.SECONDS);
|
||||
context.createInputStreamMap(containerName).clear();
|
||||
}
|
||||
|
||||
protected void createContainerAndEnsureEmpty(String containerName) throws InterruptedException,
|
||||
|
@ -287,13 +249,13 @@ public class BaseBlobStoreIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
|||
|
||||
protected void addBlobToContainer(String sourceContainer, B object) throws InterruptedException,
|
||||
ExecutionException, TimeoutException, IOException {
|
||||
context.getApi().putBlob(sourceContainer, object).get(10, TimeUnit.SECONDS);
|
||||
context.getBlobStore().putBlob(sourceContainer, object).get(10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
protected B validateContent(String sourceContainer, String key) throws InterruptedException,
|
||||
ExecutionException, TimeoutException, IOException {
|
||||
assertEventuallyContainerSize(sourceContainer, 1);
|
||||
B newObject = context.getApi().getBlob(sourceContainer, key).get(10, TimeUnit.SECONDS);
|
||||
B newObject = context.getBlobStore().getBlob(sourceContainer, key).get(10, TimeUnit.SECONDS);
|
||||
assert newObject != null;
|
||||
assertEquals(BlobStoreUtils.getContentAsStringAndClose(newObject), TEST_STRING);
|
||||
return newObject;
|
||||
|
@ -304,8 +266,8 @@ public class BaseBlobStoreIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
|||
assertEventually(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
assertEquals(context.getApi().listBlobs(containerName).get(10, TimeUnit.SECONDS)
|
||||
.size(), count);
|
||||
assertEquals(context.getBlobStore().listBlobs(containerName).get(10,
|
||||
TimeUnit.SECONDS).size(), count);
|
||||
} catch (Exception e) {
|
||||
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
}
|
||||
|
@ -317,8 +279,7 @@ public class BaseBlobStoreIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
|||
TimeoutException {
|
||||
String containerName = containerJsr330.poll(30, TimeUnit.SECONDS);
|
||||
assert containerName != null : "unable to get a container for the test";
|
||||
if (!emptyContainer(containerName))
|
||||
this.createContainerAndEnsureEmpty(containerName);
|
||||
createContainerAndEnsureEmpty(containerName);
|
||||
return containerName;
|
||||
}
|
||||
|
||||
|
@ -345,7 +306,7 @@ public class BaseBlobStoreIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
|||
* *substantially* slow down tests on a real server over a network.
|
||||
*/
|
||||
if (SANITY_CHECK_RETURNED_BUCKET_NAME) {
|
||||
if (!Iterables.any(context.getApi().listContainers(),
|
||||
if (!Iterables.any(context.getBlobStore().listContainers(),
|
||||
new Predicate<ContainerMetadata>() {
|
||||
public boolean apply(ContainerMetadata md) {
|
||||
return containerName.equals(md.getName());
|
||||
|
@ -396,60 +357,15 @@ public class BaseBlobStoreIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
|||
return new JavaUrlHttpCommandExecutorServiceModule();
|
||||
}
|
||||
|
||||
protected boolean emptyContainer(String name) throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
return emptyContainer(context, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any objects in a container, leaving it empty.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected static boolean emptyContainer(final BlobStoreContext<?, ?, ?, ?> context,
|
||||
protected static void deleteContainer(final BlobStoreContext<?, ?, ?, ?> context,
|
||||
final String name) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
if (context.getApi().containerExists(name)) {
|
||||
// This can fail to be zero length because of stale container lists. Ex.
|
||||
// context.getApi().listContainer()
|
||||
// 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 container deletion
|
||||
// operation multiple times to ensure we can acheive a zero length container.
|
||||
assertEventually(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
Map<String, InputStream> map = context.createInputStreamMap(name);
|
||||
Set<String> keys = map.keySet();
|
||||
if (keys.size() > 0) {
|
||||
map.clear();
|
||||
assertEquals(
|
||||
map.size(),
|
||||
0,
|
||||
String
|
||||
.format(
|
||||
"deleting %s, we still have %s left in container %s, using encoding %s",
|
||||
keys, map.keySet(), name, LOCAL_ENCODING));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static void deleteContainer(
|
||||
final BlobStoreContext<? extends BlobStore<?, ?, ?>, ?, ?, ?> context, final String name)
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
if (context.getApi().containerExists(name)) {
|
||||
if (context.getBlobStore().containerExists(name)) {
|
||||
System.err.printf("*** deleting container %s...%n", name);
|
||||
emptyContainer(context, name);
|
||||
context.getApi().deleteContainer(name).get(10, TimeUnit.SECONDS);
|
||||
context.getBlobStore().deleteContainer(name).get(10, TimeUnit.SECONDS);
|
||||
assertEventually(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
assert !context.getApi().containerExists(name) : "container " + name
|
||||
assert !context.getBlobStore().containerExists(name) : "container " + name
|
||||
+ " still exists";
|
||||
} catch (Exception e) {
|
||||
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
|
|
|
@ -31,7 +31,6 @@ import java.util.concurrent.ExecutionException;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
|
@ -41,20 +40,20 @@ import org.testng.annotations.Test;
|
|||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class BaseContainerIntegrationTest<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
public class BaseContainerIntegrationTest<S, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
extends BaseBlobStoreIntegrationTest<S, C, M, B> {
|
||||
|
||||
@Test(groups = { "integration", "live" })
|
||||
public void containerDoesntExist() throws Exception {
|
||||
assert !context.getApi().containerExists("forgetaboutit");
|
||||
assert !context.getBlobStore().containerExists("forgetaboutit");
|
||||
}
|
||||
|
||||
@Test(groups = { "integration", "live" })
|
||||
public void testPutTwiceIsOk() throws Exception {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
context.getApi().createContainer(containerName).get(10, TimeUnit.SECONDS);
|
||||
context.getApi().createContainer(containerName).get(10, TimeUnit.SECONDS);
|
||||
context.getBlobStore().createContainer(containerName).get(10, TimeUnit.SECONDS);
|
||||
context.getBlobStore().createContainer(containerName).get(10, TimeUnit.SECONDS);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
|
@ -64,28 +63,21 @@ public class BaseContainerIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
|||
public void containerExists() throws Exception {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
assert context.getApi().containerExists(containerName);
|
||||
assert context.getBlobStore().containerExists(containerName);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this method overrides containerName to ensure it isn't found
|
||||
*/
|
||||
@Test(groups = { "integration", "live" })
|
||||
public void deleteContainerIfEmptyNotFound() throws Exception {
|
||||
assert context.getApi().deleteContainer("dbienf").get(10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Test(groups = { "integration", "live" })
|
||||
public void deleteContainerIfEmptyButHasContents() throws Exception {
|
||||
public void deleteContainerWithContents() throws Exception {
|
||||
String containerName = getContainerName();
|
||||
try {
|
||||
addBlobToContainer(containerName, "test");
|
||||
assert !context.getApi().deleteContainer(containerName).get(10, TimeUnit.SECONDS);
|
||||
context.getBlobStore().deleteContainer(containerName).get(10, TimeUnit.SECONDS);
|
||||
assertNotExists(containerName);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
recycleContainer(containerName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,32 +85,26 @@ public class BaseContainerIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
|||
public void deleteContainerIfEmpty() throws Exception {
|
||||
final String containerName = getContainerName();
|
||||
try {
|
||||
assert context.getApi().deleteContainer(containerName).get(10, TimeUnit.SECONDS);
|
||||
|
||||
assertEventually(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
assert !context.getApi().containerExists(containerName) : "container "
|
||||
+ containerName + " still exists";
|
||||
} catch (Exception e) {
|
||||
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
context.getBlobStore().deleteContainer(containerName).get(10, TimeUnit.SECONDS);
|
||||
assertNotExists(containerName);
|
||||
} finally {
|
||||
// this container is now deleted, so we can't reuse it directly
|
||||
recycleContainer(containerName);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addAlphabetUnderRoot(String containerName) throws InterruptedException,
|
||||
ExecutionException, TimeoutException {
|
||||
for (char letter = 'a'; letter <= 'z'; letter++) {
|
||||
B blob = context.newBlob(letter + "");
|
||||
blob.setData(letter + "content");
|
||||
context.getApi().putBlob(containerName, blob).get(10, TimeUnit.SECONDS);
|
||||
private void assertNotExists(final String containerName) throws InterruptedException {
|
||||
assertEventually(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
assert !context.getBlobStore().containerExists(containerName) : "container "
|
||||
+ containerName + " still exists";
|
||||
} catch (Exception e) {
|
||||
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test(groups = { "integration", "live" })
|
||||
public void testListContainer() throws InterruptedException, ExecutionException,
|
||||
|
@ -126,7 +112,7 @@ public class BaseContainerIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
|||
String containerName = getContainerName();
|
||||
try {
|
||||
add15UnderRoot(containerName);
|
||||
SortedSet<M> container = context.getApi().listBlobs(containerName).get(10,
|
||||
SortedSet<M> container = context.getBlobStore().listBlobs(containerName).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
assertEquals(container.size(), 15);
|
||||
} finally {
|
||||
|
@ -135,12 +121,21 @@ public class BaseContainerIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
|||
|
||||
}
|
||||
|
||||
protected void addAlphabetUnderRoot(String containerName) throws InterruptedException,
|
||||
ExecutionException, TimeoutException {
|
||||
for (char letter = 'a'; letter <= 'z'; letter++) {
|
||||
B blob = context.newBlob(letter + "");
|
||||
blob.setData(letter + "content");
|
||||
context.getBlobStore().putBlob(containerName, blob).get(10, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
protected void add15UnderRoot(String containerName) throws InterruptedException,
|
||||
ExecutionException, TimeoutException {
|
||||
for (int i = 0; i < 15; i++) {
|
||||
B blob = context.newBlob(i + "");
|
||||
blob.setData(i + "content");
|
||||
context.getApi().putBlob(containerName, blob).get(10, TimeUnit.SECONDS);
|
||||
context.getBlobStore().putBlob(containerName, blob).get(10, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,7 +144,7 @@ public class BaseContainerIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
|||
for (int i = 0; i < 10; i++) {
|
||||
B blob = context.newBlob(prefix + "/" + i);
|
||||
blob.setData(i + "content");
|
||||
context.getApi().putBlob(containerName, blob).get(10, TimeUnit.SECONDS);
|
||||
context.getBlobStore().putBlob(containerName, blob).get(10, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,6 @@
|
|||
*/
|
||||
package org.jclouds.blobstore.integration.internal;
|
||||
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
|
@ -32,7 +31,7 @@ import org.jclouds.blobstore.domain.ContainerMetadata;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class BaseContainerLiveTest<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
public class BaseContainerLiveTest<S, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
extends BaseBlobStoreIntegrationTest<S, C, M, B> {
|
||||
|
||||
}
|
|
@ -37,7 +37,6 @@ import java.util.concurrent.ExecutionException;
|
|||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.BlobStoreContext;
|
||||
import org.jclouds.blobstore.InputStreamMap;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
|
@ -51,7 +50,7 @@ import org.testng.annotations.Test;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class BaseInputStreamMapIntegrationTest<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
public class BaseInputStreamMapIntegrationTest<S, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
extends BaseMapIntegrationTest<S, C, M, B, InputStream> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -37,7 +37,6 @@ import java.util.concurrent.ExecutionException;
|
|||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.BlobStoreContext;
|
||||
import org.jclouds.blobstore.ListableMap;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
|
@ -51,7 +50,7 @@ import org.testng.annotations.Test;
|
|||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
public abstract class BaseMapIntegrationTest<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>, V>
|
||||
public abstract class BaseMapIntegrationTest<S, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>, V>
|
||||
extends BaseBlobStoreIntegrationTest<S, C, M, B> {
|
||||
|
||||
public abstract void testPutAll() throws InterruptedException, ExecutionException,
|
||||
|
|
|
@ -25,7 +25,6 @@ package org.jclouds.blobstore.integration.internal;
|
|||
|
||||
import java.util.SortedSet;
|
||||
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||
|
@ -35,12 +34,12 @@ import org.testng.annotations.Test;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class BaseServiceIntegrationTest<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
public class BaseServiceIntegrationTest<S, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
|
||||
extends BaseBlobStoreIntegrationTest<S, C, M, B> {
|
||||
|
||||
@Test(groups = { "integration", "live" })
|
||||
void containerDoesntExist() throws Exception {
|
||||
SortedSet<C> list = context.getApi().listContainers();
|
||||
SortedSet<C> list = context.getBlobStore().listContainers();
|
||||
assert !list.contains(new ContainerMetadata("shouldntexist"));
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
*/
|
||||
package org.jclouds.blobstore.integration.internal;
|
||||
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.BlobStoreContext;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
|
@ -32,7 +31,7 @@ import org.testng.ITestContext;
|
|||
|
||||
import com.google.inject.Module;
|
||||
|
||||
public abstract class BaseTestInitializer<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>> {
|
||||
public abstract class BaseTestInitializer<S, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>> {
|
||||
|
||||
public BlobStoreContext<S, C, M, B> init(Module configurationModule, ITestContext testContext)
|
||||
throws Exception {
|
||||
|
|
|
@ -199,18 +199,29 @@ public class StubBlobStore<C extends ContainerMetadata, M extends BlobMetadata,
|
|||
return realContents.get(key).getMetadata();
|
||||
}
|
||||
|
||||
public Future<Boolean> removeBlob(final String container, final String key) {
|
||||
return new FutureBase<Boolean>() {
|
||||
public Boolean get() throws InterruptedException, ExecutionException {
|
||||
public Future<Void> removeBlob(final String container, final String key) {
|
||||
return new FutureBase<Void>() {
|
||||
public Void get() throws InterruptedException, ExecutionException {
|
||||
if (getContainerToBlobs().containsKey(container)) {
|
||||
getContainerToBlobs().get(container).remove(key);
|
||||
}
|
||||
return true;
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Future<Boolean> deleteContainer(final String container) {
|
||||
public Future<Void> deleteContainer(final String container) {
|
||||
return new FutureBase<Void>() {
|
||||
public Void get() throws InterruptedException, ExecutionException {
|
||||
if (getContainerToBlobs().containsKey(container)) {
|
||||
getContainerToBlobs().remove(container);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Future<Boolean> deleteContainerImpl(final String container) {
|
||||
return new FutureBase<Boolean>() {
|
||||
public Boolean get() throws InterruptedException, ExecutionException {
|
||||
if (getContainerToBlobs().containsKey(container)) {
|
||||
|
@ -385,6 +396,7 @@ public class StubBlobStore<C extends ContainerMetadata, M extends BlobMetadata,
|
|||
byte[] data = toByteArray(object.getData());
|
||||
final byte[] eTag = HttpUtils.md5(data);
|
||||
newMd.setETag(eTag);
|
||||
newMd.setContentMD5(eTag);
|
||||
newMd.setContentType(object.getMetadata().getContentType());
|
||||
|
||||
B blob = blobProvider.get();
|
||||
|
|
|
@ -52,13 +52,13 @@ public class BaseBlobMapTest {
|
|||
|
||||
BlobStoreContext<BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>, ContainerMetadata, BlobMetadata, Blob<BlobMetadata>> context;
|
||||
|
||||
InputStreamMapImpl<BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>, ContainerMetadata, BlobMetadata, Blob<BlobMetadata>> map;
|
||||
InputStreamMapImpl<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>> map;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@BeforeClass
|
||||
void addDefaultObjectsSoThatTestsWillPass() {
|
||||
context = new StubBlobStoreContextBuilder().buildContext();
|
||||
map = (InputStreamMapImpl<BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>, ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>) context
|
||||
map = (InputStreamMapImpl<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>) context
|
||||
.createInputStreamMap("test");
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
*
|
||||
* 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.http.functions;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.rest.RestContext;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ParseContentMD5FromHeaders implements Function<HttpResponse, byte[]>, RestContext {
|
||||
|
||||
public static class NoContentMD5Exception extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final HttpRequest request;
|
||||
private final HttpResponse response;
|
||||
|
||||
public NoContentMD5Exception(HttpRequest request, HttpResponse response) {
|
||||
super(String.format("no MD5 returned from request: %s; response %s", request, response));
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public HttpRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public HttpResponse getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
private Object[] args;
|
||||
private HttpRequest request;
|
||||
|
||||
public byte[] apply(HttpResponse from) {
|
||||
IOUtils.closeQuietly(from.getContent());
|
||||
String contentMD5 = from.getFirstHeaderOrNull("Content-MD5");
|
||||
if (contentMD5 != null) {
|
||||
return HttpUtils.fromBase64String(contentMD5);
|
||||
}
|
||||
throw new NoContentMD5Exception(request, from);
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public HttpRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public void setContext(HttpRequest request, Object[] args) {
|
||||
this.request = request;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
*
|
||||
* 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.http.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* parses a single URI from a list
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ParseURIList implements Function<HttpResponse, URI> {
|
||||
public URI apply(HttpResponse from) {
|
||||
try {
|
||||
checkState("text/uri-list".equals(from.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE)),
|
||||
"response should have content type test/uri-list");
|
||||
|
||||
String toParse = Utils.toStringAndClose(from.getContent());
|
||||
return URI.create(toParse.trim());
|
||||
} catch (IOException e) {
|
||||
throw new HttpResponseException("couldn't parse url from response", null, from, e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,23 +21,22 @@
|
|||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.mezeo.pcs2.functions;
|
||||
package org.jclouds.http.functions;
|
||||
|
||||
import org.jclouds.blobstore.ContainerNotFoundException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.jclouds.http.HttpResponse;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* Simply returns the InputStream of the response
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ReturnTrueIfContainerNotFound implements Function<Exception, Boolean> {
|
||||
public class ReturnInputStream implements Function<HttpResponse, InputStream> {
|
||||
|
||||
public Boolean apply(Exception from) {
|
||||
if (from instanceof ContainerNotFoundException) {
|
||||
return true;
|
||||
public InputStream apply(HttpResponse from) {
|
||||
return from.getContent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
*
|
||||
* 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.http.functions;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* Simply returns true when the http response code is in the range 200-299.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ReturnVoidIf2xx implements Function<HttpResponse, Void> {
|
||||
static final Void v;
|
||||
static {
|
||||
Constructor<Void> cv;
|
||||
try {
|
||||
cv = Void.class.getDeclaredConstructor();
|
||||
cv.setAccessible(true);
|
||||
v = cv.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new Error("Error setting up class", e);
|
||||
}
|
||||
}
|
||||
|
||||
public Void apply(HttpResponse from) {
|
||||
IOUtils.closeQuietly(from.getContent());
|
||||
int code = from.getStatusCode();
|
||||
if (code >= 300 || code < 200) {
|
||||
throw new IllegalStateException("incorrect code for this operation: " + from);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
|
@ -103,7 +103,12 @@ public class BackoffLimitedRetryHandler implements HttpRetryHandler {
|
|||
}
|
||||
|
||||
public void imposeBackoffExponentialDelay(int failureCount, String commandDescription) {
|
||||
long delayMs = (long) (50L * Math.pow(failureCount, 2));
|
||||
imposeBackoffExponentialDelay(50L, 2, failureCount, commandDescription);
|
||||
}
|
||||
|
||||
public void imposeBackoffExponentialDelay(long period, int pow, int failureCount,
|
||||
String commandDescription) {
|
||||
long delayMs = (long) (period * Math.pow(failureCount, pow));
|
||||
logger.debug("Retry %1$d/%2$d after server error, delaying for %3$d ms: %4$s", failureCount,
|
||||
retryCountLimit, delayMs, commandDescription);
|
||||
try {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue