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.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
|
|
||||||
import org.jclouds.aws.s3.binders.AccessControlListBinder;
|
|
||||||
import org.jclouds.aws.s3.binders.S3ObjectBinder;
|
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.BucketMetadata;
|
||||||
import org.jclouds.aws.s3.domain.ListBucketResponse;
|
import org.jclouds.aws.s3.domain.ListBucketResponse;
|
||||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||||
import org.jclouds.aws.s3.domain.S3Object;
|
import org.jclouds.aws.s3.domain.S3Object;
|
||||||
import org.jclouds.aws.s3.filters.RequestAuthorizeSignature;
|
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.ParseObjectFromHeadersAndHttpContent;
|
||||||
import org.jclouds.aws.s3.functions.ParseObjectMetadataFromHeaders;
|
import org.jclouds.aws.s3.functions.ParseObjectMetadataFromHeaders;
|
||||||
import org.jclouds.aws.s3.functions.ReturnTrueIfBucketAlreadyOwnedByYou;
|
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.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.ListAllMyBucketsHandler;
|
||||||
import org.jclouds.aws.s3.xml.ListBucketHandler;
|
import org.jclouds.aws.s3.xml.ListBucketHandler;
|
||||||
import org.jclouds.blobstore.BlobStore;
|
import org.jclouds.blobstore.BlobStore;
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.functions.BlobKey;
|
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.blobstore.functions.ThrowKeyNotFoundOn404;
|
||||||
import org.jclouds.http.functions.ParseETagHeader;
|
import org.jclouds.http.functions.ParseETagHeader;
|
||||||
import org.jclouds.http.functions.ReturnFalseOn404;
|
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.Endpoint;
|
||||||
import org.jclouds.rest.EntityParam;
|
import org.jclouds.rest.EntityParam;
|
||||||
import org.jclouds.rest.ExceptionParser;
|
import org.jclouds.rest.ExceptionParser;
|
||||||
import org.jclouds.rest.Headers;
|
|
||||||
import org.jclouds.rest.HostPrefixParam;
|
import org.jclouds.rest.HostPrefixParam;
|
||||||
import org.jclouds.rest.ParamParser;
|
import org.jclouds.rest.ParamParser;
|
||||||
import org.jclouds.rest.QueryParams;
|
import org.jclouds.rest.QueryParams;
|
||||||
|
@ -74,9 +66,6 @@ import org.jclouds.rest.ResponseParser;
|
||||||
import org.jclouds.rest.SkipEncoding;
|
import org.jclouds.rest.SkipEncoding;
|
||||||
import org.jclouds.rest.VirtualHost;
|
import org.jclouds.rest.VirtualHost;
|
||||||
import org.jclouds.rest.XMLResponseParser;
|
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.
|
* Provides access to S3 via their REST API.
|
||||||
|
@ -184,38 +173,8 @@ public interface S3BlobStore extends BlobStore<BucketMetadata, ObjectMetadata, S
|
||||||
*/
|
*/
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("{key}")
|
@Path("{key}")
|
||||||
Future<Boolean> removeBlob(@HostPrefixParam String bucketName, @PathParam("key") String key);
|
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
||||||
|
Future<Void> 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);
|
|
||||||
|
|
||||||
@PUT
|
@PUT
|
||||||
@Path("{key}")
|
@Path("{key}")
|
||||||
|
@ -224,33 +183,6 @@ public interface S3BlobStore extends BlobStore<BucketMetadata, ObjectMetadata, S
|
||||||
@HostPrefixParam String bucketName,
|
@HostPrefixParam String bucketName,
|
||||||
@PathParam("key") @ParamParser(BlobKey.class) @EntityParam(S3ObjectBinder.class) S3Object object);
|
@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
|
@PUT
|
||||||
@Path("/")
|
@Path("/")
|
||||||
@ExceptionParser(ReturnTrueIfBucketAlreadyOwnedByYou.class)
|
@ExceptionParser(ReturnTrueIfBucketAlreadyOwnedByYou.class)
|
||||||
|
@ -267,7 +199,6 @@ public interface S3BlobStore extends BlobStore<BucketMetadata, ObjectMetadata, S
|
||||||
*
|
*
|
||||||
* @param bucketName
|
* @param bucketName
|
||||||
* what to delete
|
* what to delete
|
||||||
* @return false, if the bucket was not empty and therefore not deleted
|
|
||||||
* @see org.jclouds.aws.s3.commands.DeleteBucket
|
* @see org.jclouds.aws.s3.commands.DeleteBucket
|
||||||
* @see <a href=
|
* @see <a href=
|
||||||
* "http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketDELETE.html"
|
* "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
|
@DELETE
|
||||||
@Path("/")
|
@Path("/")
|
||||||
@ExceptionParser(ReturnTrueOn404FalseIfNotEmpty.class)
|
@ExceptionParser(ClearAndDeleteBucketIfNotEmpty.class)
|
||||||
Future<Boolean> deleteContainer(@HostPrefixParam String bucketName);
|
Future<Void> deleteContainer(@HostPrefixParam String bucketName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Issues a HEAD command to determine if the bucket exists or not.
|
* 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
|
@GET
|
||||||
@Path("/")
|
@Path("/")
|
||||||
@XMLResponseParser(ListBucketHandler.class)
|
@XMLResponseParser(ListBucketHandler.class)
|
||||||
Future<ListBucketResponse> listBlobs(@HostPrefixParam String bucketName,
|
|
||||||
@Nullable ListBucketOptions options);
|
|
||||||
|
|
||||||
@GET
|
|
||||||
@Path("/")
|
|
||||||
@XMLResponseParser(ListBucketHandler.class)
|
|
||||||
Future<ListBucketResponse> listBlobs(@HostPrefixParam String bucketName);
|
Future<ListBucketResponse> listBlobs(@HostPrefixParam String bucketName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -330,129 +255,4 @@ public interface S3BlobStore extends BlobStore<BucketMetadata, ObjectMetadata, S
|
||||||
@Path("/")
|
@Path("/")
|
||||||
SortedSet<BucketMetadata> listContainers();
|
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
|
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
|
* @see S3Context
|
||||||
*/
|
*/
|
||||||
public class S3ContextBuilder extends
|
public class S3ContextBuilder extends
|
||||||
BlobStoreContextBuilder<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
BlobStoreContextBuilder<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public S3Context buildContext() {
|
public S3Context buildContext() {
|
||||||
|
@ -69,7 +69,7 @@ public class S3ContextBuilder extends
|
||||||
}
|
}
|
||||||
|
|
||||||
public S3ContextBuilder(Properties props) {
|
public S3ContextBuilder(Properties props) {
|
||||||
super(new TypeLiteral<S3BlobStore>() {
|
super(new TypeLiteral<S3Connection>() {
|
||||||
}, new TypeLiteral<BucketMetadata>() {
|
}, new TypeLiteral<BucketMetadata>() {
|
||||||
}, new TypeLiteral<ObjectMetadata>() {
|
}, new TypeLiteral<ObjectMetadata>() {
|
||||||
}, new TypeLiteral<S3Object>() {
|
}, new TypeLiteral<S3Object>() {
|
||||||
|
|
|
@ -45,7 +45,8 @@ public class S3ObjectBinder extends BlobBinder {
|
||||||
public void addEntityToRequest(Object entity, HttpRequest request) {
|
public void addEntityToRequest(Object entity, HttpRequest request) {
|
||||||
Blob<?> object = (Blob<?>) entity;
|
Blob<?> object = (Blob<?>) entity;
|
||||||
checkArgument(object.getMetadata().getSize() >= 0, "size must be set");
|
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) {
|
if (object instanceof S3Object) {
|
||||||
S3Object s3Object = (S3Object) object;
|
S3Object s3Object = (S3Object) object;
|
||||||
if (s3Object.getMetadata().getCacheControl() != null) {
|
if (s3Object.getMetadata().getCacheControl() != null) {
|
||||||
|
|
|
@ -30,11 +30,16 @@ import javax.inject.Singleton;
|
||||||
|
|
||||||
import org.jclouds.aws.s3.S3;
|
import org.jclouds.aws.s3.S3;
|
||||||
import org.jclouds.aws.s3.S3BlobStore;
|
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.filters.RequestAuthorizeSignature;
|
||||||
import org.jclouds.aws.s3.handlers.AWSClientErrorRetryHandler;
|
import org.jclouds.aws.s3.handlers.AWSClientErrorRetryHandler;
|
||||||
import org.jclouds.aws.s3.handlers.AWSRedirectionRetryHandler;
|
import org.jclouds.aws.s3.handlers.AWSRedirectionRetryHandler;
|
||||||
import org.jclouds.aws.s3.handlers.ParseAWSErrorFromXmlContent;
|
import org.jclouds.aws.s3.handlers.ParseAWSErrorFromXmlContent;
|
||||||
import org.jclouds.aws.s3.reference.S3Constants;
|
import org.jclouds.aws.s3.reference.S3Constants;
|
||||||
|
import org.jclouds.blobstore.BlobStore;
|
||||||
import org.jclouds.cloud.ConfiguresCloudConnection;
|
import org.jclouds.cloud.ConfiguresCloudConnection;
|
||||||
import org.jclouds.http.HttpErrorHandler;
|
import org.jclouds.http.HttpErrorHandler;
|
||||||
import org.jclouds.http.HttpRetryHandler;
|
import org.jclouds.http.HttpRetryHandler;
|
||||||
|
@ -73,10 +78,16 @@ public class RestS3ConnectionModule extends AbstractModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
protected S3BlobStore provideS3Connection(RestClientFactory factory) {
|
protected BlobStore<BucketMetadata, ObjectMetadata, S3Object> provideS3BlobStore(RestClientFactory factory) {
|
||||||
return factory.create(S3BlobStore.class);
|
return factory.create(S3BlobStore.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
protected S3Connection provideS3Connection(RestClientFactory factory) {
|
||||||
|
return factory.create(S3Connection.class);
|
||||||
|
}
|
||||||
|
|
||||||
protected void bindErrorHandlers() {
|
protected void bindErrorHandlers() {
|
||||||
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(
|
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(
|
||||||
ParseAWSErrorFromXmlContent.class);
|
ParseAWSErrorFromXmlContent.class);
|
||||||
|
|
|
@ -32,10 +32,12 @@ import javax.inject.Provider;
|
||||||
import org.jclouds.aws.reference.AWSConstants;
|
import org.jclouds.aws.reference.AWSConstants;
|
||||||
import org.jclouds.aws.s3.S3;
|
import org.jclouds.aws.s3.S3;
|
||||||
import org.jclouds.aws.s3.S3BlobStore;
|
import org.jclouds.aws.s3.S3BlobStore;
|
||||||
|
import org.jclouds.aws.s3.S3Connection;
|
||||||
import org.jclouds.aws.s3.S3Context;
|
import org.jclouds.aws.s3.S3Context;
|
||||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||||
import org.jclouds.aws.s3.domain.S3Object;
|
import org.jclouds.aws.s3.domain.S3Object;
|
||||||
|
import org.jclouds.blobstore.BlobStore;
|
||||||
import org.jclouds.blobstore.BlobStoreContextImpl;
|
import org.jclouds.blobstore.BlobStoreContextImpl;
|
||||||
import org.jclouds.blobstore.BlobMap.Factory;
|
import org.jclouds.blobstore.BlobMap.Factory;
|
||||||
import org.jclouds.lifecycle.Closer;
|
import org.jclouds.lifecycle.Closer;
|
||||||
|
@ -56,15 +58,17 @@ public class S3ContextModule extends AbstractModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class S3ContextImpl extends
|
public static class S3ContextImpl extends
|
||||||
BlobStoreContextImpl<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> implements
|
BlobStoreContextImpl<S3Connection, BucketMetadata, ObjectMetadata, S3Object> implements
|
||||||
S3Context {
|
S3Context {
|
||||||
@Inject
|
@Inject
|
||||||
S3ContextImpl(Factory<ObjectMetadata, S3Object> blobMapFactory,
|
S3ContextImpl(Factory<ObjectMetadata, S3Object> blobMapFactory,
|
||||||
org.jclouds.blobstore.InputStreamMap.Factory<ObjectMetadata> inputStreamMapFactory,
|
org.jclouds.blobstore.InputStreamMap.Factory<ObjectMetadata> inputStreamMapFactory,
|
||||||
Closer closer, Provider<S3Object> blobProvider, S3BlobStore defaultApi,
|
Closer closer, Provider<S3Object> blobProvider,
|
||||||
@S3 URI endPoint, @Named(AWSConstants.PROPERTY_AWS_ACCESSKEYID) String account) {
|
BlobStore<BucketMetadata, ObjectMetadata, S3Object> blobStore,
|
||||||
super(blobMapFactory, inputStreamMapFactory, closer, blobProvider, defaultApi, endPoint,
|
S3Connection defaultApi, @S3 URI endPoint,
|
||||||
account);
|
@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")) {
|
} else if (qName.equals("ETag")) {
|
||||||
currentObjectMetadata.setETag(HttpUtils.fromHexString(currentText.toString().replaceAll(
|
currentObjectMetadata.setETag(HttpUtils.fromHexString(currentText.toString().replaceAll(
|
||||||
"\"", "")));
|
"\"", "")));
|
||||||
|
currentObjectMetadata.setContentMD5(currentObjectMetadata.getETag());
|
||||||
} else if (qName.equals("Size")) {
|
} else if (qName.equals("Size")) {
|
||||||
currentObjectMetadata.setSize(Long.parseLong(currentText.toString()));
|
currentObjectMetadata.setSize(Long.parseLong(currentText.toString()));
|
||||||
} else if (qName.equals("Owner")) {
|
} 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.S3ContextModule;
|
||||||
import org.jclouds.aws.s3.config.StubS3BlobStoreModule;
|
import org.jclouds.aws.s3.config.StubS3BlobStoreModule;
|
||||||
import org.jclouds.aws.s3.config.S3ContextModule.S3ContextImpl;
|
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 org.testng.annotations.Test;
|
||||||
|
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
|
@ -61,6 +63,8 @@ public class S3ContextBuilderTest {
|
||||||
S3Context context = new S3ContextBuilder("id", "secret").withModules(
|
S3Context context = new S3ContextBuilder("id", "secret").withModules(
|
||||||
new StubS3BlobStoreModule()).buildContext();
|
new StubS3BlobStoreModule()).buildContext();
|
||||||
assertEquals(context.getClass(), S3ContextImpl.class);
|
assertEquals(context.getClass(), S3ContextImpl.class);
|
||||||
|
assertEquals(context.getApi().getClass(), StubS3Connection.class);
|
||||||
|
assertEquals(context.getBlobStore().getClass(), StubBlobStore.class);
|
||||||
assertEquals(context.getAccount(), "id");
|
assertEquals(context.getAccount(), "id");
|
||||||
assertEquals(context.getEndPoint(), URI.create("https://localhost/s3stub"));
|
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 static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
import org.jclouds.aws.s3.S3BlobStore;
|
|
||||||
import org.jclouds.aws.s3.S3Context;
|
import org.jclouds.aws.s3.S3Context;
|
||||||
import org.jclouds.aws.s3.config.S3ContextModule.S3ContextImpl;
|
import org.jclouds.aws.s3.config.S3ContextModule.S3ContextImpl;
|
||||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||||
|
@ -48,8 +47,7 @@ public class S3ContextModuleTest {
|
||||||
|
|
||||||
Injector createInjector() {
|
Injector createInjector() {
|
||||||
return Guice.createInjector(new StubS3BlobStoreModule(), BlobStoreMapsModule.Builder
|
return Guice.createInjector(new StubS3BlobStoreModule(), BlobStoreMapsModule.Builder
|
||||||
.newBuilder(new TypeLiteral<S3BlobStore>() {
|
.newBuilder(new TypeLiteral<BucketMetadata>() {
|
||||||
}, new TypeLiteral<BucketMetadata>() {
|
|
||||||
}, new TypeLiteral<ObjectMetadata>() {
|
}, new TypeLiteral<ObjectMetadata>() {
|
||||||
}, new TypeLiteral<S3Object>() {
|
}, new TypeLiteral<S3Object>() {
|
||||||
}).build(), new S3ContextModule() {
|
}).build(), new S3ContextModule() {
|
||||||
|
|
|
@ -28,9 +28,13 @@ import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.jclouds.aws.s3.S3;
|
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.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.cloud.ConfiguresCloudConnection;
|
||||||
import org.jclouds.http.functions.config.ParserModule;
|
import org.jclouds.http.functions.config.ParserModule;
|
||||||
|
|
||||||
|
@ -50,7 +54,10 @@ public class StubS3BlobStoreModule extends AbstractModule {
|
||||||
install(new ParserModule());
|
install(new ParserModule());
|
||||||
bind(new TypeLiteral<Map<String, Map<String, S3Object>>>() {
|
bind(new TypeLiteral<Map<String, Map<String, S3Object>>>() {
|
||||||
}).toInstance(map);
|
}).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"));
|
bind(URI.class).annotatedWith(S3.class).toInstance(URI.create("https://localhost/s3stub"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,42 +23,13 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.aws.s3.integration;
|
package org.jclouds.aws.s3.integration;
|
||||||
|
|
||||||
import static org.jclouds.aws.s3.internal.StubS3BlobStore.TEST_ACL_EMAIL;
|
import org.jclouds.aws.s3.S3Connection;
|
||||||
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.domain.BucketMetadata;
|
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.ObjectMetadata;
|
||||||
import org.jclouds.aws.s3.domain.S3Object;
|
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.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 org.testng.annotations.Test;
|
||||||
|
|
||||||
import com.google.common.collect.HashMultimap;
|
|
||||||
import com.google.common.collect.Multimap;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author James Murty
|
* @author James Murty
|
||||||
|
@ -66,361 +37,6 @@ import com.google.common.collect.Multimap;
|
||||||
*/
|
*/
|
||||||
@Test(groups = { "integration", "live" }, testName = "s3.S3BlobIntegrationTest")
|
@Test(groups = { "integration", "live" }, testName = "s3.S3BlobIntegrationTest")
|
||||||
public class S3BlobIntegrationTest extends
|
public class S3BlobIntegrationTest extends
|
||||||
BaseBlobIntegrationTest<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
BaseBlobIntegrationTest<S3Connection, 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);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -23,19 +23,11 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.aws.s3.integration;
|
package org.jclouds.aws.s3.integration;
|
||||||
|
|
||||||
import static org.jclouds.aws.s3.options.CopyObjectOptions.Builder.overrideAcl;
|
import org.jclouds.aws.s3.S3Connection;
|
||||||
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.domain.BucketMetadata;
|
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.ObjectMetadata;
|
||||||
import org.jclouds.aws.s3.domain.S3Object;
|
import org.jclouds.aws.s3.domain.S3Object;
|
||||||
import org.jclouds.blobstore.integration.internal.BaseBlobLiveTest;
|
import org.jclouds.blobstore.integration.internal.BaseBlobLiveTest;
|
||||||
import org.jclouds.util.Utils;
|
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,48 +37,6 @@ import org.testng.annotations.Test;
|
||||||
*/
|
*/
|
||||||
@Test(groups = { "live" }, testName = "s3.S3BlobLiveTest")
|
@Test(groups = { "live" }, testName = "s3.S3BlobLiveTest")
|
||||||
public class S3BlobLiveTest extends
|
public class S3BlobLiveTest extends
|
||||||
BaseBlobLiveTest<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
BaseBlobLiveTest<S3Connection, 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -23,7 +23,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.aws.s3.integration;
|
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.BucketMetadata;
|
||||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||||
import org.jclouds.aws.s3.domain.S3Object;
|
import org.jclouds.aws.s3.domain.S3Object;
|
||||||
|
@ -35,6 +35,6 @@ import org.testng.annotations.Test;
|
||||||
*/
|
*/
|
||||||
@Test(groups = { "integration", "live" }, testName = "s3.S3BlobMapIntegrationTest")
|
@Test(groups = { "integration", "live" }, testName = "s3.S3BlobMapIntegrationTest")
|
||||||
public class S3BlobMapIntegrationTest extends
|
public class S3BlobMapIntegrationTest extends
|
||||||
BaseBlobMapIntegrationTest<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
BaseBlobMapIntegrationTest<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||||
|
|
||||||
}
|
}
|
|
@ -23,31 +23,10 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.aws.s3.integration;
|
package org.jclouds.aws.s3.integration;
|
||||||
|
|
||||||
import static org.jclouds.aws.s3.internal.StubS3BlobStore.TEST_ACL_EMAIL;
|
import org.jclouds.aws.s3.S3Connection;
|
||||||
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.domain.BucketMetadata;
|
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.ObjectMetadata;
|
||||||
import org.jclouds.aws.s3.domain.S3Object;
|
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.jclouds.blobstore.integration.internal.BaseContainerIntegrationTest;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
@ -57,133 +36,6 @@ import org.testng.annotations.Test;
|
||||||
*/
|
*/
|
||||||
@Test(groups = { "integration", "live" }, testName = "s3.S3ContainerIntegrationTest")
|
@Test(groups = { "integration", "live" }, testName = "s3.S3ContainerIntegrationTest")
|
||||||
public class S3ContainerIntegrationTest extends
|
public class S3ContainerIntegrationTest extends
|
||||||
BaseContainerIntegrationTest<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
BaseContainerIntegrationTest<S3Connection, 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -23,25 +23,11 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.aws.s3.integration;
|
package org.jclouds.aws.s3.integration;
|
||||||
|
|
||||||
import static org.jclouds.aws.s3.options.PutBucketOptions.Builder.createIn;
|
import org.jclouds.aws.s3.S3Connection;
|
||||||
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.domain.BucketMetadata;
|
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.ObjectMetadata;
|
||||||
import org.jclouds.aws.s3.domain.S3Object;
|
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.blobstore.integration.internal.BaseContainerLiveTest;
|
||||||
import org.jclouds.util.Utils;
|
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,63 +36,6 @@ import org.testng.annotations.Test;
|
||||||
*/
|
*/
|
||||||
@Test(groups = { "live" }, testName = "s3.S3ContainerLiveTest")
|
@Test(groups = { "live" }, testName = "s3.S3ContainerLiveTest")
|
||||||
public class S3ContainerLiveTest extends
|
public class S3ContainerLiveTest extends
|
||||||
BaseContainerLiveTest<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
BaseContainerLiveTest<S3Connection, 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
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.BucketMetadata;
|
||||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||||
import org.jclouds.aws.s3.domain.S3Object;
|
import org.jclouds.aws.s3.domain.S3Object;
|
||||||
|
@ -35,6 +35,6 @@ import org.testng.annotations.Test;
|
||||||
*/
|
*/
|
||||||
@Test(groups = { "integration", "live" }, testName = "s3.S3InputStreamMapIntegrationTest")
|
@Test(groups = { "integration", "live" }, testName = "s3.S3InputStreamMapIntegrationTest")
|
||||||
public class S3InputStreamMapIntegrationTest extends
|
public class S3InputStreamMapIntegrationTest extends
|
||||||
BaseInputStreamMapIntegrationTest<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
BaseInputStreamMapIntegrationTest<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||||
|
|
||||||
}
|
}
|
|
@ -23,9 +23,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.aws.s3.integration;
|
package org.jclouds.aws.s3.integration;
|
||||||
|
|
||||||
import java.util.SortedSet;
|
import org.jclouds.aws.s3.S3Connection;
|
||||||
|
|
||||||
import org.jclouds.aws.s3.S3BlobStore;
|
|
||||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||||
import org.jclouds.aws.s3.domain.S3Object;
|
import org.jclouds.aws.s3.domain.S3Object;
|
||||||
|
@ -37,18 +35,6 @@ import org.testng.annotations.Test;
|
||||||
*/
|
*/
|
||||||
@Test(groups = { "integration", "live" }, testName = "s3.S3ServiceIntegrationTest")
|
@Test(groups = { "integration", "live" }, testName = "s3.S3ServiceIntegrationTest")
|
||||||
public class S3ServiceIntegrationTest extends
|
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;
|
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.S3ContextBuilder;
|
||||||
import org.jclouds.aws.s3.S3ContextFactory;
|
import org.jclouds.aws.s3.S3ContextFactory;
|
||||||
import org.jclouds.aws.s3.config.StubS3BlobStoreModule;
|
import org.jclouds.aws.s3.config.StubS3BlobStoreModule;
|
||||||
|
@ -42,10 +42,10 @@ import com.google.inject.Module;
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public class S3TestInitializer extends
|
public class S3TestInitializer extends
|
||||||
BaseTestInitializer<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
BaseTestInitializer<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||||
|
|
||||||
@Override
|
@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) {
|
Module configurationModule, String url, String app, String account, String key) {
|
||||||
BaseBlobStoreIntegrationTest.SANITY_CHECK_RETURNED_BUCKET_NAME = true;
|
BaseBlobStoreIntegrationTest.SANITY_CHECK_RETURNED_BUCKET_NAME = true;
|
||||||
return new S3ContextBuilder(account, key).withSaxDebug().relaxSSLHostname().withModules(
|
return new S3ContextBuilder(account, key).withSaxDebug().relaxSSLHostname().withModules(
|
||||||
|
@ -53,7 +53,7 @@ public class S3TestInitializer extends
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected BlobStoreContext<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> createStubContext() {
|
protected BlobStoreContext<S3Connection, BucketMetadata, ObjectMetadata, S3Object> createStubContext() {
|
||||||
return S3ContextFactory.createContext("user", "pass", new StubS3BlobStoreModule());
|
return S3ContextFactory.createContext("user", "pass", new StubS3BlobStoreModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ import javax.inject.Inject;
|
||||||
import javax.inject.Provider;
|
import javax.inject.Provider;
|
||||||
|
|
||||||
import org.jclouds.aws.s3.S3BlobStore;
|
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.AccessControlList;
|
||||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||||
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
|
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
|
||||||
|
@ -70,11 +71,11 @@ import com.google.inject.internal.Nullable;
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
* @author James Murty
|
* @author James Murty
|
||||||
*/
|
*/
|
||||||
public class StubS3BlobStore extends StubBlobStore<BucketMetadata, ObjectMetadata, S3Object>
|
public class StubS3Connection extends StubBlobStore<BucketMetadata, ObjectMetadata, S3Object>
|
||||||
implements S3BlobStore {
|
implements S3Connection {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected StubS3BlobStore(Map<String, Map<String, S3Object>> containerToBlobs,
|
protected StubS3Connection(Map<String, Map<String, S3Object>> containerToBlobs,
|
||||||
DateService dateService, Provider<BucketMetadata> containerMetaProvider,
|
DateService dateService, Provider<BucketMetadata> containerMetaProvider,
|
||||||
Provider<S3Object> blobProvider) {
|
Provider<S3Object> blobProvider) {
|
||||||
super(containerToBlobs, dateService, containerMetaProvider, 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 static final String DEFAULT_OWNER_ID = "abc123";
|
||||||
|
|
||||||
public Future<Boolean> createContainer(String name, @Nullable PutBucketOptions nullableOptions) {
|
public Future<Boolean> putBucketIfNotExists(String name, PutBucketOptions... optionsList) {
|
||||||
final PutBucketOptions options = (nullableOptions == null) ? new PutBucketOptions()
|
final PutBucketOptions options = (optionsList.length == 0) ? new PutBucketOptions()
|
||||||
: nullableOptions;
|
: optionsList[0];
|
||||||
if (options.getLocationConstraint() != null)
|
if (options.getLocationConstraint() != null)
|
||||||
bucketToLocation.put(name, options.getLocationConstraint());
|
bucketToLocation.put(name, options.getLocationConstraint());
|
||||||
keyToAcl.put(name, options.getAcl());
|
keyToAcl.put(name, options.getAcl());
|
||||||
return super.createContainer(name);
|
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>() {
|
return new FutureBase<ListBucketResponse>() {
|
||||||
public ListBucketResponse get() throws InterruptedException, ExecutionException {
|
public ListBucketResponse get() throws InterruptedException, ExecutionException {
|
||||||
final Map<String, S3Object> realContents = getContainerToBlobs().get(name);
|
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,
|
final String destinationBucket, final String destinationObject,
|
||||||
@Nullable CopyObjectOptions nullableOptions) {
|
CopyObjectOptions... nullableOptions) {
|
||||||
final CopyObjectOptions options = (nullableOptions == null) ? new CopyObjectOptions()
|
final CopyObjectOptions options = (nullableOptions.length == 0) ? new CopyObjectOptions()
|
||||||
: nullableOptions;
|
: nullableOptions[0];
|
||||||
return new FutureBase<ObjectMetadata>() {
|
return new FutureBase<ObjectMetadata>() {
|
||||||
public ObjectMetadata get() throws InterruptedException, ExecutionException {
|
public ObjectMetadata get() throws InterruptedException, ExecutionException {
|
||||||
Map<String, S3Object> source = getContainerToBlobs().get(sourceBucket);
|
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) {
|
@Nullable PutObjectOptions nullableOptions) {
|
||||||
final PutObjectOptions options = (nullableOptions == null) ? new PutObjectOptions()
|
final PutObjectOptions options = (nullableOptions == null) ? new PutObjectOptions()
|
||||||
: nullableOptions;
|
: nullableOptions;
|
||||||
|
@ -248,7 +251,7 @@ public class StubS3BlobStore extends StubBlobStore<BucketMetadata, ObjectMetadat
|
||||||
return acl;
|
return acl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Future<AccessControlList> getContainerACL(final String bucket) {
|
public Future<AccessControlList> getBucketACL(final String bucket) {
|
||||||
return new FutureBase<AccessControlList>() {
|
return new FutureBase<AccessControlList>() {
|
||||||
public AccessControlList get() throws InterruptedException, ExecutionException {
|
public AccessControlList get() throws InterruptedException, ExecutionException {
|
||||||
return getACLforS3Item(bucket);
|
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>() {
|
return new FutureBase<AccessControlList>() {
|
||||||
public AccessControlList get() throws InterruptedException, ExecutionException {
|
public AccessControlList get() throws InterruptedException, ExecutionException {
|
||||||
return getACLforS3Item(bucket + "/" + objectKey);
|
return getACLforS3Item(bucket + "/" + objectKey);
|
||||||
|
@ -287,7 +290,7 @@ public class StubS3BlobStore extends StubBlobStore<BucketMetadata, ObjectMetadat
|
||||||
return acl;
|
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>() {
|
return new FutureBase<Boolean>() {
|
||||||
public Boolean get() throws InterruptedException, ExecutionException {
|
public Boolean get() throws InterruptedException, ExecutionException {
|
||||||
keyToAcl.put(bucket, sanitizeUploadedACL(acl));
|
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) {
|
final AccessControlList acl) {
|
||||||
return new FutureBase<Boolean>() {
|
return new FutureBase<Boolean>() {
|
||||||
public Boolean get() throws InterruptedException, ExecutionException {
|
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,
|
public Future<S3Object> getObject(String bucketName, String key, GetOptions... optionsList) {
|
||||||
String destinationBucket, String destinationObject) {
|
return super.getBlob(bucketName, key, optionsList.length != 0 ? optionsList[0] : null);
|
||||||
return copyBlob(sourceBucket, sourceObject, destinationBucket, destinationObject,
|
|
||||||
CopyObjectOptions.NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Future<Boolean> createContainer(String bucketName) {
|
public Future<byte[]> putObject(String bucketName, S3Object object,
|
||||||
return createContainer(bucketName, PutBucketOptions.NONE);
|
PutObjectOptions... optionsList) {
|
||||||
|
return putObject(bucketName, object, optionsList.length != 0 ? optionsList[0] : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public boolean bucketExists(String bucketName) {
|
||||||
public Future<S3Object> getBlob(String bucketName, String key) {
|
return super.containerExists(bucketName);
|
||||||
return getBlob(bucketName, key, GetOptions.NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Future<ListBucketResponse> listBlobs(String bucketName) {
|
public Future<Boolean> deleteBucketIfEmpty(String bucketName) {
|
||||||
return listBlobs(bucketName, ListBucketOptions.NONE);
|
return super.deleteContainerImpl(bucketName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Future<byte[]> putBlob(String bucketName, S3Object object) {
|
public Future<Void> deleteObject(String bucketName, String key) {
|
||||||
return putBlob(bucketName, object, PutObjectOptions.NONE);
|
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 java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.jclouds.aws.s3.S3BlobStore;
|
import org.jclouds.aws.s3.S3BlobStore;
|
||||||
|
import org.jclouds.aws.s3.S3Connection;
|
||||||
import org.jclouds.aws.s3.S3ContextFactory;
|
import org.jclouds.aws.s3.S3ContextFactory;
|
||||||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||||
import org.jclouds.aws.s3.domain.ListBucketResponse;
|
import org.jclouds.aws.s3.domain.ListBucketResponse;
|
||||||
|
@ -65,8 +66,8 @@ public class JCloudsS3Service extends S3Service {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final BlobStoreContext<S3BlobStore, BucketMetadata, ObjectMetadata, org.jclouds.aws.s3.domain.S3Object> context;
|
private final BlobStoreContext<S3Connection, BucketMetadata, ObjectMetadata, org.jclouds.aws.s3.domain.S3Object> context;
|
||||||
private final S3BlobStore connection;
|
private final S3Connection connection;
|
||||||
|
|
||||||
private final long requestTimeoutMilliseconds = 10000;
|
private final long requestTimeoutMilliseconds = 10000;
|
||||||
|
|
||||||
|
@ -106,7 +107,7 @@ public class JCloudsS3Service extends S3Service {
|
||||||
try {
|
try {
|
||||||
CopyObjectOptions options = Util.convertCopyObjectOptions(acl, destinationMetadata,
|
CopyObjectOptions options = Util.convertCopyObjectOptions(acl, destinationMetadata,
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchTags, ifNoneMatchTags);
|
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,
|
sourceBucketName, sourceObjectKey, destinationBucketName, destinationObjectKey,
|
||||||
options).get(requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
|
options).get(requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
@ -130,7 +131,7 @@ public class JCloudsS3Service extends S3Service {
|
||||||
throw new UnsupportedOperationException("Bucket ACL is not yet supported");
|
throw new UnsupportedOperationException("Bucket ACL is not yet supported");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (connection.createContainer(bucketName).get(requestTimeoutMilliseconds,
|
if (connection.putBucketIfNotExists(bucketName).get(requestTimeoutMilliseconds,
|
||||||
TimeUnit.MILLISECONDS)) {
|
TimeUnit.MILLISECONDS)) {
|
||||||
// Bucket created.
|
// Bucket created.
|
||||||
}
|
}
|
||||||
|
@ -149,7 +150,7 @@ public class JCloudsS3Service extends S3Service {
|
||||||
@Override
|
@Override
|
||||||
protected void deleteBucketImpl(String bucketName) throws S3ServiceException {
|
protected void deleteBucketImpl(String bucketName) throws S3ServiceException {
|
||||||
try {
|
try {
|
||||||
connection.deleteContainer(bucketName).get(requestTimeoutMilliseconds,
|
connection.deleteBucketIfEmpty(bucketName).get(requestTimeoutMilliseconds,
|
||||||
TimeUnit.MILLISECONDS);
|
TimeUnit.MILLISECONDS);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
||||||
|
@ -165,7 +166,7 @@ public class JCloudsS3Service extends S3Service {
|
||||||
@Override
|
@Override
|
||||||
protected void deleteObjectImpl(String bucketName, String objectKey) throws S3ServiceException {
|
protected void deleteObjectImpl(String bucketName, String objectKey) throws S3ServiceException {
|
||||||
try {
|
try {
|
||||||
connection.removeBlob(bucketName, objectKey).get(requestTimeoutMilliseconds,
|
connection.deleteObject(bucketName, objectKey).get(requestTimeoutMilliseconds,
|
||||||
TimeUnit.MILLISECONDS);
|
TimeUnit.MILLISECONDS);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
||||||
|
@ -177,7 +178,7 @@ public class JCloudsS3Service extends S3Service {
|
||||||
@Override
|
@Override
|
||||||
protected AccessControlList getBucketAclImpl(String bucketName) throws S3ServiceException {
|
protected AccessControlList getBucketAclImpl(String bucketName) throws S3ServiceException {
|
||||||
try {
|
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);
|
.get(requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
|
||||||
return Util.convertAccessControlList(jcACL);
|
return Util.convertAccessControlList(jcACL);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -203,7 +204,7 @@ public class JCloudsS3Service extends S3Service {
|
||||||
protected AccessControlList getObjectAclImpl(String bucketName, String objectKey)
|
protected AccessControlList getObjectAclImpl(String bucketName, String objectKey)
|
||||||
throws S3ServiceException {
|
throws S3ServiceException {
|
||||||
try {
|
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);
|
objectKey).get(requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
|
||||||
return Util.convertAccessControlList(jcACL);
|
return Util.convertAccessControlList(jcACL);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -226,7 +227,7 @@ public class JCloudsS3Service extends S3Service {
|
||||||
if (ifNoneMatchTags != null)
|
if (ifNoneMatchTags != null)
|
||||||
throw new IllegalArgumentException("ifNoneMatchTags");
|
throw new IllegalArgumentException("ifNoneMatchTags");
|
||||||
|
|
||||||
return Util.convertObjectHead(connection.blobMetadata(bucketName, objectKey));
|
return Util.convertObjectHead(connection.headObject(bucketName, objectKey));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
||||||
throw new S3ServiceException(String.format("error retrieving object head: %1$s:%2$s",
|
throw new S3ServiceException(String.format("error retrieving object head: %1$s:%2$s",
|
||||||
|
@ -241,7 +242,7 @@ public class JCloudsS3Service extends S3Service {
|
||||||
try {
|
try {
|
||||||
GetOptions options = Util.convertGetObjectOptions(ifModifiedSince, ifUnmodifiedSince,
|
GetOptions options = Util.convertGetObjectOptions(ifModifiedSince, ifUnmodifiedSince,
|
||||||
ifMatchTags, ifNoneMatchTags);
|
ifMatchTags, ifNoneMatchTags);
|
||||||
return Util.convertObject(connection.getBlob(bucketName, objectKey, options).get(
|
return Util.convertObject(connection.getObject(bucketName, objectKey, options).get(
|
||||||
requestTimeoutMilliseconds, TimeUnit.MILLISECONDS));
|
requestTimeoutMilliseconds, TimeUnit.MILLISECONDS));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
||||||
|
@ -265,7 +266,8 @@ public class JCloudsS3Service extends S3Service {
|
||||||
@Override
|
@Override
|
||||||
protected S3Bucket[] listAllBucketsImpl() throws S3ServiceException {
|
protected S3Bucket[] listAllBucketsImpl() throws S3ServiceException {
|
||||||
try {
|
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);
|
return Util.convertBuckets(jcBucketList);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
||||||
|
@ -285,7 +287,7 @@ public class JCloudsS3Service extends S3Service {
|
||||||
ListBucketOptions options = Util.convertListObjectOptions(prefix, priorLastKey,
|
ListBucketOptions options = Util.convertListObjectOptions(prefix, priorLastKey,
|
||||||
delimiter, maxListingLength);
|
delimiter, maxListingLength);
|
||||||
|
|
||||||
jcBucket = connection.listBlobs(bucketName, options).get(requestTimeoutMilliseconds,
|
jcBucket = connection.listBucket(bucketName, options).get(requestTimeoutMilliseconds,
|
||||||
TimeUnit.MILLISECONDS);
|
TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
jsObjects.addAll(Arrays.asList(Util.convertObjectHeads(jcBucket)));
|
jsObjects.addAll(Arrays.asList(Util.convertObjectHeads(jcBucket)));
|
||||||
|
@ -325,7 +327,7 @@ public class JCloudsS3Service extends S3Service {
|
||||||
throws S3ServiceException {
|
throws S3ServiceException {
|
||||||
try {
|
try {
|
||||||
org.jclouds.aws.s3.domain.AccessControlList jcACL = Util.convertAccessControlList(jsACL);
|
org.jclouds.aws.s3.domain.AccessControlList jcACL = Util.convertAccessControlList(jsACL);
|
||||||
connection.putContainerACL(bucketName, jcACL).get(requestTimeoutMilliseconds,
|
connection.putBucketACL(bucketName, jcACL).get(requestTimeoutMilliseconds,
|
||||||
TimeUnit.MILLISECONDS);
|
TimeUnit.MILLISECONDS);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
||||||
|
@ -338,7 +340,7 @@ public class JCloudsS3Service extends S3Service {
|
||||||
throws S3ServiceException {
|
throws S3ServiceException {
|
||||||
try {
|
try {
|
||||||
org.jclouds.aws.s3.domain.AccessControlList jcACL = Util.convertAccessControlList(jsACL);
|
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);
|
TimeUnit.MILLISECONDS);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
|
||||||
|
@ -351,7 +353,7 @@ public class JCloudsS3Service extends S3Service {
|
||||||
try {
|
try {
|
||||||
PutObjectOptions options = Util.convertPutObjectOptions(jsObject.getAcl());
|
PutObjectOptions options = Util.convertPutObjectOptions(jsObject.getAcl());
|
||||||
org.jclouds.aws.s3.domain.S3Object jcObject = Util.convertObject(jsObject);
|
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);
|
requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
|
||||||
jsObject.setMd5Hash(eTag);
|
jsObject.setMd5Hash(eTag);
|
||||||
return jsObject;
|
return jsObject;
|
||||||
|
|
|
@ -44,7 +44,7 @@ import java.util.concurrent.TimeoutException;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
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.BucketMetadata;
|
||||||
import org.jclouds.aws.s3.domain.ListBucketResponse;
|
import org.jclouds.aws.s3.domain.ListBucketResponse;
|
||||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||||
|
@ -82,7 +82,7 @@ import com.google.common.collect.Iterators;
|
||||||
@Test(groups = { "live" }, testName = "jets3t.JCloudsS3ServiceIntegrationTest")
|
@Test(groups = { "live" }, testName = "jets3t.JCloudsS3ServiceIntegrationTest")
|
||||||
public class JCloudsS3ServiceLiveTest
|
public class JCloudsS3ServiceLiveTest
|
||||||
extends
|
extends
|
||||||
BaseBlobStoreIntegrationTest<S3BlobStore, BucketMetadata, ObjectMetadata, org.jclouds.aws.s3.domain.S3Object> {
|
BaseBlobStoreIntegrationTest<S3Connection, BucketMetadata, ObjectMetadata, org.jclouds.aws.s3.domain.S3Object> {
|
||||||
AWSCredentials credentials;
|
AWSCredentials credentials;
|
||||||
S3Service service;
|
S3Service service;
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ public class JCloudsS3ServiceLiveTest
|
||||||
try {
|
try {
|
||||||
S3Bucket bucket = service.createBucket(new S3Bucket(bucketName));
|
S3Bucket bucket = service.createBucket(new S3Bucket(bucketName));
|
||||||
assertEquals(bucket.getName(), bucketName);
|
assertEquals(bucket.getName(), bucketName);
|
||||||
assertTrue(context.getApi().containerExists(bucketName));
|
assertTrue(context.getApi().bucketExists(bucketName));
|
||||||
} finally {
|
} finally {
|
||||||
returnContainer(bucketName);
|
returnContainer(bucketName);
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ public class JCloudsS3ServiceLiveTest
|
||||||
service.deleteBucket(bucketName);
|
service.deleteBucket(bucketName);
|
||||||
assertEventually(new Runnable() {
|
assertEventually(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
assertFalse(context.getApi().containerExists(bucketName));
|
assertFalse(context.getApi().bucketExists(bucketName));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@ public class JCloudsS3ServiceLiveTest
|
||||||
S3Bucket[] jsBuckets = service.listAllBuckets();
|
S3Bucket[] jsBuckets = service.listAllBuckets();
|
||||||
|
|
||||||
SortedSet<org.jclouds.aws.s3.domain.BucketMetadata> jcBuckets = context.getApi()
|
SortedSet<org.jclouds.aws.s3.domain.BucketMetadata> jcBuckets = context.getApi()
|
||||||
.listContainers();
|
.listOwnedBuckets();
|
||||||
|
|
||||||
assert jsBuckets.length == jcBuckets.size();
|
assert jsBuckets.length == jcBuckets.size();
|
||||||
|
|
||||||
|
@ -363,7 +363,7 @@ public class JCloudsS3ServiceLiveTest
|
||||||
// Upload empty object
|
// Upload empty object
|
||||||
requestObject = new S3Object(objectKey);
|
requestObject = new S3Object(objectKey);
|
||||||
jsResultObject = service.putObject(new S3Bucket(bucketName), requestObject);
|
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);
|
// TODO null keys from s3object! assertEquals(jcObject.getKey(), objectKey);
|
||||||
assertEquals(jcObject.getMetadata().getSize(), 0);
|
assertEquals(jcObject.getMetadata().getSize(), 0);
|
||||||
assertEquals(jcObject.getMetadata().getContentType(), MediaType.APPLICATION_OCTET_STREAM);
|
assertEquals(jcObject.getMetadata().getContentType(), MediaType.APPLICATION_OCTET_STREAM);
|
||||||
|
@ -374,7 +374,7 @@ public class JCloudsS3ServiceLiveTest
|
||||||
// Upload unicode-named object
|
// Upload unicode-named object
|
||||||
requestObject = new S3Object("Ÿn’<EFBFBD>˜dŽ-object");
|
requestObject = new S3Object("Ÿn’<EFBFBD>˜dŽ-object");
|
||||||
jsResultObject = service.putObject(new S3Bucket(bucketName), requestObject);
|
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);
|
TimeUnit.SECONDS);
|
||||||
// TODO null keys from s3object! assertEquals(jcObject.getKey(), requestObject.getKey());
|
// TODO null keys from s3object! assertEquals(jcObject.getKey(), requestObject.getKey());
|
||||||
assertEquals(jcObject.getMetadata().getSize(), 0);
|
assertEquals(jcObject.getMetadata().getSize(), 0);
|
||||||
|
@ -387,7 +387,7 @@ public class JCloudsS3ServiceLiveTest
|
||||||
String data = "This is my Ÿn’<6E>˜dŽ data";
|
String data = "This is my Ÿn’<6E>˜dŽ data";
|
||||||
requestObject = new S3Object(objectKey, data);
|
requestObject = new S3Object(objectKey, data);
|
||||||
jsResultObject = service.putObject(new S3Bucket(bucketName), requestObject);
|
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);
|
assertEquals(jcObject.getMetadata().getSize(), data.getBytes("UTF-8").length);
|
||||||
assertTrue(jcObject.getMetadata().getContentType().startsWith("text/plain"));
|
assertTrue(jcObject.getMetadata().getContentType().startsWith("text/plain"));
|
||||||
assertEquals(jsResultObject.getContentLength(), data.getBytes("UTF-8").length);
|
assertEquals(jsResultObject.getContentLength(), data.getBytes("UTF-8").length);
|
||||||
|
@ -397,7 +397,7 @@ public class JCloudsS3ServiceLiveTest
|
||||||
requestObject = new S3Object(objectKey);
|
requestObject = new S3Object(objectKey);
|
||||||
requestObject.addMetadata("x-amz-meta-" + "my-metadata-1", "value-1");
|
requestObject.addMetadata("x-amz-meta-" + "my-metadata-1", "value-1");
|
||||||
jsResultObject = service.putObject(new S3Bucket(bucketName), requestObject);
|
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(
|
assertEquals(Iterables.getLast(jcObject.getMetadata().getUserMetadata().get(
|
||||||
"my-metadata-1")), "value-1");
|
"my-metadata-1")), "value-1");
|
||||||
assertEquals(jsResultObject.getMetadata("x-amz-meta-" + "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 = new S3Object(objectKey);
|
||||||
requestObject.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ);
|
requestObject.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ);
|
||||||
jsResultObject = service.putObject(new S3Bucket(bucketName), requestObject);
|
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);
|
bucketName, objectKey).get(10, TimeUnit.SECONDS);
|
||||||
assertTrue(jcACL.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ));
|
assertTrue(jcACL.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ));
|
||||||
assertTrue(jcACL.hasPermission(jcACL.getOwner().getId(), Permission.FULL_CONTROL));
|
assertTrue(jcACL.hasPermission(jcACL.getOwner().getId(), Permission.FULL_CONTROL));
|
||||||
|
@ -422,7 +422,7 @@ public class JCloudsS3ServiceLiveTest
|
||||||
data = "Here is some d‡tˆ for you";
|
data = "Here is some d‡tˆ for you";
|
||||||
requestObject.setDataInputStream(new ByteArrayInputStream(data.getBytes("UTF-8")));
|
requestObject.setDataInputStream(new ByteArrayInputStream(data.getBytes("UTF-8")));
|
||||||
jsResultObject = service.putObject(new S3Bucket(bucketName), requestObject);
|
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")));
|
assertTrue(jsResultObject.verifyData(data.getBytes("UTF-8")));
|
||||||
assertEquals(jsResultObject.getMd5HashAsHex(), HttpUtils.toHexString(jcObject
|
assertEquals(jsResultObject.getMd5HashAsHex(), HttpUtils.toHexString(jcObject
|
||||||
.getMetadata().getETag()));
|
.getMetadata().getETag()));
|
||||||
|
@ -458,7 +458,7 @@ public class JCloudsS3ServiceLiveTest
|
||||||
destinationObject = new S3Object(destinationObjectKey);
|
destinationObject = new S3Object(destinationObjectKey);
|
||||||
copyResult = service.copyObject(bucketName, sourceObjectKey, bucketName,
|
copyResult = service.copyObject(bucketName, sourceObjectKey, bucketName,
|
||||||
destinationObject, false);
|
destinationObject, false);
|
||||||
jcDestinationObject = context.getApi().getBlob(bucketName, destinationObject.getKey())
|
jcDestinationObject = context.getApi().getObject(bucketName, destinationObject.getKey())
|
||||||
.get(10, TimeUnit.SECONDS);
|
.get(10, TimeUnit.SECONDS);
|
||||||
// TODO null keys from s3object! assertEquals(jcDestinationObject.getKey(),
|
// TODO null keys from s3object! assertEquals(jcDestinationObject.getKey(),
|
||||||
// destinationObjectKey);
|
// destinationObjectKey);
|
||||||
|
@ -467,7 +467,7 @@ public class JCloudsS3ServiceLiveTest
|
||||||
assertEquals(copyResult.get("ETag"), HttpUtils.toHexString(jcDestinationObject
|
assertEquals(copyResult.get("ETag"), HttpUtils.toHexString(jcDestinationObject
|
||||||
.getMetadata().getETag()));
|
.getMetadata().getETag()));
|
||||||
// Test destination ACL is unchanged (ie private)
|
// 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);
|
bucketName, destinationObject.getKey()).get(10, TimeUnit.SECONDS);
|
||||||
assertEquals(jcACL.getGrants().size(), 1);
|
assertEquals(jcACL.getGrants().size(), 1);
|
||||||
assertTrue(jcACL.hasPermission(jcACL.getOwner().getId(), Permission.FULL_CONTROL));
|
assertTrue(jcACL.hasPermission(jcACL.getOwner().getId(), Permission.FULL_CONTROL));
|
||||||
|
@ -477,12 +477,12 @@ public class JCloudsS3ServiceLiveTest
|
||||||
destinationObject.addMetadata("x-amz-meta-" + metadataName, destinationMetadataValue);
|
destinationObject.addMetadata("x-amz-meta-" + metadataName, destinationMetadataValue);
|
||||||
copyResult = service.copyObject(bucketName, sourceObjectKey, bucketName,
|
copyResult = service.copyObject(bucketName, sourceObjectKey, bucketName,
|
||||||
destinationObject, true);
|
destinationObject, true);
|
||||||
jcDestinationObject = context.getApi().getBlob(bucketName, destinationObject.getKey())
|
jcDestinationObject = context.getApi().getObject(bucketName, destinationObject.getKey())
|
||||||
.get(10, TimeUnit.SECONDS);
|
.get(10, TimeUnit.SECONDS);
|
||||||
assertEquals(Iterators.getLast(jcDestinationObject.getMetadata().getUserMetadata().get(
|
assertEquals(Iterators.getLast(jcDestinationObject.getMetadata().getUserMetadata().get(
|
||||||
metadataName).iterator()), destinationMetadataValue);
|
metadataName).iterator()), destinationMetadataValue);
|
||||||
// Test destination ACL is unchanged (ie private)
|
// 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);
|
TimeUnit.SECONDS);
|
||||||
assertEquals(jcACL.getGrants().size(), 1);
|
assertEquals(jcACL.getGrants().size(), 1);
|
||||||
assertTrue(jcACL.hasPermission(jcACL.getOwner().getId(), Permission.FULL_CONTROL));
|
assertTrue(jcACL.hasPermission(jcACL.getOwner().getId(), Permission.FULL_CONTROL));
|
||||||
|
@ -493,7 +493,7 @@ public class JCloudsS3ServiceLiveTest
|
||||||
copyResult = service.copyObject(bucketName, sourceObjectKey, bucketName,
|
copyResult = service.copyObject(bucketName, sourceObjectKey, bucketName,
|
||||||
destinationObject, false);
|
destinationObject, false);
|
||||||
// Test destination ACL is changed (ie public-read)
|
// 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);
|
TimeUnit.SECONDS);
|
||||||
assertEquals(jcACL.getGrants().size(), 2);
|
assertEquals(jcACL.getGrants().size(), 2);
|
||||||
assertTrue(jcACL.hasPermission(jcACL.getOwner().getId(), Permission.FULL_CONTROL));
|
assertTrue(jcACL.hasPermission(jcACL.getOwner().getId(), Permission.FULL_CONTROL));
|
||||||
|
@ -673,7 +673,7 @@ public class JCloudsS3ServiceLiveTest
|
||||||
multiService.putObjects(bucket, objects);
|
multiService.putObjects(bucket, objects);
|
||||||
|
|
||||||
assertEquals(countOfUploadCompletions[0], OBJECT_COUNT);
|
assertEquals(countOfUploadCompletions[0], OBJECT_COUNT);
|
||||||
ListBucketResponse theBucket = context.getApi().listBlobs(bucketName).get(10,
|
ListBucketResponse theBucket = context.getApi().listBucket(bucketName).get(10,
|
||||||
TimeUnit.SECONDS);
|
TimeUnit.SECONDS);
|
||||||
assertEquals(theBucket.size(), OBJECT_COUNT);
|
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);
|
org.jclouds.aws.s3.domain.S3Object object = new org.jclouds.aws.s3.domain.S3Object(key);
|
||||||
object.getMetadata().setContentType(contentType);
|
object.getMetadata().setContentType(contentType);
|
||||||
object.setData(data);
|
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
|
@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);
|
org.jclouds.aws.s3.domain.S3Object object = new org.jclouds.aws.s3.domain.S3Object(key);
|
||||||
object.getMetadata().setContentType(contentType);
|
object.getMetadata().setContentType(contentType);
|
||||||
object.setData(data);
|
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
|
@Override
|
||||||
|
@ -76,7 +76,7 @@ public abstract class BaseJCloudsPerformanceLiveTest extends BasePerformanceLive
|
||||||
object.getMetadata().setContentType(contentType);
|
object.getMetadata().setContentType(contentType);
|
||||||
object.setData(data);
|
object.setData(data);
|
||||||
object.getMetadata().setSize(data.available());
|
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
|
@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);
|
org.jclouds.aws.s3.domain.S3Object object = new org.jclouds.aws.s3.domain.S3Object(key);
|
||||||
object.getMetadata().setContentType(contentType);
|
object.getMetadata().setContentType(contentType);
|
||||||
object.setData(data);
|
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
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public abstract class BasePerformanceLiveTest extends
|
public abstract class BasePerformanceLiveTest extends
|
||||||
BaseBlobStoreIntegrationTest<S3BlobStore, BucketMetadata, ObjectMetadata, S3Object> {
|
BaseBlobStoreIntegrationTest<S3Connection, BucketMetadata, ObjectMetadata, S3Object> {
|
||||||
protected int timeoutSeconds = 10;
|
protected int timeoutSeconds = 10;
|
||||||
protected int loopCount = 100;
|
protected int loopCount = 100;
|
||||||
protected ExecutorService exec;
|
protected ExecutorService exec;
|
||||||
|
@ -94,7 +94,7 @@ public abstract class BasePerformanceLiveTest extends
|
||||||
protected String createScratchContainerInEU() throws InterruptedException, ExecutionException,
|
protected String createScratchContainerInEU() throws InterruptedException, ExecutionException,
|
||||||
TimeoutException {
|
TimeoutException {
|
||||||
String containerName = getScratchContainerName();
|
String containerName = getScratchContainerName();
|
||||||
context.getApi().createContainer(containerName, createIn(LocationConstraint.EU)).get(30,
|
context.getApi().putBucketIfNotExists(containerName, createIn(LocationConstraint.EU)).get(30,
|
||||||
TimeUnit.SECONDS);
|
TimeUnit.SECONDS);
|
||||||
return containerName;
|
return containerName;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,14 +66,14 @@ public class MainApp {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// Create Bucket
|
// 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);
|
BlobMap blobMap = context.createBlobMap(bucketName);
|
||||||
Blob blob = context.newBlob("test");
|
Blob blob = context.newBlob("test");
|
||||||
blob.setData("testdata");
|
blob.setData("testdata");
|
||||||
blobMap.put("test", blob);
|
blobMap.put("test", blob);
|
||||||
|
|
||||||
// List bucket
|
// 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", bucketObj));
|
||||||
System.out.println(String.format(": %1$s entries%n", context.createInputStreamMap(
|
System.out.println(String.format(": %1$s entries%n", context.createInputStreamMap(
|
||||||
bucketObj.getName()).size()));
|
bucketObj.getName()).size()));
|
||||||
|
|
|
@ -86,7 +86,7 @@ public class GetAllBucketsController extends HttpServlet {
|
||||||
private void addMyBucketsToRequest(HttpServletRequest request) throws InterruptedException,
|
private void addMyBucketsToRequest(HttpServletRequest request) throws InterruptedException,
|
||||||
ExecutionException, TimeoutException {
|
ExecutionException, TimeoutException {
|
||||||
System.err.println(context.getAccount() + ":" + context.getEndPoint());
|
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,
|
SortedSet<BucketResult> myBuckets = Sets.newTreeSet(Iterables.transform(myBucketMetadata,
|
||||||
metadataToBucketResultProvider.get()));
|
metadataToBucketResultProvider.get()));
|
||||||
request.setAttribute("buckets", myBuckets);
|
request.setAttribute("buckets", myBuckets);
|
||||||
|
|
|
@ -108,14 +108,14 @@ public class JCloudsServlet extends HttpServlet {
|
||||||
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
try {
|
try {
|
||||||
SortedSet<BucketMetadata> myBucketMetadata = context.getApi().listContainers();
|
SortedSet<BucketMetadata> myBucketMetadata = context.getApi().listOwnedBuckets();
|
||||||
SortedSet<BucketResult> myBuckets = Sets.newTreeSet();
|
SortedSet<BucketResult> myBuckets = Sets.newTreeSet();
|
||||||
for (BucketMetadata metadata : myBucketMetadata) {
|
for (BucketMetadata metadata : myBucketMetadata) {
|
||||||
BucketResult result = new BucketResult();
|
BucketResult result = new BucketResult();
|
||||||
result.setName(metadata.getName());
|
result.setName(metadata.getName());
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
ListBucketResponse bucket = context.getApi().listBlobs(metadata.getName()).get(
|
ListBucketResponse bucket = context.getApi().listBucket(metadata.getName()).get(
|
||||||
10, TimeUnit.SECONDS);
|
10, TimeUnit.SECONDS);
|
||||||
result.setSize(bucket.size() + "");
|
result.setSize(bucket.size() + "");
|
||||||
} catch (ContainerNotFoundException ex) {
|
} 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
|
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
|
* @see AzureBlobContext
|
||||||
*/
|
*/
|
||||||
public class AzureBlobContextBuilder extends
|
public class AzureBlobContextBuilder extends
|
||||||
BlobStoreContextBuilder<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> {
|
BlobStoreContextBuilder<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AzureBlobContext buildContext() {
|
public AzureBlobContext buildContext() {
|
||||||
|
@ -68,7 +68,7 @@ public class AzureBlobContextBuilder extends
|
||||||
}
|
}
|
||||||
|
|
||||||
public AzureBlobContextBuilder(Properties props) {
|
public AzureBlobContextBuilder(Properties props) {
|
||||||
super(new TypeLiteral<AzureBlobStore>() {
|
super(new TypeLiteral<AzureBlobConnection>() {
|
||||||
}, new TypeLiteral<ContainerMetadata>() {
|
}, new TypeLiteral<ContainerMetadata>() {
|
||||||
}, new TypeLiteral<BlobMetadata>() {
|
}, new TypeLiteral<BlobMetadata>() {
|
||||||
}, new TypeLiteral<Blob>() {
|
}, new TypeLiteral<Blob>() {
|
||||||
|
@ -78,6 +78,12 @@ public class AzureBlobContextBuilder extends
|
||||||
"https://{account}.blob.core.windows.net");
|
"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) {
|
public AzureBlobContextBuilder(String id, String secret) {
|
||||||
this(new Properties());
|
this(new Properties());
|
||||||
properties.setProperty(AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT, checkNotNull(id,
|
properties.setProperty(AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT, checkNotNull(id,
|
||||||
|
@ -152,7 +158,7 @@ public class AzureBlobContextBuilder extends
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AzureBlobContextBuilder withSaxDebug() {
|
public AzureBlobContextBuilder withSaxDebug() {
|
||||||
return (AzureBlobContextBuilder) (AzureBlobContextBuilder) super.withSaxDebug();
|
return (AzureBlobContextBuilder) super.withSaxDebug();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.BlobMetadata;
|
||||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||||
import org.jclouds.azure.storage.blob.domain.ListBlobsResponse;
|
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.ParseBlobFromHeadersAndHttpContent;
|
||||||
import org.jclouds.azure.storage.blob.functions.ParseBlobMetadataFromHeaders;
|
import org.jclouds.azure.storage.blob.functions.ParseBlobMetadataFromHeaders;
|
||||||
import org.jclouds.azure.storage.blob.functions.ReturnTrueIfContainerAlreadyExists;
|
import org.jclouds.azure.storage.blob.functions.ReturnTrueIfContainerAlreadyExists;
|
||||||
import org.jclouds.azure.storage.blob.options.CreateContainerOptions;
|
import org.jclouds.azure.storage.blob.options.CreateContainerOptions;
|
||||||
import org.jclouds.azure.storage.blob.xml.AccountNameEnumerationResultsHandler;
|
import org.jclouds.azure.storage.blob.xml.AccountNameEnumerationResultsHandler;
|
||||||
import org.jclouds.azure.storage.blob.xml.ContainerNameEnumerationResultsHandler;
|
import org.jclouds.azure.storage.blob.xml.AddMD5ToListBlobsResponse;
|
||||||
import org.jclouds.azure.storage.domain.BoundedSortedSet;
|
|
||||||
import org.jclouds.azure.storage.filters.SharedKeyAuthentication;
|
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.options.ListOptions;
|
||||||
import org.jclouds.azure.storage.reference.AzureStorageHeaders;
|
import org.jclouds.azure.storage.reference.AzureStorageHeaders;
|
||||||
import org.jclouds.blobstore.BlobStore;
|
import org.jclouds.blobstore.BlobStore;
|
||||||
import org.jclouds.blobstore.binders.BlobBinder;
|
|
||||||
import org.jclouds.blobstore.functions.BlobKey;
|
import org.jclouds.blobstore.functions.BlobKey;
|
||||||
|
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
|
||||||
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
|
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
|
||||||
import org.jclouds.http.functions.ParseETagHeader;
|
import org.jclouds.http.functions.ParseETagHeader;
|
||||||
import org.jclouds.http.functions.ReturnFalseOn404;
|
import org.jclouds.http.functions.ReturnFalseOn404;
|
||||||
import org.jclouds.http.functions.ReturnTrueOn404;
|
|
||||||
import org.jclouds.http.options.GetOptions;
|
import org.jclouds.http.options.GetOptions;
|
||||||
import org.jclouds.rest.Endpoint;
|
import org.jclouds.rest.Endpoint;
|
||||||
import org.jclouds.rest.EntityParam;
|
import org.jclouds.rest.EntityParam;
|
||||||
|
@ -99,12 +97,6 @@ public interface AzureBlobStore extends BlobStore<ContainerMetadata, BlobMetadat
|
||||||
@QueryParams(keys = "comp", values = "list")
|
@QueryParams(keys = "comp", values = "list")
|
||||||
SortedSet<ContainerMetadata> listContainers();
|
SortedSet<ContainerMetadata> listContainers();
|
||||||
|
|
||||||
@GET
|
|
||||||
@XMLResponseParser(AccountNameEnumerationResultsHandler.class)
|
|
||||||
@Path("/")
|
|
||||||
@QueryParams(keys = "comp", values = "list")
|
|
||||||
BoundedSortedSet<ContainerMetadata> listContainers(ListOptions listOptions);
|
|
||||||
|
|
||||||
@HEAD
|
@HEAD
|
||||||
@Path("{container}")
|
@Path("{container}")
|
||||||
@ExceptionParser(ReturnFalseOn404.class)
|
@ExceptionParser(ReturnFalseOn404.class)
|
||||||
|
@ -127,13 +119,6 @@ public interface AzureBlobStore extends BlobStore<ContainerMetadata, BlobMetadat
|
||||||
@QueryParams(keys = "restype", values = "container")
|
@QueryParams(keys = "restype", values = "container")
|
||||||
Future<Boolean> createContainer(@PathParam("container") String 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
|
* The Delete Container operation marks the specified container for deletion. The container and
|
||||||
* any blobs contained within it are later deleted during garbage collection.
|
* any blobs contained within it are later deleted during garbage collection.
|
||||||
|
@ -149,68 +134,22 @@ public interface AzureBlobStore extends BlobStore<ContainerMetadata, BlobMetadat
|
||||||
*/
|
*/
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("{container}")
|
@Path("{container}")
|
||||||
@ExceptionParser(ReturnTrueOn404.class)
|
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
||||||
@QueryParams(keys = "restype", values = "container")
|
@QueryParams(keys = "restype", values = "container")
|
||||||
Future<Boolean> deleteContainer(@PathParam("container") String 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();
|
|
||||||
|
|
||||||
@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();
|
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@XMLResponseParser(ContainerNameEnumerationResultsHandler.class)
|
@XMLResponseParser(AddMD5ToListBlobsResponse.class)
|
||||||
@Path("{container}")
|
@Path("{container}")
|
||||||
@QueryParams(keys = { "restype", "comp" }, values = { "container", "list" })
|
@QueryParams(keys = { "restype", "comp" }, values = { "container", "list" })
|
||||||
Future<ListBlobsResponse> listBlobs(@PathParam("container") String container);
|
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
|
@PUT
|
||||||
@Path("{container}/{key}")
|
@Path("{container}/{key}")
|
||||||
@ResponseParser(ParseETagHeader.class)
|
@ResponseParser(ParseETagHeader.class)
|
||||||
Future<byte[]> putBlob(@PathParam("container") String container,
|
Future<byte[]> putBlob(
|
||||||
@PathParam("key") @ParamParser(BlobKey.class) @EntityParam(BlobBinder.class) Blob object);
|
@PathParam("container") String container,
|
||||||
|
@PathParam("key") @ParamParser(BlobKey.class) @EntityParam(MD5EnforcingBlobBinder.class) Blob object);
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@ResponseParser(ParseBlobFromHeadersAndHttpContent.class)
|
@ResponseParser(ParseBlobFromHeadersAndHttpContent.class)
|
||||||
|
@ -234,8 +173,8 @@ public interface AzureBlobStore extends BlobStore<ContainerMetadata, BlobMetadat
|
||||||
BlobMetadata blobMetadata(@PathParam("container") String container, @PathParam("key") String key);
|
BlobMetadata blobMetadata(@PathParam("container") String container, @PathParam("key") String key);
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
@ExceptionParser(ReturnTrueOn404.class)
|
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
||||||
@Path("{container}/{key}")
|
@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) {
|
public void addEntityToRequest(Object entity, HttpRequest request) {
|
||||||
Blob<?> object = (Blob<?>) entity;
|
Blob<?> object = (Blob<?>) entity;
|
||||||
checkArgument(object.getMetadata().getSize() >= 0, "size must be set");
|
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) {
|
if (object.getMetadata() instanceof BlobMetadata) {
|
||||||
BlobMetadata md = (BlobMetadata) object.getMetadata();
|
BlobMetadata md = (BlobMetadata) object.getMetadata();
|
||||||
|
|
||||||
|
|
|
@ -30,12 +30,14 @@ import javax.inject.Named;
|
||||||
import javax.inject.Provider;
|
import javax.inject.Provider;
|
||||||
|
|
||||||
import org.jclouds.azure.storage.AzureBlob;
|
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.AzureBlobContext;
|
||||||
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
||||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||||
import org.jclouds.azure.storage.reference.AzureStorageConstants;
|
import org.jclouds.azure.storage.reference.AzureStorageConstants;
|
||||||
|
import org.jclouds.blobstore.BlobStore;
|
||||||
import org.jclouds.blobstore.BlobStoreContextImpl;
|
import org.jclouds.blobstore.BlobStoreContextImpl;
|
||||||
import org.jclouds.blobstore.BlobMap.Factory;
|
import org.jclouds.blobstore.BlobMap.Factory;
|
||||||
import org.jclouds.lifecycle.Closer;
|
import org.jclouds.lifecycle.Closer;
|
||||||
|
@ -55,16 +57,17 @@ public class AzureBlobContextModule extends AbstractModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class AzureBlobContextImpl extends
|
public static class AzureBlobContextImpl extends
|
||||||
BlobStoreContextImpl<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> implements
|
BlobStoreContextImpl<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob>
|
||||||
AzureBlobContext {
|
implements AzureBlobContext {
|
||||||
@Inject
|
@Inject
|
||||||
AzureBlobContextImpl(Factory<BlobMetadata, Blob> blobMapFactory,
|
AzureBlobContextImpl(Factory<BlobMetadata, Blob> blobMapFactory,
|
||||||
org.jclouds.blobstore.InputStreamMap.Factory<BlobMetadata> inputStreamMapFactory,
|
org.jclouds.blobstore.InputStreamMap.Factory<BlobMetadata> inputStreamMapFactory,
|
||||||
Closer closer, Provider<Blob> blobProvider, AzureBlobStore defaultApi,
|
Closer closer, Provider<Blob> blobProvider,
|
||||||
@AzureBlob URI endPoint,
|
BlobStore<ContainerMetadata, BlobMetadata, Blob> blobStore,
|
||||||
|
AzureBlobConnection defaultApi, @AzureBlob URI endPoint,
|
||||||
@Named(AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT) String account) {
|
@Named(AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT) String account) {
|
||||||
super(blobMapFactory, inputStreamMapFactory, closer, blobProvider, defaultApi, endPoint,
|
super(blobMapFactory, inputStreamMapFactory, closer, blobProvider, blobStore, defaultApi,
|
||||||
account);
|
endPoint, account);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,11 +29,20 @@ import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import org.jclouds.azure.storage.AzureBlob;
|
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.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.blob.reference.AzureBlobConstants;
|
||||||
import org.jclouds.azure.storage.config.RestAzureStorageConnectionModule;
|
import org.jclouds.azure.storage.config.RestAzureStorageConnectionModule;
|
||||||
|
import org.jclouds.blobstore.BlobStore;
|
||||||
import org.jclouds.cloud.ConfiguresCloudConnection;
|
import org.jclouds.cloud.ConfiguresCloudConnection;
|
||||||
|
import org.jclouds.http.HttpRetryHandler;
|
||||||
import org.jclouds.http.RequiresHttp;
|
import org.jclouds.http.RequiresHttp;
|
||||||
|
import org.jclouds.http.annotation.ClientError;
|
||||||
import org.jclouds.rest.RestClientFactory;
|
import org.jclouds.rest.RestClientFactory;
|
||||||
|
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
|
@ -62,8 +71,26 @@ public class RestAzureBlobStoreModule extends RestAzureStorageConnectionModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@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);
|
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 org.joda.time.DateTime;
|
||||||
|
|
||||||
|
import com.google.common.collect.HashMultimap;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
|
@ -37,21 +40,22 @@ public class ContainerMetadata extends org.jclouds.blobstore.domain.ContainerMet
|
||||||
private URI url;
|
private URI url;
|
||||||
private DateTime lastModified;
|
private DateTime lastModified;
|
||||||
private byte[] eTag;
|
private byte[] eTag;
|
||||||
|
private Multimap<String, String> userMetadata = HashMultimap.create();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = super.hashCode();
|
int result = super.hashCode();
|
||||||
result = prime * result + Arrays.hashCode(eTag);
|
result = prime * result + Arrays.hashCode(eTag);
|
||||||
result = prime * result + ((lastModified == null) ? 0 : lastModified.hashCode());
|
result = prime * result + ((getLastModified() == null) ? 0 : getLastModified().hashCode());
|
||||||
result = prime * result + ((url == null) ? 0 : url.hashCode());
|
result = prime * result + ((getUrl() == null) ? 0 : getUrl().hashCode());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ContainerMetadata [eTag=" + Arrays.toString(eTag) + ", lastModified=" + lastModified
|
return "ContainerMetadata [eTag=" + Arrays.toString(eTag) + ", lastModified="
|
||||||
+ ", url=" + url + ", name=" + name + "]";
|
+ getLastModified() + ", url=" + getUrl() + ", name=" + name + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -65,22 +69,22 @@ public class ContainerMetadata extends org.jclouds.blobstore.domain.ContainerMet
|
||||||
ContainerMetadata other = (ContainerMetadata) obj;
|
ContainerMetadata other = (ContainerMetadata) obj;
|
||||||
if (!Arrays.equals(eTag, other.eTag))
|
if (!Arrays.equals(eTag, other.eTag))
|
||||||
return false;
|
return false;
|
||||||
if (lastModified == null) {
|
if (getLastModified() == null) {
|
||||||
if (other.lastModified != null)
|
if (other.getLastModified() != null)
|
||||||
return false;
|
return false;
|
||||||
} else if (!lastModified.equals(other.lastModified))
|
} else if (!getLastModified().equals(other.getLastModified()))
|
||||||
return false;
|
return false;
|
||||||
if (url == null) {
|
if (getUrl() == null) {
|
||||||
if (other.url != null)
|
if (other.getUrl() != null)
|
||||||
return false;
|
return false;
|
||||||
} else if (!url.equals(other.url))
|
} else if (!getUrl().equals(other.getUrl()))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContainerMetadata(URI url, DateTime lastModified, byte[] eTag) {
|
public ContainerMetadata(URI url, DateTime lastModified, byte[] eTag) {
|
||||||
super(url.getPath().substring(1));
|
super(url.getPath().substring(1));
|
||||||
this.url = url;
|
this.setUrl(url);
|
||||||
this.lastModified = lastModified;
|
this.lastModified = lastModified;
|
||||||
this.eTag = eTag;
|
this.eTag = eTag;
|
||||||
}
|
}
|
||||||
|
@ -105,4 +109,24 @@ public class ContainerMetadata extends org.jclouds.blobstore.domain.ContainerMet
|
||||||
return eTag;
|
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
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Test(groups = "live", sequential = true, testName = "cloudservers.AzureBlobStoreLiveTest")
|
@Test(groups = "live", sequential = true, testName = "azureblob.AzureBlobConnectionLiveTest")
|
||||||
public class AzureBlobStoreLiveTest {
|
public class AzureBlobConnectionLiveTest {
|
||||||
|
|
||||||
protected AzureBlobStore connection;
|
protected AzureBlobConnection connection;
|
||||||
|
|
||||||
private String containerPrefix = System.getProperty("user.name") + "-azureblob";
|
private String containerPrefix = System.getProperty("user.name") + "-azureblob";
|
||||||
|
|
||||||
|
@ -215,14 +215,14 @@ public class AzureBlobStoreLiveTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteOneContainer() throws Exception {
|
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",
|
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = { "testListOwnedContainers",
|
||||||
"testObjectOperations" })
|
"testObjectOperations" })
|
||||||
public void testDeleteContainer() throws Exception {
|
public void testDeleteContainer() throws Exception {
|
||||||
assert connection.deleteContainer(privateContainer).get(10, TimeUnit.SECONDS);
|
connection.deleteContainer(privateContainer).get(10, TimeUnit.SECONDS);
|
||||||
assert connection.deleteContainer(publicContainer).get(10, TimeUnit.SECONDS);
|
connection.deleteContainer(publicContainer).get(10, TimeUnit.SECONDS);
|
||||||
// TODO loop for up to 30 seconds checking if they are really gone
|
// 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
|
// Test HEAD of missing object
|
||||||
try {
|
try {
|
||||||
connection.blobMetadata(privateContainer, "non-existent-object");
|
connection.getBlobProperties(privateContainer, "non-existent-object");
|
||||||
assert false;
|
assert false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test HEAD of object
|
// Test HEAD of object
|
||||||
BlobMetadata metadata = connection.blobMetadata(privateContainer, object.getKey());
|
BlobMetadata metadata = connection.getBlobProperties(privateContainer, object.getKey());
|
||||||
// TODO assertEquals(metadata.getKey(), 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
|
// 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
|
// 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);
|
// TimeUnit.SECONDS);
|
||||||
// assertEquals(IOUtils.toString((InputStream) getBlob.getData()), data.substring(8));
|
// assertEquals(IOUtils.toString((InputStream) getBlob.getData()), data.substring(8));
|
||||||
|
|
||||||
assertTrue(connection.removeBlob(privateContainer, "object").get(10, TimeUnit.SECONDS));
|
connection.deleteBlob(privateContainer, "object").get(10, TimeUnit.SECONDS);
|
||||||
assertTrue(connection.removeBlob(privateContainer, "chunked-object")
|
connection.deleteBlob(privateContainer, "chunked-object").get(10, TimeUnit.SECONDS);
|
||||||
.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.RestAzureBlobStoreModule;
|
||||||
import org.jclouds.azure.storage.blob.config.StubAzureBlobStoreModule;
|
import org.jclouds.azure.storage.blob.config.StubAzureBlobStoreModule;
|
||||||
import org.jclouds.azure.storage.blob.config.AzureBlobContextModule.AzureBlobContextImpl;
|
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.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 org.testng.annotations.Test;
|
||||||
|
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
|
@ -60,22 +62,26 @@ public class AzureBlobContextBuilderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBuildContext() {
|
public void testBuildContext() {
|
||||||
CloudContext<AzureBlobStore> context = new AzureBlobContextBuilder("id", "secret")
|
AzureBlobContext context = new AzureBlobContextBuilder("id", HttpUtils
|
||||||
.withModules(new StubAzureBlobStoreModule()).buildContext();
|
.toBase64String("secret".getBytes())).withModules(new StubAzureBlobStoreModule())
|
||||||
|
.buildContext();
|
||||||
assertEquals(context.getClass(), AzureBlobContextImpl.class);
|
assertEquals(context.getClass(), AzureBlobContextImpl.class);
|
||||||
|
assertEquals(context.getApi().getClass(), StubAzureBlobConnection.class);
|
||||||
|
assertEquals(context.getBlobStore().getClass(), StubBlobStore.class);
|
||||||
assertEquals(context.getAccount(), "id");
|
assertEquals(context.getAccount(), "id");
|
||||||
assertEquals(context.getEndPoint(), URI.create("https://id.blob.core.windows.net"));
|
assertEquals(context.getEndPoint(), URI.create("https://id.blob.core.windows.net"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBuildInjector() {
|
public void testBuildInjector() {
|
||||||
Injector i = new AzureBlobContextBuilder("id", "secret").withModules(
|
Injector i = new AzureBlobContextBuilder("id", HttpUtils.toBase64String("secret".getBytes()))
|
||||||
new StubAzureBlobStoreModule()).buildInjector();
|
.withModules(new StubAzureBlobStoreModule()).buildInjector();
|
||||||
assert i.getInstance(AzureBlobContext.class) != null;
|
assert i.getInstance(AzureBlobContext.class) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void testAddContextModule() {
|
protected void testAddContextModule() {
|
||||||
List<Module> modules = new ArrayList<Module>();
|
List<Module> modules = new ArrayList<Module>();
|
||||||
AzureBlobContextBuilder builder = new AzureBlobContextBuilder("id", "secret");
|
AzureBlobContextBuilder builder = new AzureBlobContextBuilder("id", HttpUtils
|
||||||
|
.toBase64String("secret".getBytes()));
|
||||||
builder.addContextModule(modules);
|
builder.addContextModule(modules);
|
||||||
assertEquals(modules.size(), 1);
|
assertEquals(modules.size(), 1);
|
||||||
assertEquals(modules.get(0).getClass(), AzureBlobContextModule.class);
|
assertEquals(modules.get(0).getClass(), AzureBlobContextModule.class);
|
||||||
|
@ -83,7 +89,8 @@ public class AzureBlobContextBuilderTest {
|
||||||
|
|
||||||
protected void addConnectionModule() {
|
protected void addConnectionModule() {
|
||||||
List<Module> modules = new ArrayList<Module>();
|
List<Module> modules = new ArrayList<Module>();
|
||||||
AzureBlobContextBuilder builder = new AzureBlobContextBuilder("id", "secret");
|
AzureBlobContextBuilder builder = new AzureBlobContextBuilder("id", HttpUtils
|
||||||
|
.toBase64String("secret".getBytes()));
|
||||||
builder.addConnectionModule(modules);
|
builder.addConnectionModule(modules);
|
||||||
assertEquals(modules.size(), 1);
|
assertEquals(modules.size(), 1);
|
||||||
assertEquals(modules.get(0).getClass(), RestAzureBlobStoreModule.class);
|
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;
|
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 static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
import javax.ws.rs.HttpMethod;
|
import javax.ws.rs.HttpMethod;
|
||||||
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
|
|
||||||
import org.jclouds.azure.storage.AzureBlob;
|
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.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.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.WithinThreadExecutorService;
|
||||||
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||||
import org.jclouds.http.HttpRequest;
|
import org.jclouds.http.HttpRequest;
|
||||||
import org.jclouds.http.HttpUtils;
|
import org.jclouds.http.HttpUtils;
|
||||||
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
||||||
|
import org.jclouds.http.functions.ParseETagHeader;
|
||||||
import org.jclouds.http.functions.ParseSax;
|
import org.jclouds.http.functions.ParseSax;
|
||||||
import org.jclouds.http.functions.ReturnTrueIf2xx;
|
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.JaxrsAnnotationProcessor;
|
||||||
import org.jclouds.rest.config.JaxrsModule;
|
import org.jclouds.rest.config.JaxrsModule;
|
||||||
import org.jclouds.util.Jsr330;
|
import org.jclouds.util.Jsr330;
|
||||||
import org.testng.annotations.BeforeClass;
|
import org.testng.annotations.BeforeClass;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMultimap;
|
|
||||||
import com.google.inject.AbstractModule;
|
import com.google.inject.AbstractModule;
|
||||||
import com.google.inject.Guice;
|
import com.google.inject.Guice;
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
import com.google.inject.Key;
|
import com.google.inject.Key;
|
||||||
|
import com.google.inject.Provides;
|
||||||
import com.google.inject.TypeLiteral;
|
import com.google.inject.TypeLiteral;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,7 +67,7 @@ import com.google.inject.TypeLiteral;
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Test(groups = "unit", testName = "cloudservers.AzureBlobStoreTest")
|
@Test(groups = "unit", testName = "azureblob.AzureBlobStoreTest")
|
||||||
public class AzureBlobStoreTest {
|
public class AzureBlobStoreTest {
|
||||||
|
|
||||||
public void testListContainers() throws SecurityException, NoSuchMethodException {
|
public void testListContainers() throws SecurityException, NoSuchMethodException {
|
||||||
|
@ -85,27 +87,6 @@ public class AzureBlobStoreTest {
|
||||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
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 {
|
public void testCreateContainer() throws SecurityException, NoSuchMethodException {
|
||||||
Method method = AzureBlobStore.class.getMethod("createContainer", String.class);
|
Method method = AzureBlobStore.class.getMethod("createContainer", String.class);
|
||||||
|
|
||||||
|
@ -137,94 +118,10 @@ public class AzureBlobStoreTest {
|
||||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||||
.singletonList("2009-07-17"));
|
.singletonList("2009-07-17"));
|
||||||
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||||
ReturnTrueIf2xx.class);
|
ReturnVoidIf2xx.class);
|
||||||
// TODO check generic type of response parser
|
// TODO check generic type of response parser
|
||||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
|
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
|
||||||
ReturnTrueOn404.class);
|
ReturnVoidOnNotFoundOr404.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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testListBlobs() throws SecurityException, NoSuchMethodException {
|
public void testListBlobs() throws SecurityException, NoSuchMethodException {
|
||||||
|
@ -244,21 +141,29 @@ public class AzureBlobStoreTest {
|
||||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testListRootBlobs() throws SecurityException, NoSuchMethodException {
|
public void testPutBlob() throws SecurityException, NoSuchMethodException, IOException {
|
||||||
Method method = AzureBlobStore.class.getMethod("listBlobs");
|
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().getHost(), "myaccount.blob.core.windows.net");
|
||||||
assertEquals(httpMethod.getEndpoint().getPath(), "/$root");
|
assertEquals(httpMethod.getEndpoint().getPath(), "/mycontainer/test");
|
||||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container&comp=list");
|
assertEquals(httpMethod.getEndpoint().getQuery(), null);
|
||||||
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
|
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
|
||||||
assertEquals(httpMethod.getHeaders().size(), 1);
|
assertEquals(httpMethod.getHeaders().size(), 4);
|
||||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||||
.singletonList("2009-07-17"));
|
.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(),
|
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
|
||||||
ParseSax.class);
|
ParseETagHeader.class);
|
||||||
// TODO check generic type of response parser
|
|
||||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
|
@ -274,7 +179,22 @@ public class AzureBlobStoreTest {
|
||||||
bindConstant().annotatedWith(
|
bindConstant().annotatedWith(
|
||||||
Jsr330.named(AzureStorageConstants.PROPERTY_AZURESTORAGE_KEY)).to(
|
Jsr330.named(AzureStorageConstants.PROPERTY_AZURESTORAGE_KEY)).to(
|
||||||
HttpUtils.toBase64String("key".getBytes()));
|
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 JaxrsModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
|
||||||
new JavaUrlHttpCommandExecutorServiceModule());
|
new JavaUrlHttpCommandExecutorServiceModule());
|
||||||
processor = injector.getInstance(Key
|
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 java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.jclouds.azure.storage.AzureBlob;
|
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.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.cloud.ConfiguresCloudConnection;
|
||||||
import org.jclouds.http.functions.config.ParserModule;
|
import org.jclouds.http.functions.config.ParserModule;
|
||||||
|
|
||||||
|
@ -51,7 +55,10 @@ public class StubAzureBlobStoreModule extends AbstractModule {
|
||||||
install(new ParserModule());
|
install(new ParserModule());
|
||||||
bind(new TypeLiteral<Map<String, Map<String, Blob>>>() {
|
bind(new TypeLiteral<Map<String, Map<String, Blob>>>() {
|
||||||
}).toInstance(map);
|
}).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(
|
bind(URI.class).annotatedWith(AzureBlob.class).toInstance(
|
||||||
URI.create("https://id.blob.core.windows.net"));
|
URI.create("https://id.blob.core.windows.net"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.azure.storage.blob.integration;
|
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.Blob;
|
||||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||||
|
@ -33,11 +33,8 @@ import org.testng.annotations.Test;
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Test(groups = { "integration", "live" }, testName = "cloudfiles.AzureBlobContainerIntegrationTest")
|
@Test(groups = { "integration", "live" }, testName = "azureblob.AzureBlobContainerIntegrationTest")
|
||||||
public class AzureBlobContainerIntegrationTest extends
|
public class AzureBlobContainerIntegrationTest extends
|
||||||
BaseContainerIntegrationTest<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> {
|
BaseContainerIntegrationTest<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> {
|
||||||
@Test(groups = { "integration", "live" }, enabled = false)
|
|
||||||
public void deleteContainerIfEmptyButHasContents() throws Exception {
|
|
||||||
// azure recursively deletes containers in the background.
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -23,7 +23,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.azure.storage.blob.integration;
|
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.Blob;
|
||||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||||
|
@ -33,8 +33,8 @@ import org.testng.annotations.Test;
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Test(groups = { "live" }, testName = "cloudfiles.AzureBlobContainerLiveTest")
|
@Test(groups = { "live" }, testName = "azureblob.AzureBlobContainerLiveTest")
|
||||||
public class AzureBlobContainerLiveTest extends
|
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;
|
package org.jclouds.azure.storage.blob.integration;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
|
||||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||||
|
@ -36,31 +33,9 @@ import org.testng.annotations.Test;
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Test(groups = { "integration", "live" }, testName = "cloudfiles.AzureBlobInputStreamMapIntegrationTest")
|
@Test(groups = { "integration", "live" }, testName = "azureblob.AzureBlobInputStreamMapIntegrationTest")
|
||||||
public class AzureBlobInputStreamMapIntegrationTest extends
|
public class AzureBlobInputStreamMapIntegrationTest
|
||||||
BaseInputStreamMapIntegrationTest<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> {
|
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.ExecutionException;
|
||||||
import java.util.concurrent.TimeoutException;
|
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.Blob;
|
||||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||||
|
@ -41,9 +41,9 @@ import org.testng.annotations.Test;
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Test(groups = { "integration", "live" }, testName = "cloudfiles.AzureBlobIntegrationTest")
|
@Test(groups = { "integration", "live" }, testName = "azureblob.AzureBlobIntegrationTest")
|
||||||
public class AzureBlobIntegrationTest extends
|
public class AzureBlobIntegrationTest extends
|
||||||
BaseBlobIntegrationTest<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> {
|
BaseBlobIntegrationTest<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Test(enabled = false)
|
@Test(enabled = false)
|
||||||
|
@ -68,7 +68,7 @@ public class AzureBlobIntegrationTest extends
|
||||||
|
|
||||||
protected void validateMetadata(BlobMetadata metadata) {
|
protected void validateMetadata(BlobMetadata metadata) {
|
||||||
assertEquals(metadata.getContentType(), "text/plain");
|
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
|
// 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
|
// tradeoff, as a container list will contain the correct size of the objects in an
|
||||||
// inexpensive fashion
|
// inexpensive fashion
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.azure.storage.blob.integration;
|
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.Blob;
|
||||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||||
|
@ -33,8 +33,8 @@ import org.testng.annotations.Test;
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Test(groups = { "live" }, testName = "cloudfiles.AzureBlobLiveTest")
|
@Test(groups = { "live" }, testName = "azureblob.AzureBlobLiveTest")
|
||||||
public class AzureBlobLiveTest extends
|
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;
|
package org.jclouds.azure.storage.blob.integration;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
|
||||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||||
|
@ -36,12 +33,8 @@ import org.testng.annotations.Test;
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Test(groups = { "integration", "live" }, testName = "cloudfiles.AzureBlobMapIntegrationTest")
|
@Test(groups = { "integration", "live" }, testName = "azureblob.AzureBlobMapIntegrationTest")
|
||||||
public class AzureBlobMapIntegrationTest extends
|
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;
|
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.Blob;
|
||||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||||
|
@ -33,8 +33,8 @@ import org.testng.annotations.Test;
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Test(groups = { "integration", "live" }, testName = "cloudfiles.AzureBlobServiceIntegrationTest")
|
@Test(groups = { "integration", "live" }, testName = "azureblob.AzureBlobServiceIntegrationTest")
|
||||||
public class AzureBlobServiceIntegrationTest extends
|
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;
|
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.AzureBlobContextBuilder;
|
||||||
import org.jclouds.azure.storage.blob.AzureBlobContextFactory;
|
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.config.StubAzureBlobStoreModule;
|
||||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
||||||
|
@ -41,17 +41,17 @@ import com.google.inject.Module;
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public class AzureBlobTestInitializer extends
|
public class AzureBlobTestInitializer extends
|
||||||
BaseTestInitializer<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> {
|
BaseTestInitializer<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> {
|
||||||
|
|
||||||
@Override
|
@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) {
|
Module configurationModule, String url, String app, String account, String key) {
|
||||||
return new AzureBlobContextBuilder(account, key).withSaxDebug().relaxSSLHostname()
|
return new AzureBlobContextBuilder(account, key).withSaxDebug().relaxSSLHostname()
|
||||||
.withModules(configurationModule, new Log4JLoggingModule()).buildContext();
|
.withModules(configurationModule, new Log4JLoggingModule()).buildContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected BlobStoreContext<AzureBlobStore, ContainerMetadata, BlobMetadata, Blob> createStubContext() {
|
protected BlobStoreContext<AzureBlobConnection, ContainerMetadata, BlobMetadata, Blob> createStubContext() {
|
||||||
return AzureBlobContextFactory.createContext("user", "pass", new StubAzureBlobStoreModule());
|
return AzureBlobContextFactory.createContext("user", "pass", new StubAzureBlobStoreModule());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -32,6 +32,7 @@ import java.util.concurrent.Future;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Provider;
|
import javax.inject.Provider;
|
||||||
|
|
||||||
|
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||||
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
import org.jclouds.azure.storage.blob.AzureBlobStore;
|
||||||
import org.jclouds.azure.storage.blob.domain.Blob;
|
import org.jclouds.azure.storage.blob.domain.Blob;
|
||||||
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
|
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.ListBlobsResponse;
|
||||||
import org.jclouds.azure.storage.blob.domain.TreeSetListBlobsResponse;
|
import org.jclouds.azure.storage.blob.domain.TreeSetListBlobsResponse;
|
||||||
import org.jclouds.azure.storage.blob.options.CreateContainerOptions;
|
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.domain.BoundedSortedSet;
|
||||||
import org.jclouds.azure.storage.options.CreateOptions;
|
|
||||||
import org.jclouds.azure.storage.options.ListOptions;
|
import org.jclouds.azure.storage.options.ListOptions;
|
||||||
import org.jclouds.blobstore.ContainerNotFoundException;
|
import org.jclouds.blobstore.ContainerNotFoundException;
|
||||||
import org.jclouds.blobstore.integration.internal.StubBlobStore;
|
import org.jclouds.blobstore.integration.internal.StubBlobStore;
|
||||||
|
import org.jclouds.http.options.GetOptions;
|
||||||
import org.jclouds.util.DateService;
|
import org.jclouds.util.DateService;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,40 +58,16 @@ import com.google.common.collect.Sets;
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public class StubAzureBlobStore extends StubBlobStore<ContainerMetadata, BlobMetadata, Blob>
|
public class StubAzureBlobConnection extends StubBlobStore<ContainerMetadata, BlobMetadata, Blob>
|
||||||
implements AzureBlobStore {
|
implements AzureBlobConnection {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected StubAzureBlobStore(Map<String, Map<String, Blob>> containerToBlobs,
|
protected StubAzureBlobConnection(Map<String, Map<String, Blob>> containerToBlobs,
|
||||||
DateService dateService, Provider<ContainerMetadata> containerMetaProvider,
|
DateService dateService, Provider<ContainerMetadata> containerMetaProvider,
|
||||||
Provider<Blob> blobProvider) {
|
Provider<Blob> blobProvider) {
|
||||||
super(containerToBlobs, dateService, containerMetaProvider, 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) {
|
public Future<ListBlobsResponse> listBlobs(final String name) {
|
||||||
return new FutureBase<ListBlobsResponse>() {
|
return new FutureBase<ListBlobsResponse>() {
|
||||||
public ListBlobsResponse get() throws InterruptedException, ExecutionException {
|
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
|
created = connection.createQueue(privateQueue, CreateOptions.Builder
|
||||||
.withMetadata(ImmutableMultimap.of("foo", "bar")));
|
.withMetadata(ImmutableMultimap.of("foo", "bar")));
|
||||||
} catch (UndeclaredThrowableException e) {
|
} catch (UndeclaredThrowableException e) {
|
||||||
|
if (e.getCause().getCause() instanceof HttpResponseException) {
|
||||||
HttpResponseException htpe = (HttpResponseException) e.getCause().getCause();
|
HttpResponseException htpe = (HttpResponseException) e.getCause().getCause();
|
||||||
if (htpe.getResponse().getStatusCode() == 409)
|
if (htpe.getResponse().getStatusCode() == 409)
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,13 +42,11 @@ public interface BlobStore<C extends ContainerMetadata, M extends BlobMetadata,
|
||||||
Future<Boolean> createContainer(String container);
|
Future<Boolean> createContainer(String container);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* if supported, this will delete a container recursively. Otherwise, it will return false, if
|
* This will delete a container recursively.
|
||||||
* the container could not be deleted because it is not empty.
|
|
||||||
*
|
*
|
||||||
* @param container
|
* @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);
|
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);
|
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)
|
@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> {
|
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);
|
BlobMap<M, B> createBlobMap(String container);
|
||||||
|
|
||||||
|
BlobStore<C, M, B> getBlobStore();
|
||||||
|
|
||||||
B newBlob(String key);
|
B newBlob(String key);
|
||||||
}
|
}
|
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.blobstore;
|
package org.jclouds.blobstore;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ import com.google.inject.util.Types;
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @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> {
|
extends CloudContextBuilder<S> {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
|
@ -141,8 +142,12 @@ public abstract class BlobStoreContextBuilder<S extends BlobStore<C, M, B>, C ex
|
||||||
this.containerMetadataType = containerMetadataType;
|
this.containerMetadataType = containerMetadataType;
|
||||||
this.blobMetadataType = blobMetadataType;
|
this.blobMetadataType = blobMetadataType;
|
||||||
this.blobType = blobType;
|
this.blobType = blobType;
|
||||||
modules.add(BlobStoreMapsModule.Builder.newBuilder(connectionType,
|
addBlobStoreModule(modules);
|
||||||
containerMetadataType, blobMetadataType, blobType).build());
|
}
|
||||||
|
|
||||||
|
protected void addBlobStoreModule(List<Module> modules) {
|
||||||
|
modules.add(BlobStoreMapsModule.Builder.newBuilder(containerMetadataType, blobMetadataType,
|
||||||
|
blobType).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|
|
@ -36,19 +36,22 @@ import org.jclouds.lifecycle.Closer;
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @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> {
|
extends CloudContextImpl<S> implements BlobStoreContext<S, C, M, B> {
|
||||||
private final BlobMap.Factory<M, B> blobMapFactory;
|
private final BlobMap.Factory<M, B> blobMapFactory;
|
||||||
private final InputStreamMap.Factory<M> inputStreamMapFactory;
|
private final InputStreamMap.Factory<M> inputStreamMapFactory;
|
||||||
private final Provider<B> blobProvider;
|
private final Provider<B> blobProvider;
|
||||||
|
private final BlobStore<C, M, B> blobStore;
|
||||||
|
|
||||||
public BlobStoreContextImpl(BlobMap.Factory<M, B> blobMapFactory,
|
public BlobStoreContextImpl(BlobMap.Factory<M, B> blobMapFactory,
|
||||||
InputStreamMap.Factory<M> inputStreamMapFactory, Closer closer,
|
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);
|
super(closer, defaultApi, endPoint, account);
|
||||||
this.blobMapFactory = blobMapFactory;
|
this.blobMapFactory = blobMapFactory;
|
||||||
this.inputStreamMapFactory = inputStreamMapFactory;
|
this.inputStreamMapFactory = inputStreamMapFactory;
|
||||||
this.blobProvider = blobProvider;
|
this.blobProvider = blobProvider;
|
||||||
|
this.blobStore = blobStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlobMap<M, B> createBlobMap(String container) {
|
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);
|
blob.getMetadata().setKey(key);
|
||||||
return blob;
|
return blob;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BlobStore<C, M, B> getBlobStore() {
|
||||||
|
return blobStore;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,16 +23,26 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.blobstore;
|
package org.jclouds.blobstore;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||||
import org.jclouds.blobstore.internal.BlobMapImpl;
|
import org.jclouds.blobstore.internal.BlobMapImpl;
|
||||||
import org.jclouds.blobstore.internal.InputStreamMapImpl;
|
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.GetAllBlobMetadataStrategy;
|
||||||
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
||||||
import org.jclouds.blobstore.strategy.internal.ContainerListGetAllBlobMetadataStrategy;
|
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.jclouds.blobstore.strategy.internal.RetryOnNotFoundGetAllBlobsStrategy;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
import com.google.inject.AbstractModule;
|
import com.google.inject.AbstractModule;
|
||||||
import com.google.inject.Scopes;
|
import com.google.inject.Scopes;
|
||||||
import com.google.inject.TypeLiteral;
|
import com.google.inject.TypeLiteral;
|
||||||
|
@ -47,17 +57,12 @@ public class BlobStoreMapsModule extends AbstractModule {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private BlobStoreMapsModule(TypeLiteral blobMapFactoryType, TypeLiteral blobMapImplType,
|
private BlobStoreMapsModule(TypeLiteral blobMapFactoryType, TypeLiteral blobMapImplType,
|
||||||
TypeLiteral inputStreamMapFactoryType, TypeLiteral inputStreamMapImplType,
|
TypeLiteral inputStreamMapFactoryType, TypeLiteral inputStreamMapImplType,
|
||||||
TypeLiteral getAllBlobsStrategyType, TypeLiteral getAllBlobsStrategyImplType,
|
Map<TypeLiteral, TypeLiteral> strategyImplMap) {
|
||||||
TypeLiteral getAllBlobMetadataStrategyType,
|
|
||||||
TypeLiteral getAllBlobMetadataStrategyImplType) {
|
|
||||||
this.blobMapFactoryType = blobMapFactoryType;
|
this.blobMapFactoryType = blobMapFactoryType;
|
||||||
this.blobMapImplType = blobMapImplType;
|
this.blobMapImplType = blobMapImplType;
|
||||||
this.inputStreamMapFactoryType = inputStreamMapFactoryType;
|
this.inputStreamMapFactoryType = inputStreamMapFactoryType;
|
||||||
this.inputStreamMapImplType = inputStreamMapImplType;
|
this.inputStreamMapImplType = inputStreamMapImplType;
|
||||||
this.getAllBlobsStrategyType = getAllBlobsStrategyType;
|
this.strategyImplMap = strategyImplMap;
|
||||||
this.getAllBlobsStrategyImplType = getAllBlobsStrategyImplType;
|
|
||||||
this.getAllBlobMetadataStrategyType = getAllBlobMetadataStrategyType;
|
|
||||||
this.getAllBlobMetadataStrategyImplType = getAllBlobMetadataStrategyImplType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// code is unchecked here as we are getting types at runtime. Due to type erasure, we cannot pass
|
// 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")
|
@SuppressWarnings("unchecked")
|
||||||
protected final TypeLiteral inputStreamMapImplType;
|
protected final TypeLiteral inputStreamMapImplType;
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected final TypeLiteral getAllBlobsStrategyType;
|
protected final Map<TypeLiteral, TypeLiteral> strategyImplMap;
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected final TypeLiteral getAllBlobsStrategyImplType;
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected final TypeLiteral getAllBlobMetadataStrategyType;
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected final TypeLiteral getAllBlobMetadataStrategyImplType;
|
|
||||||
|
|
||||||
public static class Builder<S extends BlobStore<C, M, B>, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>> {
|
public static class Builder<S, C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>> {
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final TypeLiteral<S> connectionType;
|
|
||||||
private final TypeLiteral<C> containerMetadataType;
|
private final TypeLiteral<C> containerMetadataType;
|
||||||
private final TypeLiteral<M> blobMetadataType;
|
private final TypeLiteral<M> blobMetadataType;
|
||||||
private final TypeLiteral<B> blobType;
|
private final TypeLiteral<B> blobType;
|
||||||
|
@ -101,23 +98,33 @@ public class BlobStoreMapsModule extends AbstractModule {
|
||||||
private TypeLiteral getAllBlobMetadataStrategyType;
|
private TypeLiteral getAllBlobMetadataStrategyType;
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private TypeLiteral getAllBlobMetadataStrategyImplType;
|
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,
|
private Builder(TypeLiteral<C> containerMetadataType, TypeLiteral<M> blobMetadataType,
|
||||||
TypeLiteral<M> blobMetadataType, TypeLiteral<B> blobType) {
|
TypeLiteral<B> blobType) {
|
||||||
this.connectionType = connectionType;
|
|
||||||
this.containerMetadataType = containerMetadataType;
|
this.containerMetadataType = containerMetadataType;
|
||||||
this.blobMetadataType = blobMetadataType;
|
this.blobMetadataType = blobMetadataType;
|
||||||
this.blobType = blobType;
|
this.blobType = blobType;
|
||||||
blobMapFactoryType = TypeLiteral.get(Types.newParameterizedTypeWithOwner(BlobMap.class,
|
blobMapFactoryType = TypeLiteral.get(Types.newParameterizedTypeWithOwner(BlobMap.class,
|
||||||
BlobMap.Factory.class, blobMetadataType.getType(), blobType.getType()));
|
BlobMap.Factory.class, blobMetadataType.getType(), blobType.getType()));
|
||||||
blobMapImplType = TypeLiteral.get(Types.newParameterizedType(BlobMapImpl.class,
|
blobMapImplType = TypeLiteral.get(Types.newParameterizedType(BlobMapImpl.class,
|
||||||
connectionType.getType(), containerMetadataType.getType(), blobMetadataType
|
containerMetadataType.getType(), blobMetadataType.getType(), blobType.getType()));
|
||||||
.getType(), blobType.getType()));
|
|
||||||
inputStreamMapFactoryType = TypeLiteral.get(Types.newParameterizedTypeWithOwner(
|
inputStreamMapFactoryType = TypeLiteral.get(Types.newParameterizedTypeWithOwner(
|
||||||
InputStreamMap.class, InputStreamMap.Factory.class, blobMetadataType.getType()));
|
InputStreamMap.class, InputStreamMap.Factory.class, blobMetadataType.getType()));
|
||||||
inputStreamMapImplType = TypeLiteral.get(Types.newParameterizedType(
|
inputStreamMapImplType = TypeLiteral.get(Types.newParameterizedType(
|
||||||
InputStreamMapImpl.class, connectionType.getType(), containerMetadataType
|
InputStreamMapImpl.class, containerMetadataType.getType(), blobMetadataType
|
||||||
.getType(), blobMetadataType.getType(), blobType.getType()));
|
.getType(), blobType.getType()));
|
||||||
getAllBlobsStrategyType = TypeLiteral.get(Types.newParameterizedType(
|
getAllBlobsStrategyType = TypeLiteral.get(Types.newParameterizedType(
|
||||||
GetAllBlobsStrategy.class, containerMetadataType.getType(), blobMetadataType
|
GetAllBlobsStrategy.class, containerMetadataType.getType(), blobMetadataType
|
||||||
.getType(), blobType.getType()));
|
.getType(), blobType.getType()));
|
||||||
|
@ -126,35 +133,95 @@ public class BlobStoreMapsModule extends AbstractModule {
|
||||||
getAllBlobMetadataStrategyType = TypeLiteral.get(Types.newParameterizedType(
|
getAllBlobMetadataStrategyType = TypeLiteral.get(Types.newParameterizedType(
|
||||||
GetAllBlobMetadataStrategy.class, containerMetadataType.getType(),
|
GetAllBlobMetadataStrategy.class, containerMetadataType.getType(),
|
||||||
blobMetadataType.getType(), blobType.getType()));
|
blobMetadataType.getType(), blobType.getType()));
|
||||||
getAllBlobMetadataStrategyImplType = TypeLiteral.get(Types.newParameterizedType(
|
setGetAllBlobMetadataStrategyImpl(ContainerListGetAllBlobMetadataStrategy.class);
|
||||||
ContainerListGetAllBlobMetadataStrategy.class, containerMetadataType.getType(),
|
|
||||||
blobMetadataType.getType(), blobType.getType()));
|
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);
|
setGetAllBlobsStrategyImpl(getAllBlobsStrategyImplClass);
|
||||||
return this;
|
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) {
|
private void setGetAllBlobsStrategyImpl(Class<?> getAllBlobsStrategyImplClass) {
|
||||||
getAllBlobsStrategyImplType = TypeLiteral.get(Types.newParameterizedType(
|
getAllBlobsStrategyImplType = TypeLiteral.get(Types.newParameterizedType(
|
||||||
getAllBlobsStrategyImplClass, containerMetadataType.getType(), blobMetadataType
|
getAllBlobsStrategyImplClass, containerMetadataType.getType(), blobMetadataType
|
||||||
.getType(), blobType.getType()));
|
.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(
|
private void setGetAllBlobMetadataStrategyImpl(Class<?> getAllBlobMetadataStrategyImplClass) {
|
||||||
TypeLiteral<S> connectionType, TypeLiteral<C> containerMetadataType,
|
getAllBlobMetadataStrategyImplType = TypeLiteral.get(Types.newParameterizedType(
|
||||||
TypeLiteral<M> blobMetadataType, TypeLiteral<B> blobType) {
|
getAllBlobMetadataStrategyImplClass, containerMetadataType.getType(),
|
||||||
return new Builder<S, C, M, B>(connectionType, containerMetadataType, blobMetadataType,
|
blobMetadataType.getType(), blobType.getType()));
|
||||||
blobType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
return new BlobStoreMapsModule(blobMapFactoryType, blobMapImplType,
|
||||||
inputStreamMapFactoryType, inputStreamMapImplType, getAllBlobsStrategyType,
|
inputStreamMapFactoryType, inputStreamMapImplType, strategyImplMap);
|
||||||
getAllBlobsStrategyImplType, getAllBlobMetadataStrategyType,
|
|
||||||
getAllBlobMetadataStrategyImplType);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,9 +234,9 @@ public class BlobStoreMapsModule extends AbstractModule {
|
||||||
bind(inputStreamMapFactoryType).toProvider(
|
bind(inputStreamMapFactoryType).toProvider(
|
||||||
FactoryProvider.newFactory(inputStreamMapFactoryType, inputStreamMapImplType)).in(
|
FactoryProvider.newFactory(inputStreamMapFactoryType, inputStreamMapImplType)).in(
|
||||||
Scopes.SINGLETON);
|
Scopes.SINGLETON);
|
||||||
bind(getAllBlobsStrategyType).to(getAllBlobsStrategyImplType).in(Scopes.SINGLETON);
|
for (Entry<TypeLiteral, TypeLiteral> entry : strategyImplMap.entrySet()) {
|
||||||
bind(getAllBlobMetadataStrategyType).to(getAllBlobMetadataStrategyImplType).in(
|
bind(entry.getKey()).to(entry.getValue()).in(Scopes.SINGLETON);
|
||||||
Scopes.SINGLETON);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -23,7 +23,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.blobstore.binders;
|
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 static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
@ -45,6 +45,7 @@ public class BlobBinder implements EntityBinder {
|
||||||
|
|
||||||
public void addEntityToRequest(Object entity, HttpRequest request) {
|
public void addEntityToRequest(Object entity, HttpRequest request) {
|
||||||
Blob<?> object = (Blob<?>) entity;
|
Blob<?> object = (Blob<?>) entity;
|
||||||
|
|
||||||
for (String key : object.getMetadata().getUserMetadata().keySet()) {
|
for (String key : object.getMetadata().getUserMetadata().keySet()) {
|
||||||
request.getHeaders().putAll(key.startsWith(metadataPrefix) ? key : metadataPrefix + key,
|
request.getHeaders().putAll(key.startsWith(metadataPrefix) ? key : metadataPrefix + key,
|
||||||
object.getMetadata().getUserMetadata().get(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;
|
package org.jclouds.blobstore.functions;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
|
||||||
import org.jclouds.blobstore.ContainerNotFoundException;
|
import org.jclouds.blobstore.ContainerNotFoundException;
|
||||||
import org.jclouds.blobstore.KeyNotFoundException;
|
import org.jclouds.blobstore.KeyNotFoundException;
|
||||||
import org.jclouds.http.functions.ReturnTrueOn404;
|
import org.jclouds.http.functions.ReturnTrueOn404;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
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();
|
ReturnTrueOn404 rto404 = new ReturnTrueOn404();
|
||||||
|
|
||||||
public Boolean apply(Exception from) {
|
public Void apply(Exception from) {
|
||||||
if (from instanceof KeyNotFoundException||from instanceof ContainerNotFoundException) {
|
if (from instanceof KeyNotFoundException || from instanceof ContainerNotFoundException) {
|
||||||
return true;
|
return v;
|
||||||
} else {
|
} 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.checkArgument;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
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.Set;
|
||||||
import java.util.SortedSet;
|
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.Inject;
|
||||||
import javax.inject.Named;
|
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.BlobMetadata;
|
||||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||||
import org.jclouds.blobstore.reference.BlobStoreConstants;
|
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.GetAllBlobMetadataStrategy;
|
||||||
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
||||||
import org.jclouds.rest.BoundedSortedSet;
|
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 Provider<B> blobFactory;
|
||||||
protected final GetAllBlobsStrategy<C, M, B> getAllBlobs;
|
protected final GetAllBlobsStrategy<C, M, B> getAllBlobs;
|
||||||
protected final GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata;
|
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
|
* maximum duration of an blob Request
|
||||||
|
@ -89,12 +88,18 @@ public abstract class BaseBlobMap<C extends ContainerMetadata, M extends BlobMet
|
||||||
@Inject
|
@Inject
|
||||||
public BaseBlobMap(BlobStore<C, M, B> connection, Provider<B> blobFactory,
|
public BaseBlobMap(BlobStore<C, M, B> connection, Provider<B> blobFactory,
|
||||||
GetAllBlobsStrategy<C, M, B> getAllBlobs,
|
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.connection = checkNotNull(connection, "connection");
|
||||||
this.containerName = checkNotNull(containerName, "container");
|
this.containerName = checkNotNull(containerName, "container");
|
||||||
this.blobFactory = checkNotNull(blobFactory, "blobFactory");
|
this.blobFactory = checkNotNull(blobFactory, "blobFactory");
|
||||||
this.getAllBlobs = checkNotNull(getAllBlobs, "getAllBlobs");
|
this.getAllBlobs = checkNotNull(getAllBlobs, "getAllBlobs");
|
||||||
this.getAllBlobMetadata = checkNotNull(getAllBlobMetadata, "getAllBlobMetadata");
|
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!");
|
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()
|
* @see BoundedSortedSet#getContents()
|
||||||
*/
|
*/
|
||||||
public int size() {
|
public int size() {
|
||||||
return getAllBlobMetadata.execute(connection, containerName).size();
|
return (int) containerCountStrategy.execute(connection, containerName);
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,9 +120,7 @@ public abstract class BaseBlobMap<C extends ContainerMetadata, M extends BlobMet
|
||||||
* @see BlobStore#getBlob(String, String)
|
* @see BlobStore#getBlob(String, String)
|
||||||
*/
|
*/
|
||||||
protected Set<B> getAllBlobs() {
|
protected Set<B> getAllBlobs() {
|
||||||
|
|
||||||
return getAllBlobs.execute(connection, containerName);
|
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
|
* method. To reuse data from InputStreams, pass {@link java.io.InputStream}s inside {@link Blob}s
|
||||||
*/
|
*/
|
||||||
public boolean containsValue(Object value) {
|
public boolean containsValue(Object value) {
|
||||||
return eTagExistsMatchingMD5Of(value);
|
return containsValueStrategy.execute(connection, containerName, 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
Set<Future<Boolean>> deletes = Sets.newHashSet();
|
clearContainerStrategy.execute(connection, containerName);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> keySet() {
|
public Set<String> keySet() {
|
||||||
|
|
|
@ -39,6 +39,9 @@ import org.jclouds.blobstore.KeyNotFoundException;
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
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.GetAllBlobMetadataStrategy;
|
||||||
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
||||||
import org.jclouds.util.Utils;
|
import org.jclouds.util.Utils;
|
||||||
|
@ -54,14 +57,18 @@ import com.google.inject.assistedinject.Assisted;
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @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> {
|
extends BaseBlobMap<C, M, B, B> implements BlobMap<M, B> {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public BlobMapImpl(S connection, Provider<B> blobFactory,
|
public BlobMapImpl(BlobStore<C, M, B> connection, Provider<B> blobFactory,
|
||||||
GetAllBlobsStrategy<C, M, B> getAllBlobs,
|
GetAllBlobsStrategy<C, M, B> getAllBlobs,
|
||||||
GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata, @Assisted String containerName) {
|
GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata,
|
||||||
super(connection, blobFactory, getAllBlobs, getAllBlobMetadata, containerName);
|
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.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
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.GetAllBlobMetadataStrategy;
|
||||||
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
||||||
import org.jclouds.util.Utils;
|
import org.jclouds.util.Utils;
|
||||||
|
@ -59,14 +62,18 @@ import com.google.inject.assistedinject.Assisted;
|
||||||
* @see InputStreamMap
|
* @see InputStreamMap
|
||||||
* @see BaseBlobMap
|
* @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> {
|
extends BaseBlobMap<C, M, B, InputStream> implements InputStreamMap<M> {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public InputStreamMapImpl(S connection, Provider<B> blobFactory,
|
public InputStreamMapImpl(BlobStore<C, M, B> connection, Provider<B> blobFactory,
|
||||||
GetAllBlobsStrategy<C, M, B> getAllBlobs,
|
GetAllBlobsStrategy<C, M, B> getAllBlobs,
|
||||||
GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata, @Assisted String containerName) {
|
GetAllBlobMetadataStrategy<C, M, B> getAllBlobMetadata,
|
||||||
super(connection, blobFactory, getAllBlobs, getAllBlobMetadata, containerName);
|
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.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
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.reference.BlobStoreConstants;
|
||||||
import org.jclouds.blobstore.strategy.GetAllBlobMetadataStrategy;
|
import org.jclouds.blobstore.strategy.GetAllBlobMetadataStrategy;
|
||||||
import org.jclouds.util.Utils;
|
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.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
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.reference.BlobStoreConstants;
|
||||||
import org.jclouds.blobstore.strategy.GetAllBlobMetadataStrategy;
|
import org.jclouds.blobstore.strategy.GetAllBlobMetadataStrategy;
|
||||||
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
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.integration.config.StubBlobStoreConnectionModule;
|
||||||
import org.jclouds.blobstore.internal.BlobMapImpl;
|
import org.jclouds.blobstore.internal.BlobMapImpl;
|
||||||
import org.jclouds.blobstore.internal.InputStreamMapImpl;
|
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.GetAllBlobMetadataStrategy;
|
||||||
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
|
||||||
import org.jclouds.blobstore.strategy.internal.ContainerListGetAllBlobMetadataStrategy;
|
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.jclouds.blobstore.strategy.internal.RetryOnNotFoundGetAllBlobsStrategy;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
@ -48,51 +54,58 @@ public class BlobStoreMapsModuleTest {
|
||||||
|
|
||||||
public void testBuilderBuild() {
|
public void testBuilderBuild() {
|
||||||
BlobStoreMapsModule module = BlobStoreMapsModule.Builder.newBuilder(
|
BlobStoreMapsModule module = BlobStoreMapsModule.Builder.newBuilder(
|
||||||
new TypeLiteral<BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
new TypeLiteral<ContainerMetadata>() {
|
||||||
}, new TypeLiteral<ContainerMetadata>() {
|
|
||||||
}, new TypeLiteral<BlobMetadata>() {
|
}, new TypeLiteral<BlobMetadata>() {
|
||||||
}, new TypeLiteral<Blob<BlobMetadata>>() {
|
}, new TypeLiteral<Blob<BlobMetadata>>() {
|
||||||
}).build();
|
}).build();
|
||||||
assertEquals(module.blobMapFactoryType,
|
assertEquals(module.blobMapFactoryType,
|
||||||
new TypeLiteral<BlobMap.Factory<BlobMetadata, Blob<BlobMetadata>>>() {
|
new TypeLiteral<BlobMap.Factory<BlobMetadata, Blob<BlobMetadata>>>() {
|
||||||
});
|
});
|
||||||
assertEquals(
|
assertEquals(module.blobMapImplType,
|
||||||
module.blobMapImplType,
|
new TypeLiteral<BlobMapImpl<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||||
new TypeLiteral<BlobMapImpl<BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>, ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
|
||||||
});
|
});
|
||||||
assertEquals(module.inputStreamMapFactoryType,
|
assertEquals(module.inputStreamMapFactoryType,
|
||||||
new TypeLiteral<InputStreamMap.Factory<BlobMetadata>>() {
|
new TypeLiteral<InputStreamMap.Factory<BlobMetadata>>() {
|
||||||
});
|
});
|
||||||
assertEquals(
|
assertEquals(
|
||||||
module.inputStreamMapImplType,
|
module.inputStreamMapImplType,
|
||||||
new TypeLiteral<InputStreamMapImpl<BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>, ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
new TypeLiteral<InputStreamMapImpl<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||||
});
|
});
|
||||||
assertEquals(
|
assertEquals(
|
||||||
module.getAllBlobsStrategyType,
|
module.strategyImplMap
|
||||||
new TypeLiteral<GetAllBlobsStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
.get(new TypeLiteral<GetAllBlobsStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||||
});
|
}),
|
||||||
assertEquals(
|
|
||||||
module.getAllBlobsStrategyImplType,
|
|
||||||
new TypeLiteral<RetryOnNotFoundGetAllBlobsStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
new TypeLiteral<RetryOnNotFoundGetAllBlobsStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||||
});
|
});
|
||||||
assertEquals(
|
assertEquals(
|
||||||
module.getAllBlobMetadataStrategyType,
|
module.strategyImplMap
|
||||||
new TypeLiteral<GetAllBlobMetadataStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
.get(new TypeLiteral<GetAllBlobMetadataStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||||
|
}),
|
||||||
|
new TypeLiteral<ContainerListGetAllBlobMetadataStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
||||||
});
|
});
|
||||||
assertEquals(
|
assertEquals(
|
||||||
module.getAllBlobMetadataStrategyImplType,
|
module.strategyImplMap
|
||||||
new TypeLiteral<ContainerListGetAllBlobMetadataStrategy<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
.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() {
|
public void testInject() {
|
||||||
Injector i = Guice
|
Injector i = Guice.createInjector(new StubBlobStoreConnectionModule(),
|
||||||
.createInjector(
|
BlobStoreMapsModule.Builder.newBuilder(new TypeLiteral<ContainerMetadata>() {
|
||||||
new StubBlobStoreConnectionModule(),
|
|
||||||
BlobStoreMapsModule.Builder
|
|
||||||
.newBuilder(
|
|
||||||
new TypeLiteral<BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>>() {
|
|
||||||
}, new TypeLiteral<ContainerMetadata>() {
|
|
||||||
}, new TypeLiteral<BlobMetadata>() {
|
}, new TypeLiteral<BlobMetadata>() {
|
||||||
}, new TypeLiteral<Blob<BlobMetadata>>() {
|
}, new TypeLiteral<Blob<BlobMetadata>>() {
|
||||||
}).build());
|
}).build());
|
||||||
|
|
|
@ -79,7 +79,7 @@ public class StubBlobStoreContextBuilder
|
||||||
Provider<Blob<BlobMetadata>> blobProvider,
|
Provider<Blob<BlobMetadata>> blobProvider,
|
||||||
BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>> api) {
|
BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>> api) {
|
||||||
return new BlobStoreContextImpl<BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>, ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>(
|
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");
|
.create("http://localhost/blobstub"), "foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,6 @@ import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.jclouds.blobstore.BlobStore;
|
|
||||||
import org.jclouds.blobstore.ContainerNotFoundException;
|
import org.jclouds.blobstore.ContainerNotFoundException;
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
|
@ -59,7 +58,7 @@ import org.testng.annotations.Test;
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @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> {
|
extends BaseBlobStoreIntegrationTest<S, C, M, B> {
|
||||||
|
|
||||||
@Test(groups = { "integration", "live" })
|
@Test(groups = { "integration", "live" })
|
||||||
|
@ -76,12 +75,12 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
||||||
addObjectAndValidateContent(containerName, key);
|
addObjectAndValidateContent(containerName, key);
|
||||||
DateTime after = new DateTime().plusSeconds(1);
|
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);
|
TimeUnit.SECONDS);
|
||||||
validateContent(containerName, key);
|
validateContent(containerName, key);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
context.getApi().getBlob(containerName, key, ifModifiedSince(after)).get(10,
|
context.getBlobStore().getBlob(containerName, key, ifModifiedSince(after)).get(10,
|
||||||
TimeUnit.SECONDS);
|
TimeUnit.SECONDS);
|
||||||
validateContent(containerName, key);
|
validateContent(containerName, key);
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
|
@ -112,12 +111,12 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
||||||
addObjectAndValidateContent(containerName, key);
|
addObjectAndValidateContent(containerName, key);
|
||||||
DateTime after = new DateTime().plusSeconds(1);
|
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);
|
TimeUnit.SECONDS);
|
||||||
validateContent(containerName, key);
|
validateContent(containerName, key);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
context.getApi().getBlob(containerName, key, ifUnmodifiedSince(before)).get(10,
|
context.getBlobStore().getBlob(containerName, key, ifUnmodifiedSince(before)).get(10,
|
||||||
TimeUnit.SECONDS);
|
TimeUnit.SECONDS);
|
||||||
validateContent(containerName, key);
|
validateContent(containerName, key);
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
|
@ -145,12 +144,12 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
||||||
|
|
||||||
addObjectAndValidateContent(containerName, key);
|
addObjectAndValidateContent(containerName, key);
|
||||||
|
|
||||||
context.getApi().getBlob(containerName, key, ifETagMatches(goodETag)).get(10,
|
context.getBlobStore().getBlob(containerName, key, ifETagMatches(goodETag)).get(10,
|
||||||
TimeUnit.SECONDS);
|
TimeUnit.SECONDS);
|
||||||
validateContent(containerName, key);
|
validateContent(containerName, key);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
context.getApi().getBlob(containerName, key, ifETagMatches(badETag)).get(10,
|
context.getBlobStore().getBlob(containerName, key, ifETagMatches(badETag)).get(10,
|
||||||
TimeUnit.SECONDS);
|
TimeUnit.SECONDS);
|
||||||
validateContent(containerName, key);
|
validateContent(containerName, key);
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
|
@ -178,12 +177,12 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
||||||
|
|
||||||
addObjectAndValidateContent(containerName, key);
|
addObjectAndValidateContent(containerName, key);
|
||||||
|
|
||||||
context.getApi().getBlob(containerName, key, ifETagDoesntMatch(badETag)).get(10,
|
context.getBlobStore().getBlob(containerName, key, ifETagDoesntMatch(badETag)).get(10,
|
||||||
TimeUnit.SECONDS);
|
TimeUnit.SECONDS);
|
||||||
validateContent(containerName, key);
|
validateContent(containerName, key);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
context.getApi().getBlob(containerName, key, ifETagDoesntMatch(goodETag)).get(10,
|
context.getBlobStore().getBlob(containerName, key, ifETagDoesntMatch(goodETag)).get(10,
|
||||||
TimeUnit.SECONDS);
|
TimeUnit.SECONDS);
|
||||||
validateContent(containerName, key);
|
validateContent(containerName, key);
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
|
@ -208,13 +207,13 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
||||||
String key = "apples";
|
String key = "apples";
|
||||||
|
|
||||||
addObjectAndValidateContent(containerName, key);
|
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);
|
TimeUnit.SECONDS);
|
||||||
assertEquals(BlobStoreUtils.getContentAsStringAndClose(object1), TEST_STRING.substring(0,
|
assertEquals(BlobStoreUtils.getContentAsStringAndClose(object1), TEST_STRING.substring(0,
|
||||||
6));
|
6));
|
||||||
|
|
||||||
B object2 = context.getApi().getBlob(containerName, key, range(6, TEST_STRING.length()))
|
B object2 = context.getBlobStore().getBlob(containerName, key,
|
||||||
.get(10, TimeUnit.SECONDS);
|
range(6, TEST_STRING.length())).get(10, TimeUnit.SECONDS);
|
||||||
assertEquals(BlobStoreUtils.getContentAsStringAndClose(object2), TEST_STRING.substring(6,
|
assertEquals(BlobStoreUtils.getContentAsStringAndClose(object2), TEST_STRING.substring(6,
|
||||||
TEST_STRING.length()));
|
TEST_STRING.length()));
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -231,7 +230,7 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
||||||
String key = "apples";
|
String key = "apples";
|
||||||
|
|
||||||
addObjectAndValidateContent(containerName, key);
|
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);
|
range(0, 5).range(6, TEST_STRING.length())).get(10, TimeUnit.SECONDS);
|
||||||
|
|
||||||
assertEquals(BlobStoreUtils.getContentAsStringAndClose(object), TEST_STRING);
|
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";
|
String key = "apples";
|
||||||
|
|
||||||
addObjectAndValidateContent(containerName, key);
|
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
|
assertEquals(BlobStoreUtils.getContentAsStringAndClose(object), TEST_STRING
|
||||||
.substring(TEST_STRING.length() - 5));
|
.substring(TEST_STRING.length() - 5));
|
||||||
assertEquals(object.getContentLength(), 5);
|
assertEquals(object.getContentLength(), 5);
|
||||||
|
@ -267,7 +267,7 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
||||||
String key = "apples";
|
String key = "apples";
|
||||||
|
|
||||||
addObjectAndValidateContent(containerName, key);
|
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);
|
TimeUnit.SECONDS);
|
||||||
assertEquals(BlobStoreUtils.getContentAsStringAndClose(object), TEST_STRING.substring(5,
|
assertEquals(BlobStoreUtils.getContentAsStringAndClose(object), TEST_STRING.substring(5,
|
||||||
TEST_STRING.length()));
|
TEST_STRING.length()));
|
||||||
|
@ -289,7 +289,7 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
||||||
String containerName = getContainerName();
|
String containerName = getContainerName();
|
||||||
String key = "test";
|
String key = "test";
|
||||||
try {
|
try {
|
||||||
assert context.getApi().removeBlob(containerName, key).get(10, TimeUnit.SECONDS);
|
context.getBlobStore().removeBlob(containerName, key).get(10, TimeUnit.SECONDS);
|
||||||
} finally {
|
} finally {
|
||||||
returnContainer(containerName);
|
returnContainer(containerName);
|
||||||
}
|
}
|
||||||
|
@ -305,7 +305,7 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
||||||
String containerName = getContainerName();
|
String containerName = getContainerName();
|
||||||
try {
|
try {
|
||||||
addBlobToContainer(containerName, key);
|
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);
|
assertContainerEmptyDeleting(containerName, key);
|
||||||
} finally {
|
} finally {
|
||||||
returnContainer(containerName);
|
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)
|
private void assertContainerEmptyDeleting(String containerName, String key)
|
||||||
throws InterruptedException, ExecutionException, TimeoutException {
|
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(
|
assertEquals(listing.size(), 0, String.format(
|
||||||
"deleting %s, we still have %s left in container %s, using encoding %s", key,
|
"deleting %s, we still have %s left in container %s, using encoding %s", key,
|
||||||
listing.size(), containerName, LOCAL_ENCODING));
|
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" })
|
@Test(groups = { "integration", "live" })
|
||||||
public void deleteObjectNoContainer() throws Exception {
|
public void deleteObjectNoContainer() throws Exception {
|
||||||
try {
|
try {
|
||||||
context.getApi().removeBlob("donb", "test").get(10, TimeUnit.SECONDS);
|
context.getBlobStore().removeBlob("donb", "test").get(10, TimeUnit.SECONDS);
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
assert (e.getCause() instanceof HttpResponseException || e.getCause() instanceof ContainerNotFoundException);
|
assert (e.getCause() instanceof HttpResponseException || e.getCause() instanceof ContainerNotFoundException);
|
||||||
if (e.getCause() instanceof HttpResponseException)
|
if (e.getCause() instanceof HttpResponseException)
|
||||||
|
@ -352,12 +353,14 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
||||||
}
|
}
|
||||||
String containerName = getContainerName();
|
String containerName = getContainerName();
|
||||||
try {
|
try {
|
||||||
assertNotNull(context.getApi().putBlob(containerName, object).get(10, TimeUnit.SECONDS));
|
assertNotNull(context.getBlobStore().putBlob(containerName, object).get(10,
|
||||||
object = context.getApi().getBlob(containerName, object.getKey())
|
TimeUnit.SECONDS));
|
||||||
.get(10, TimeUnit.SECONDS);
|
object = context.getBlobStore().getBlob(containerName, object.getKey()).get(10,
|
||||||
|
TimeUnit.SECONDS);
|
||||||
String returnedString = BlobStoreUtils.getContentAsStringAndClose(object);
|
String returnedString = BlobStoreUtils.getContentAsStringAndClose(object);
|
||||||
assertEquals(returnedString, realObject);
|
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 {
|
} finally {
|
||||||
returnContainer(containerName);
|
returnContainer(containerName);
|
||||||
}
|
}
|
||||||
|
@ -383,7 +386,7 @@ public class BaseBlobIntegrationTest<S extends BlobStore<C, M, B>, C extends Con
|
||||||
M metadata = newObject.getMetadata();
|
M metadata = newObject.getMetadata();
|
||||||
|
|
||||||
validateMetadata(metadata);
|
validateMetadata(metadata);
|
||||||
validateMetadata(context.getApi().blobMetadata(containerName, key));
|
validateMetadata(context.getBlobStore().blobMetadata(containerName, key));
|
||||||
} finally {
|
} finally {
|
||||||
returnContainer(containerName);
|
returnContainer(containerName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.jclouds.blobstore.BlobStore;
|
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||||
|
@ -48,7 +47,7 @@ import org.testng.annotations.Test;
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Test(groups = { "live" }, testName = "blobstore.BlobLiveTest")
|
@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> {
|
extends BaseBlobStoreIntegrationTest<S, C, M, B> {
|
||||||
|
|
||||||
private static final String sysHttpStreamUrl = System
|
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);
|
object.getMetadata().setSize(length);
|
||||||
String bucketName = getContainerName();
|
String bucketName = getContainerName();
|
||||||
try {
|
try {
|
||||||
context.getApi().putBlob(bucketName, object).get(180, TimeUnit.SECONDS);
|
context.getBlobStore().putBlob(bucketName, object).get(180, TimeUnit.SECONDS);
|
||||||
assertEquals(context.getApi().blobMetadata(bucketName, key).getContentMD5(), md5);
|
assertEquals(context.getBlobStore().blobMetadata(bucketName, key).getContentMD5(), md5);
|
||||||
} finally {
|
} finally {
|
||||||
returnContainer(bucketName);
|
returnContainer(bucketName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,6 @@ import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.jclouds.blobstore.BlobStore;
|
|
||||||
import org.jclouds.blobstore.BlobStoreContext;
|
import org.jclouds.blobstore.BlobStoreContext;
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
|
@ -50,7 +49,7 @@ import org.testng.annotations.Test;
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @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> {
|
extends BaseMapIntegrationTest<S, C, M, B, B> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -27,8 +27,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.concurrent.ArrayBlockingQueue;
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
@ -41,13 +39,11 @@ import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import org.jclouds.blobstore.BlobStore;
|
|
||||||
import org.jclouds.blobstore.BlobStoreContext;
|
import org.jclouds.blobstore.BlobStoreContext;
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||||
import org.jclouds.blobstore.util.BlobStoreUtils;
|
import org.jclouds.blobstore.util.BlobStoreUtils;
|
||||||
import org.jclouds.http.HttpResponseException;
|
|
||||||
import org.jclouds.http.HttpUtils;
|
import org.jclouds.http.HttpUtils;
|
||||||
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
||||||
import org.jclouds.util.Utils;
|
import org.jclouds.util.Utils;
|
||||||
|
@ -62,7 +58,7 @@ import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.inject.Module;
|
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 LOCAL_ENCODING = System.getProperty("file.encoding");
|
||||||
protected static final String TEST_STRING = "<apples><apple name=\"fuji\"></apple> </apples>";
|
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;
|
protected ExecutorService exec;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* we are doing this at a class level, as the context.getApi() object is going to be shared for
|
* we are doing this at a class level, as the context.getBlobStore() object is going to be shared
|
||||||
* all methods in the class. We don't want to do this for group, as some test classes may want to
|
* for all methods in the class. We don't want to do this for group, as some test classes may
|
||||||
* have a different implementation of context.getApi(). For example, one class may want
|
* want to have a different implementation of context.getBlobStore(). For example, one class may
|
||||||
* non-blocking i/o and another class google appengine.
|
* want non-blocking i/o and another class google appengine.
|
||||||
*/
|
*/
|
||||||
@BeforeClass(groups = { "integration", "live" })
|
@BeforeClass(groups = { "integration", "live" })
|
||||||
public void setUpResourcesOnThisThread(ITestContext testContext) throws Exception {
|
public void setUpResourcesOnThisThread(ITestContext testContext) throws Exception {
|
||||||
|
@ -182,7 +178,7 @@ public class BaseBlobStoreIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
Iterable<ContainerMetadata> testContainers = Iterables.filter(
|
Iterable<ContainerMetadata> testContainers = Iterables.filter(
|
||||||
(SortedSet<ContainerMetadata>) context.getApi().listContainers(),
|
(SortedSet<ContainerMetadata>) context.getBlobStore().listContainers(),
|
||||||
new Predicate<ContainerMetadata>() {
|
new Predicate<ContainerMetadata>() {
|
||||||
public boolean apply(ContainerMetadata input) {
|
public boolean apply(ContainerMetadata input) {
|
||||||
return input.getName().startsWith(CONTAINER_PREFIX.toLowerCase());
|
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,
|
protected static void createContainerAndEnsureEmpty(BlobStoreContext<?, ?, ?, ?> context,
|
||||||
final String containerName) throws InterruptedException, ExecutionException,
|
final String containerName) throws InterruptedException, ExecutionException,
|
||||||
TimeoutException {
|
TimeoutException {
|
||||||
attemptToCreateContainerButRetryOn409(context, containerName);
|
context.getBlobStore().createContainer(containerName).get(30, TimeUnit.SECONDS);
|
||||||
emptyContainer(context, containerName);
|
context.createInputStreamMap(containerName).clear();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void createContainerAndEnsureEmpty(String containerName) throws InterruptedException,
|
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,
|
protected void addBlobToContainer(String sourceContainer, B object) throws InterruptedException,
|
||||||
ExecutionException, TimeoutException, IOException {
|
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,
|
protected B validateContent(String sourceContainer, String key) throws InterruptedException,
|
||||||
ExecutionException, TimeoutException, IOException {
|
ExecutionException, TimeoutException, IOException {
|
||||||
assertEventuallyContainerSize(sourceContainer, 1);
|
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;
|
assert newObject != null;
|
||||||
assertEquals(BlobStoreUtils.getContentAsStringAndClose(newObject), TEST_STRING);
|
assertEquals(BlobStoreUtils.getContentAsStringAndClose(newObject), TEST_STRING);
|
||||||
return newObject;
|
return newObject;
|
||||||
|
@ -304,8 +266,8 @@ public class BaseBlobStoreIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
||||||
assertEventually(new Runnable() {
|
assertEventually(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
assertEquals(context.getApi().listBlobs(containerName).get(10, TimeUnit.SECONDS)
|
assertEquals(context.getBlobStore().listBlobs(containerName).get(10,
|
||||||
.size(), count);
|
TimeUnit.SECONDS).size(), count);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||||
}
|
}
|
||||||
|
@ -317,8 +279,7 @@ public class BaseBlobStoreIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
||||||
TimeoutException {
|
TimeoutException {
|
||||||
String containerName = containerJsr330.poll(30, TimeUnit.SECONDS);
|
String containerName = containerJsr330.poll(30, TimeUnit.SECONDS);
|
||||||
assert containerName != null : "unable to get a container for the test";
|
assert containerName != null : "unable to get a container for the test";
|
||||||
if (!emptyContainer(containerName))
|
createContainerAndEnsureEmpty(containerName);
|
||||||
this.createContainerAndEnsureEmpty(containerName);
|
|
||||||
return 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.
|
* *substantially* slow down tests on a real server over a network.
|
||||||
*/
|
*/
|
||||||
if (SANITY_CHECK_RETURNED_BUCKET_NAME) {
|
if (SANITY_CHECK_RETURNED_BUCKET_NAME) {
|
||||||
if (!Iterables.any(context.getApi().listContainers(),
|
if (!Iterables.any(context.getBlobStore().listContainers(),
|
||||||
new Predicate<ContainerMetadata>() {
|
new Predicate<ContainerMetadata>() {
|
||||||
public boolean apply(ContainerMetadata md) {
|
public boolean apply(ContainerMetadata md) {
|
||||||
return containerName.equals(md.getName());
|
return containerName.equals(md.getName());
|
||||||
|
@ -396,60 +357,15 @@ public class BaseBlobStoreIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
||||||
return new JavaUrlHttpCommandExecutorServiceModule();
|
return new JavaUrlHttpCommandExecutorServiceModule();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean emptyContainer(String name) throws InterruptedException, ExecutionException,
|
protected static void deleteContainer(final BlobStoreContext<?, ?, ?, ?> context,
|
||||||
TimeoutException {
|
|
||||||
return emptyContainer(context, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove any objects in a container, leaving it empty.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
protected static boolean emptyContainer(final BlobStoreContext<?, ?, ?, ?> context,
|
|
||||||
final String name) throws InterruptedException, ExecutionException, TimeoutException {
|
final String name) throws InterruptedException, ExecutionException, TimeoutException {
|
||||||
if (context.getApi().containerExists(name)) {
|
if (context.getBlobStore().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)) {
|
|
||||||
System.err.printf("*** deleting container %s...%n", name);
|
System.err.printf("*** deleting container %s...%n", name);
|
||||||
emptyContainer(context, name);
|
context.getBlobStore().deleteContainer(name).get(10, TimeUnit.SECONDS);
|
||||||
context.getApi().deleteContainer(name).get(10, TimeUnit.SECONDS);
|
|
||||||
assertEventually(new Runnable() {
|
assertEventually(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
assert !context.getApi().containerExists(name) : "container " + name
|
assert !context.getBlobStore().containerExists(name) : "container " + name
|
||||||
+ " still exists";
|
+ " still exists";
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||||
|
|
|
@ -31,7 +31,6 @@ import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import org.jclouds.blobstore.BlobStore;
|
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||||
|
@ -41,20 +40,20 @@ import org.testng.annotations.Test;
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @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> {
|
extends BaseBlobStoreIntegrationTest<S, C, M, B> {
|
||||||
|
|
||||||
@Test(groups = { "integration", "live" })
|
@Test(groups = { "integration", "live" })
|
||||||
public void containerDoesntExist() throws Exception {
|
public void containerDoesntExist() throws Exception {
|
||||||
assert !context.getApi().containerExists("forgetaboutit");
|
assert !context.getBlobStore().containerExists("forgetaboutit");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(groups = { "integration", "live" })
|
@Test(groups = { "integration", "live" })
|
||||||
public void testPutTwiceIsOk() throws Exception {
|
public void testPutTwiceIsOk() throws Exception {
|
||||||
String containerName = getContainerName();
|
String containerName = getContainerName();
|
||||||
try {
|
try {
|
||||||
context.getApi().createContainer(containerName).get(10, TimeUnit.SECONDS);
|
context.getBlobStore().createContainer(containerName).get(10, TimeUnit.SECONDS);
|
||||||
context.getApi().createContainer(containerName).get(10, TimeUnit.SECONDS);
|
context.getBlobStore().createContainer(containerName).get(10, TimeUnit.SECONDS);
|
||||||
} finally {
|
} finally {
|
||||||
returnContainer(containerName);
|
returnContainer(containerName);
|
||||||
}
|
}
|
||||||
|
@ -64,28 +63,21 @@ public class BaseContainerIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
||||||
public void containerExists() throws Exception {
|
public void containerExists() throws Exception {
|
||||||
String containerName = getContainerName();
|
String containerName = getContainerName();
|
||||||
try {
|
try {
|
||||||
assert context.getApi().containerExists(containerName);
|
assert context.getBlobStore().containerExists(containerName);
|
||||||
} finally {
|
} finally {
|
||||||
returnContainer(containerName);
|
returnContainer(containerName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* this method overrides containerName to ensure it isn't found
|
|
||||||
*/
|
|
||||||
@Test(groups = { "integration", "live" })
|
@Test(groups = { "integration", "live" })
|
||||||
public void deleteContainerIfEmptyNotFound() throws Exception {
|
public void deleteContainerWithContents() throws Exception {
|
||||||
assert context.getApi().deleteContainer("dbienf").get(10, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(groups = { "integration", "live" })
|
|
||||||
public void deleteContainerIfEmptyButHasContents() throws Exception {
|
|
||||||
String containerName = getContainerName();
|
String containerName = getContainerName();
|
||||||
try {
|
try {
|
||||||
addBlobToContainer(containerName, "test");
|
addBlobToContainer(containerName, "test");
|
||||||
assert !context.getApi().deleteContainer(containerName).get(10, TimeUnit.SECONDS);
|
context.getBlobStore().deleteContainer(containerName).get(10, TimeUnit.SECONDS);
|
||||||
|
assertNotExists(containerName);
|
||||||
} finally {
|
} 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 {
|
public void deleteContainerIfEmpty() throws Exception {
|
||||||
final String containerName = getContainerName();
|
final String containerName = getContainerName();
|
||||||
try {
|
try {
|
||||||
assert context.getApi().deleteContainer(containerName).get(10, TimeUnit.SECONDS);
|
context.getBlobStore().deleteContainer(containerName).get(10, TimeUnit.SECONDS);
|
||||||
|
assertNotExists(containerName);
|
||||||
assertEventually(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
assert !context.getApi().containerExists(containerName) : "container "
|
|
||||||
+ containerName + " still exists";
|
|
||||||
} catch (Exception e) {
|
|
||||||
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} finally {
|
} finally {
|
||||||
// this container is now deleted, so we can't reuse it directly
|
// this container is now deleted, so we can't reuse it directly
|
||||||
recycleContainer(containerName);
|
recycleContainer(containerName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addAlphabetUnderRoot(String containerName) throws InterruptedException,
|
private void assertNotExists(final String containerName) throws InterruptedException {
|
||||||
ExecutionException, TimeoutException {
|
assertEventually(new Runnable() {
|
||||||
for (char letter = 'a'; letter <= 'z'; letter++) {
|
public void run() {
|
||||||
B blob = context.newBlob(letter + "");
|
try {
|
||||||
blob.setData(letter + "content");
|
assert !context.getBlobStore().containerExists(containerName) : "container "
|
||||||
context.getApi().putBlob(containerName, blob).get(10, TimeUnit.SECONDS);
|
+ containerName + " still exists";
|
||||||
|
} catch (Exception e) {
|
||||||
|
Utils.<RuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Test(groups = { "integration", "live" })
|
@Test(groups = { "integration", "live" })
|
||||||
public void testListContainer() throws InterruptedException, ExecutionException,
|
public void testListContainer() throws InterruptedException, ExecutionException,
|
||||||
|
@ -126,7 +112,7 @@ public class BaseContainerIntegrationTest<S extends BlobStore<C, M, B>, C extend
|
||||||
String containerName = getContainerName();
|
String containerName = getContainerName();
|
||||||
try {
|
try {
|
||||||
add15UnderRoot(containerName);
|
add15UnderRoot(containerName);
|
||||||
SortedSet<M> container = context.getApi().listBlobs(containerName).get(10,
|
SortedSet<M> container = context.getBlobStore().listBlobs(containerName).get(10,
|
||||||
TimeUnit.SECONDS);
|
TimeUnit.SECONDS);
|
||||||
assertEquals(container.size(), 15);
|
assertEquals(container.size(), 15);
|
||||||
} finally {
|
} 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,
|
protected void add15UnderRoot(String containerName) throws InterruptedException,
|
||||||
ExecutionException, TimeoutException {
|
ExecutionException, TimeoutException {
|
||||||
for (int i = 0; i < 15; i++) {
|
for (int i = 0; i < 15; i++) {
|
||||||
B blob = context.newBlob(i + "");
|
B blob = context.newBlob(i + "");
|
||||||
blob.setData(i + "content");
|
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++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
B blob = context.newBlob(prefix + "/" + i);
|
B blob = context.newBlob(prefix + "/" + i);
|
||||||
blob.setData(i + "content");
|
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;
|
package org.jclouds.blobstore.integration.internal;
|
||||||
|
|
||||||
import org.jclouds.blobstore.BlobStore;
|
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||||
|
@ -32,7 +31,7 @@ import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @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> {
|
extends BaseBlobStoreIntegrationTest<S, C, M, B> {
|
||||||
|
|
||||||
}
|
}
|
|
@ -37,7 +37,6 @@ import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.jclouds.blobstore.BlobStore;
|
|
||||||
import org.jclouds.blobstore.BlobStoreContext;
|
import org.jclouds.blobstore.BlobStoreContext;
|
||||||
import org.jclouds.blobstore.InputStreamMap;
|
import org.jclouds.blobstore.InputStreamMap;
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
|
@ -51,7 +50,7 @@ import org.testng.annotations.Test;
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @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> {
|
extends BaseMapIntegrationTest<S, C, M, B, InputStream> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -37,7 +37,6 @@ import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.jclouds.blobstore.BlobStore;
|
|
||||||
import org.jclouds.blobstore.BlobStoreContext;
|
import org.jclouds.blobstore.BlobStoreContext;
|
||||||
import org.jclouds.blobstore.ListableMap;
|
import org.jclouds.blobstore.ListableMap;
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
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.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
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> {
|
extends BaseBlobStoreIntegrationTest<S, C, M, B> {
|
||||||
|
|
||||||
public abstract void testPutAll() throws InterruptedException, ExecutionException,
|
public abstract void testPutAll() throws InterruptedException, ExecutionException,
|
||||||
|
|
|
@ -25,7 +25,6 @@ package org.jclouds.blobstore.integration.internal;
|
||||||
|
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
|
|
||||||
import org.jclouds.blobstore.BlobStore;
|
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
import org.jclouds.blobstore.domain.ContainerMetadata;
|
import org.jclouds.blobstore.domain.ContainerMetadata;
|
||||||
|
@ -35,12 +34,12 @@ import org.testng.annotations.Test;
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @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> {
|
extends BaseBlobStoreIntegrationTest<S, C, M, B> {
|
||||||
|
|
||||||
@Test(groups = { "integration", "live" })
|
@Test(groups = { "integration", "live" })
|
||||||
void containerDoesntExist() throws Exception {
|
void containerDoesntExist() throws Exception {
|
||||||
SortedSet<C> list = context.getApi().listContainers();
|
SortedSet<C> list = context.getBlobStore().listContainers();
|
||||||
assert !list.contains(new ContainerMetadata("shouldntexist"));
|
assert !list.contains(new ContainerMetadata("shouldntexist"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.blobstore.integration.internal;
|
package org.jclouds.blobstore.integration.internal;
|
||||||
|
|
||||||
import org.jclouds.blobstore.BlobStore;
|
|
||||||
import org.jclouds.blobstore.BlobStoreContext;
|
import org.jclouds.blobstore.BlobStoreContext;
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
|
@ -32,7 +31,7 @@ import org.testng.ITestContext;
|
||||||
|
|
||||||
import com.google.inject.Module;
|
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)
|
public BlobStoreContext<S, C, M, B> init(Module configurationModule, ITestContext testContext)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
|
@ -199,18 +199,29 @@ public class StubBlobStore<C extends ContainerMetadata, M extends BlobMetadata,
|
||||||
return realContents.get(key).getMetadata();
|
return realContents.get(key).getMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Future<Boolean> removeBlob(final String container, final String key) {
|
public Future<Void> removeBlob(final String container, final String key) {
|
||||||
return new FutureBase<Boolean>() {
|
return new FutureBase<Void>() {
|
||||||
public Boolean get() throws InterruptedException, ExecutionException {
|
public Void get() throws InterruptedException, ExecutionException {
|
||||||
if (getContainerToBlobs().containsKey(container)) {
|
if (getContainerToBlobs().containsKey(container)) {
|
||||||
getContainerToBlobs().get(container).remove(key);
|
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>() {
|
return new FutureBase<Boolean>() {
|
||||||
public Boolean get() throws InterruptedException, ExecutionException {
|
public Boolean get() throws InterruptedException, ExecutionException {
|
||||||
if (getContainerToBlobs().containsKey(container)) {
|
if (getContainerToBlobs().containsKey(container)) {
|
||||||
|
@ -385,6 +396,7 @@ public class StubBlobStore<C extends ContainerMetadata, M extends BlobMetadata,
|
||||||
byte[] data = toByteArray(object.getData());
|
byte[] data = toByteArray(object.getData());
|
||||||
final byte[] eTag = HttpUtils.md5(data);
|
final byte[] eTag = HttpUtils.md5(data);
|
||||||
newMd.setETag(eTag);
|
newMd.setETag(eTag);
|
||||||
|
newMd.setContentMD5(eTag);
|
||||||
newMd.setContentType(object.getMetadata().getContentType());
|
newMd.setContentType(object.getMetadata().getContentType());
|
||||||
|
|
||||||
B blob = blobProvider.get();
|
B blob = blobProvider.get();
|
||||||
|
|
|
@ -52,13 +52,13 @@ public class BaseBlobMapTest {
|
||||||
|
|
||||||
BlobStoreContext<BlobStore<ContainerMetadata, BlobMetadata, Blob<BlobMetadata>>, ContainerMetadata, BlobMetadata, Blob<BlobMetadata>> context;
|
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")
|
@SuppressWarnings("unchecked")
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
void addDefaultObjectsSoThatTestsWillPass() {
|
void addDefaultObjectsSoThatTestsWillPass() {
|
||||||
context = new StubBlobStoreContextBuilder().buildContext();
|
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");
|
.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.
|
* 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;
|
import com.google.common.base.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Simply returns the InputStream of the response
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public class ReturnTrueIfContainerNotFound implements Function<Exception, Boolean> {
|
public class ReturnInputStream implements Function<HttpResponse, InputStream> {
|
||||||
|
|
||||||
public Boolean apply(Exception from) {
|
public InputStream apply(HttpResponse from) {
|
||||||
if (from instanceof ContainerNotFoundException) {
|
return from.getContent();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
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) {
|
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,
|
logger.debug("Retry %1$d/%2$d after server error, delaying for %3$d ms: %4$s", failureCount,
|
||||||
retryCountLimit, delayMs, commandDescription);
|
retryCountLimit, delayMs, commandDescription);
|
||||||
try {
|
try {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue