You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ga...@apache.org on 2013/07/17 19:37:46 UTC
[1/3] git commit: JCLOUDS-161: large blob support for Azure
Updated Branches:
refs/heads/1.6.x 6c8679af6 -> 2ebde8c55
JCLOUDS-161: large blob support for Azure
Large blob support for AzureClient; the next step of this is to
support PutOptions.multipart and digest a blob into 4M parts. This
just implements the Azure interaction.
Project: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/commit/3a734b89
Tree: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/tree/3a734b89
Diff: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/diff/3a734b89
Branch: refs/heads/1.6.x
Commit: 3a734b897c821b3e34afc8c9e45aa791eaad32c4
Parents: 6c8679a
Author: John Kew <jo...@socrata.com>
Authored: Tue Jul 2 14:22:02 2013 -0700
Committer: Andrew Gaul <ga...@apache.org>
Committed: Wed Jul 17 10:35:13 2013 -0700
----------------------------------------------------------------------
.../jclouds/azureblob/AzureBlobAsyncClient.java | 43 +++++++++
.../org/jclouds/azureblob/AzureBlobClient.java | 28 ++++++
.../binders/BindAzureBlocksToRequest.java | 49 ++++++++++
.../blobstore/AzureAsyncBlobStore.java | 46 ++++++++-
.../azureblob/blobstore/AzureBlobStore.java | 40 +++++++-
.../strategy/AzureBlobBlockUploadStrategy.java | 87 +++++++++++++++++
.../strategy/MultipartUploadStrategy.java | 36 +++++++
.../org/jclouds/azureblob/domain/AzureBlob.java | 2 +-
.../azureblob/domain/BlobBlockProperties.java | 28 ++++++
.../domain/ListBlobBlocksResponse.java | 28 ++++++
.../internal/BlobBlockPropertiesImpl.java | 66 +++++++++++++
.../internal/ListBlobBlocksResponseImpl.java | 56 +++++++++++
.../predicates/validators/BlockIdValidator.java | 41 ++++++++
.../azureblob/xml/BlobBlocksResultsHandler.java | 98 ++++++++++++++++++++
.../azureblob/AzureBlobClientLiveTest.java | 33 ++++++-
.../AzureBlobIntegrationLiveTest.java | 40 ++++++++
.../AzureBlobBlockUploadStrategyTest.java | 74 +++++++++++++++
.../xml/BlobBlocksResultsHandlerTest.java | 59 ++++++++++++
.../test/resources/test_list_blob_blocks.xml | 23 +++++
19 files changed, 871 insertions(+), 6 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobAsyncClient.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobAsyncClient.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobAsyncClient.java
index 94db993..6f69739 100644
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobAsyncClient.java
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobAsyncClient.java
@@ -18,6 +18,7 @@ package org.jclouds.azureblob;
import static com.google.common.net.HttpHeaders.EXPECT;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@@ -28,6 +29,7 @@ import javax.ws.rs.HEAD;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
+import javax.ws.rs.QueryParam;
import org.jclouds.Fallbacks.TrueOnNotFoundOr404;
import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
@@ -37,8 +39,10 @@ import org.jclouds.azure.storage.options.ListOptions;
import org.jclouds.azure.storage.reference.AzureStorageHeaders;
import org.jclouds.azureblob.AzureBlobFallbacks.FalseIfContainerAlreadyExists;
import org.jclouds.azureblob.binders.BindAzureBlobMetadataToRequest;
+import org.jclouds.azureblob.binders.BindAzureBlocksToRequest;
import org.jclouds.azureblob.domain.BlobProperties;
import org.jclouds.azureblob.domain.ContainerProperties;
+import org.jclouds.azureblob.domain.ListBlobBlocksResponse;
import org.jclouds.azureblob.domain.ListBlobsResponse;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.azureblob.functions.BlobName;
@@ -48,8 +52,10 @@ import org.jclouds.azureblob.functions.ParseContainerPropertiesFromHeaders;
import org.jclouds.azureblob.functions.ParsePublicAccessHeader;
import org.jclouds.azureblob.options.CreateContainerOptions;
import org.jclouds.azureblob.options.ListBlobsOptions;
+import org.jclouds.azureblob.predicates.validators.BlockIdValidator;
import org.jclouds.azureblob.predicates.validators.ContainerNameValidator;
import org.jclouds.azureblob.xml.AccountNameEnumerationResultsHandler;
+import org.jclouds.azureblob.xml.BlobBlocksResultsHandler;
import org.jclouds.azureblob.xml.ContainerNameEnumerationResultsHandler;
import org.jclouds.blobstore.BlobStoreFallbacks.FalseOnContainerNotFound;
import org.jclouds.blobstore.BlobStoreFallbacks.FalseOnKeyNotFound;
@@ -58,6 +64,7 @@ import org.jclouds.blobstore.BlobStoreFallbacks.NullOnKeyNotFound;
import org.jclouds.blobstore.binders.BindMapToHeadersWithPrefix;
import org.jclouds.http.functions.ParseETagHeader;
import org.jclouds.http.options.GetOptions;
+import org.jclouds.io.Payload;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.Headers;
@@ -284,4 +291,40 @@ public interface AzureBlobAsyncClient {
@PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
@PathParam("name") String name);
+
+ /**
+ * @see AzureBlobClient#putBlock
+ */
+ @Named("PutBlock")
+ @PUT
+ @Path("{container}/{name}")
+ @QueryParams(keys = { "comp" }, values = { "block" })
+ ListenableFuture<Void> putBlock(@PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
+ @PathParam("name") String name,
+ @QueryParam("blockid") @ParamValidators(BlockIdValidator.class) String blockId, Payload part);
+
+
+ /**
+ * @see AzureBlobClient#putBlockList
+ */
+ @Named("PutBlockList")
+ @PUT
+ @Path("{container}/{name}")
+ @ResponseParser(ParseETagHeader.class)
+ @QueryParams(keys = { "comp" }, values = { "blocklist" })
+ ListenableFuture<String> putBlockList(@PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
+ @PathParam("name") String name,
+ @BinderParam(BindAzureBlocksToRequest.class) List<String> blockIdList);
+
+ /**
+ * @see AzureBlobClient#getBlockList
+ */
+ @Named("GetBlockList")
+ @GET
+ @Path("{container}/{name}")
+ @XMLResponseParser(BlobBlocksResultsHandler.class)
+ @QueryParams(keys = { "comp" }, values = { "blocklist" })
+ ListenableFuture<ListBlobBlocksResponse> getBlockList(@PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
+ @PathParam("name") String name);
+
}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobClient.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobClient.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobClient.java
index 54cd605..6a18881 100644
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobClient.java
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobClient.java
@@ -16,12 +16,14 @@
*/
package org.jclouds.azureblob;
+import java.util.List;
import java.util.Map;
import org.jclouds.azure.storage.domain.BoundedSet;
import org.jclouds.azure.storage.options.ListOptions;
import org.jclouds.azureblob.domain.AzureBlob;
import org.jclouds.azureblob.domain.BlobProperties;
import org.jclouds.azureblob.domain.ContainerProperties;
+import org.jclouds.azureblob.domain.ListBlobBlocksResponse;
import org.jclouds.azureblob.domain.ListBlobsResponse;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.azureblob.options.CreateContainerOptions;
@@ -29,6 +31,7 @@ import org.jclouds.azureblob.options.ListBlobsOptions;
import org.jclouds.http.options.GetOptions;
import com.google.inject.Provides;
+import org.jclouds.io.Payload;
/**
* Provides access to Azure Blob via their REST API.
@@ -208,6 +211,31 @@ public interface AzureBlobClient {
AzureBlob getBlob(String container, String name, GetOptions... options);
/**
+ * The Put Block operation creates a block blob on Azure which can be later assembled into
+ * a single, large blob object with the Put Block List operation.
+ *
+ * @see <a href="http://msdn.microsoft.com/en-us/library/windowsazure/dd135726.aspx">Put Blob</a>
+ */
+ void putBlock(String container, String name, String blockId, Payload object);
+
+
+ /**
+ * The Put Block List assembles a list of blocks previously uploaded with Put Block into a single
+ * blob. Blocks are either already committed to a blob or uncommitted. The blocks ids passed here
+ * are searched for first in the uncommitted block list; then committed using the "latest" strategy.
+ *
+ * @see <a href="http://msdn.microsoft.com/en-us/library/windowsazure/dd179467.aspx">Put Block List</a>
+ */
+ String putBlockList(String container, String name, List<String> blockIdList);
+
+ /**
+ * Get Block ID List for a blob
+ *
+ * @see <a href="http://msdn.microsoft.com/en-us/library/windowsazure/dd179400.aspx">Get Block List</a>
+ */
+ ListBlobBlocksResponse getBlockList(String container, String name);
+
+ /**
* 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.
*/
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/main/java/org/jclouds/azureblob/binders/BindAzureBlocksToRequest.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/binders/BindAzureBlocksToRequest.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/binders/BindAzureBlocksToRequest.java
new file mode 100644
index 0000000..e22aa09
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/binders/BindAzureBlocksToRequest.java
@@ -0,0 +1,49 @@
+/*
+ * 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.azureblob.binders;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.Binder;
+
+import java.util.List;
+
+/**
+ * Binds a list of blocks to a putBlockList request
+ *
+ * <?xml version="1.0" encoding="utf-8"?>
+ * <BlockList>
+ * <Committed>first-base64-encoded-block-id</Committed>
+ * <Uncommitted>second-base64-encoded-block-id</Uncommitted>
+ * <Latest>third-base64-encoded-block-id</Latest>
+ * ...
+ * </BlockList>
+ */
+public class BindAzureBlocksToRequest implements Binder {
+ @Override
+ public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+ List<String> blockIds = (List<String>)input;
+ StringBuilder content = new StringBuilder();
+ content.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ content.append("<BlockList>");
+ for (String id : blockIds) {
+ content.append("<Latest>").append(id).append("</Latest>");
+ }
+ content.append("</BlockList>");
+ request.setPayload(content.toString());
+ return request;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureAsyncBlobStore.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureAsyncBlobStore.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureAsyncBlobStore.java
index 6ce8cf2..77c6ead 100644
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureAsyncBlobStore.java
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureAsyncBlobStore.java
@@ -20,10 +20,12 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.util.concurrent.Futures.transform;
import static org.jclouds.azure.storage.options.ListOptions.Builder.includeMetadata;
+import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
+import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.Constants;
@@ -35,9 +37,11 @@ import org.jclouds.azureblob.blobstore.functions.BlobToAzureBlob;
import org.jclouds.azureblob.blobstore.functions.ContainerToResourceMetadata;
import org.jclouds.azureblob.blobstore.functions.ListBlobsResponseToResourceList;
import org.jclouds.azureblob.blobstore.functions.ListOptionsToListBlobsOptions;
+import org.jclouds.azureblob.blobstore.strategy.MultipartUploadStrategy;
import org.jclouds.azureblob.domain.AzureBlob;
import org.jclouds.azureblob.domain.BlobProperties;
import org.jclouds.azureblob.domain.ContainerProperties;
+import org.jclouds.azureblob.domain.ListBlobBlocksResponse;
import org.jclouds.azureblob.domain.ListBlobsResponse;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.azureblob.options.ListBlobsOptions;
@@ -62,6 +66,7 @@ import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
+import org.jclouds.io.Payload;
/**
* @author Adrian Cole
@@ -79,6 +84,8 @@ public class AzureAsyncBlobStore extends BaseAsyncBlobStore {
private final BlobToAzureBlob blob2AzureBlob;
private final BlobPropertiesToBlobMetadata blob2BlobMd;
private final BlobToHttpGetOptions blob2ObjectGetOptions;
+ private final Provider<MultipartUploadStrategy> multipartUploadStrategy;
+
@Inject
AzureAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
@@ -88,7 +95,8 @@ public class AzureAsyncBlobStore extends BaseAsyncBlobStore {
ListOptionsToListBlobsOptions blobStore2AzureContainerListOptions,
ListBlobsResponseToResourceList azure2BlobStoreResourceList, AzureBlobToBlob azureBlob2Blob,
BlobToAzureBlob blob2AzureBlob, BlobPropertiesToBlobMetadata blob2BlobMd,
- BlobToHttpGetOptions blob2ObjectGetOptions) {
+ BlobToHttpGetOptions blob2ObjectGetOptions,
+ Provider<MultipartUploadStrategy> multipartUploadStrategy) {
super(context, blobUtils, userExecutor, defaultLocation, locations);
this.async = checkNotNull(async, "async");
this.container2ResourceMd = checkNotNull(container2ResourceMd, "container2ResourceMd");
@@ -99,6 +107,7 @@ public class AzureAsyncBlobStore extends BaseAsyncBlobStore {
this.blob2AzureBlob = checkNotNull(blob2AzureBlob, "blob2AzureBlob");
this.blob2BlobMd = checkNotNull(blob2BlobMd, "blob2BlobMd");
this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions");
+ this.multipartUploadStrategy = checkNotNull(multipartUploadStrategy, "multipartUploadStrategy");
}
/**
@@ -221,6 +230,37 @@ public class AzureAsyncBlobStore extends BaseAsyncBlobStore {
}
/**
+ * This implementation invokes {@link AzureBlobAsyncClient#putBlock(String, String, String, Payload)}
+ * @param container
+ * @param name
+ * @param blockId
+ * @param object
+ */
+ public ListenableFuture<Void> putBlock(String container, String name, String blockId, Payload object) {
+ return async.putBlock(container, name, blockId, object);
+ }
+
+
+ /**
+ * This implementation invokes {@link AzureBlobAsyncClient#putBlockList(String, String, java.util.List)}
+ * @param container
+ * @param name
+ * @param blockIdList
+ */
+ public ListenableFuture<String> putBlockList(String container, String name, List<String> blockIdList) {
+ return async.putBlockList(container, name, blockIdList);
+ }
+
+ /**
+ * This implementation invokes {@link AzureBlobAsyncClient#getBlockList(String, String)}
+ * @param container
+ * @param name
+ */
+ public ListenableFuture<ListBlobBlocksResponse> getBlockList(String container, String name) {
+ return async.getBlockList(container, name);
+ }
+
+ /**
* This implementation invokes {@link AzureBlobAsyncClient#getBlobProperties}
*
* @param container
@@ -244,7 +284,9 @@ public class AzureAsyncBlobStore extends BaseAsyncBlobStore {
@Override
public ListenableFuture<String> putBlob(String container, Blob blob, PutOptions options) {
- // TODO implement options
+ if (options.isMultipart()) {
+ throw new UnsupportedOperationException("Multipart upload not supported in AzureAsyncBlobStore");
+ }
return putBlob(container, blob);
}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobStore.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobStore.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobStore.java
index d171a3d..0d5f406 100644
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobStore.java
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobStore.java
@@ -19,9 +19,11 @@ package org.jclouds.azureblob.blobstore;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.azure.storage.options.ListOptions.Builder.includeMetadata;
+import java.util.List;
import java.util.Set;
import javax.inject.Inject;
+import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.azure.storage.domain.BoundedSet;
@@ -32,7 +34,10 @@ import org.jclouds.azureblob.blobstore.functions.BlobToAzureBlob;
import org.jclouds.azureblob.blobstore.functions.ContainerToResourceMetadata;
import org.jclouds.azureblob.blobstore.functions.ListBlobsResponseToResourceList;
import org.jclouds.azureblob.blobstore.functions.ListOptionsToListBlobsOptions;
+import org.jclouds.azureblob.blobstore.strategy.MultipartUploadStrategy;
+import org.jclouds.azureblob.domain.AzureBlob;
import org.jclouds.azureblob.domain.ContainerProperties;
+import org.jclouds.azureblob.domain.ListBlobBlocksResponse;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.azureblob.options.ListBlobsOptions;
import org.jclouds.blobstore.BlobStoreContext;
@@ -54,6 +59,7 @@ import org.jclouds.http.options.GetOptions;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
+import org.jclouds.io.Payload;
/**
* @author Adrian Cole
@@ -68,6 +74,8 @@ public class AzureBlobStore extends BaseBlobStore {
private final BlobToAzureBlob blob2AzureBlob;
private final BlobPropertiesToBlobMetadata blob2BlobMd;
private final BlobToHttpGetOptions blob2ObjectGetOptions;
+ private final Provider<MultipartUploadStrategy> multipartUploadStrategy;
+
@Inject
AzureBlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation,
@@ -76,7 +84,7 @@ public class AzureBlobStore extends BaseBlobStore {
ListOptionsToListBlobsOptions blobStore2AzureContainerListOptions,
ListBlobsResponseToResourceList azure2BlobStoreResourceList, AzureBlobToBlob azureBlob2Blob,
BlobToAzureBlob blob2AzureBlob, BlobPropertiesToBlobMetadata blob2BlobMd,
- BlobToHttpGetOptions blob2ObjectGetOptions) {
+ BlobToHttpGetOptions blob2ObjectGetOptions, Provider<MultipartUploadStrategy> multipartUploadStrategy) {
super(context, blobUtils, defaultLocation, locations);
this.sync = checkNotNull(sync, "sync");
this.container2ResourceMd = checkNotNull(container2ResourceMd, "container2ResourceMd");
@@ -87,6 +95,7 @@ public class AzureBlobStore extends BaseBlobStore {
this.blob2AzureBlob = checkNotNull(blob2AzureBlob, "blob2AzureBlob");
this.blob2BlobMd = checkNotNull(blob2BlobMd, "blob2BlobMd");
this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions");
+ this.multipartUploadStrategy = checkNotNull(multipartUploadStrategy, "multipartUploadStrategy");
}
/**
@@ -202,7 +211,9 @@ public class AzureBlobStore extends BaseBlobStore {
*/
@Override
public String putBlob(String container, Blob blob, PutOptions options) {
- // TODO implement options
+ if (options.isMultipart()) {
+ return multipartUploadStrategy.get().execute(container, blob);
+ }
return putBlob(container, blob);
}
@@ -220,6 +231,31 @@ public class AzureBlobStore extends BaseBlobStore {
}
/**
+ * The Put Block operation creates a block blob on Azure which can be later assembled into
+ * a single, large blob object with the Put Block List operation.
+ */
+ public void putBlock(String container, String name, String blockId, Payload block) {
+ sync.putBlock(container, name, blockId, block);
+ }
+
+
+ /**
+ * The Put Block operation creates a block blob on Azure which can be later assembled into
+ * a single, large blob object with the Put Block List operation. Azure will search the
+ * latest blocks uploaded with putBlock to assemble the blob.
+ */
+ public String putBlockList(String container, String name, List<String> blockIdList) {
+ return sync.putBlockList(container, name, blockIdList);
+ }
+
+ /**
+ * Get Block ID List for a blob
+ */
+ public ListBlobBlocksResponse getBlockList(String container, String name) {
+ return sync.getBlockList(container, name);
+ }
+
+ /**
* This implementation invokes {@link AzureBlobClient#getBlobProperties}
*
* @param container
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategy.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategy.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategy.java
new file mode 100644
index 0000000..d725875
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategy.java
@@ -0,0 +1,87 @@
+/*
+ * 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.azureblob.blobstore.strategy;
+
+import com.google.common.collect.Lists;
+import com.google.common.hash.Hashing;
+import com.google.common.io.BaseEncoding;
+import com.google.inject.Inject;
+import org.jclouds.azureblob.AzureBlobClient;
+import org.jclouds.blobstore.domain.Blob;
+import org.jclouds.blobstore.reference.BlobStoreConstants;
+import org.jclouds.io.Payload;
+import org.jclouds.io.PayloadSlicer;
+import org.jclouds.logging.Logger;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+
+import java.security.SecureRandom;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Decomposes a blob into blocks for upload and assembly through PutBlock and PutBlockList
+ */
+public class AzureBlobBlockUploadStrategy implements MultipartUploadStrategy {
+ @Resource
+ @Named(BlobStoreConstants.BLOBSTORE_LOGGER)
+ private Logger logger = Logger.NULL;
+
+ private final AzureBlobClient client;
+ private final PayloadSlicer slicer;
+
+ @Inject
+ public AzureBlobBlockUploadStrategy(AzureBlobClient client, PayloadSlicer slicer) {
+ this.client = checkNotNull(client, "client");
+ this.slicer = checkNotNull(slicer, "slicer");
+ }
+
+ @Override
+ public String execute(String container, Blob blob) {
+ String blobName = blob.getMetadata().getName();
+ Payload payload = blob.getPayload();
+ long length = payload.getContentMetadata().getContentLength();
+ checkNotNull(length,
+ "please invoke payload.getContentMetadata().setContentLength(length) prior to azure block upload");
+ checkArgument(length <= (MAX_NUMBER_OF_BLOCKS * MAX_BLOCK_SIZE));
+ long offset = 0L;
+ List<String> blockIds = Lists.newArrayList();
+ int blockCount = 0;
+ int totalBlocks = (int) Math.ceil(((double)length) / MAX_BLOCK_SIZE);
+ long bytesWritten = 0;
+ while (offset < length) {
+ blockCount++;
+ long chunkSize = MAX_BLOCK_SIZE;
+ if (blockCount >= totalBlocks) {
+ chunkSize = length % MAX_BLOCK_SIZE;
+ }
+ bytesWritten += chunkSize;
+ Payload block = slicer.slice(payload, offset, chunkSize);
+ offset += MultipartUploadStrategy.MAX_BLOCK_SIZE;
+ String blockName = blobName + "-" + offset + "-" + new SecureRandom().nextInt();
+ byte blockIdBytes[] = Hashing.md5().hashBytes(blockName.getBytes()).asBytes();
+ String blockId = BaseEncoding.base64().encode(blockIdBytes);
+ blockIds.add(blockId);
+ client.putBlock(container, blobName, blockId, block);
+ }
+ assert bytesWritten == length;
+ return client.putBlockList(container, blobName, blockIds);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/MultipartUploadStrategy.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/MultipartUploadStrategy.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/MultipartUploadStrategy.java
new file mode 100755
index 0000000..bd3897d
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/MultipartUploadStrategy.java
@@ -0,0 +1,36 @@
+/*
+ * 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.azureblob.blobstore.strategy;
+
+import com.google.inject.ImplementedBy;
+import org.jclouds.blobstore.domain.Blob;
+
+/**
+ * @see <a href="http://msdn.microsoft.com/en-us/library/windowsazure/dd135726.aspx">Azure Put Block Documentation</a>
+ *
+ * @author John Victor Kew
+ */
+@ImplementedBy(AzureBlobBlockUploadStrategy.class)
+public interface MultipartUploadStrategy {
+ /* Maximum number of blocks per upload */
+ public static final int MAX_NUMBER_OF_BLOCKS = 50000;
+
+ /* Maximum block size */
+ public static final long MAX_BLOCK_SIZE = 4L * 1024 * 1024;
+
+ String execute(String container, Blob blob);
+}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/AzureBlob.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/AzureBlob.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/AzureBlob.java
index 8efab36..b395419 100644
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/AzureBlob.java
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/AzureBlob.java
@@ -26,7 +26,7 @@ import com.google.common.collect.Multimap;
* Amazon S3 is designed to store objects. Objects are stored in buckets and consist of a
* {@link ObjectPropertiesBlob#getInput() value}, a {@link ObjectProperties#getKey key},
* {@link ObjectProperties#getUserProperties() metadata}, and an access control policy.
- *
+ *
* @author Adrian Cole
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?UsingObjects.html"
* />
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/BlobBlockProperties.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/BlobBlockProperties.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/BlobBlockProperties.java
new file mode 100644
index 0000000..c03eace
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/BlobBlockProperties.java
@@ -0,0 +1,28 @@
+/*
+ * 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.azureblob.domain;
+
+/**
+ * Properties on a specific block within a blob
+ *
+ * @author John V Kew II
+ */
+public interface BlobBlockProperties {
+ String getBlockName();
+ boolean isCommitted();
+ long getContentLength();
+}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/ListBlobBlocksResponse.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/ListBlobBlocksResponse.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/ListBlobBlocksResponse.java
new file mode 100644
index 0000000..d469818
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/ListBlobBlocksResponse.java
@@ -0,0 +1,28 @@
+/*
+ * 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.azureblob.domain;
+
+import java.util.List;
+
+/**
+ * Typed response from Get Blob Block List operation
+ *
+ * @author John V Kew II
+ */
+public interface ListBlobBlocksResponse {
+ List<BlobBlockProperties> getBlocks();
+}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/BlobBlockPropertiesImpl.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/BlobBlockPropertiesImpl.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/BlobBlockPropertiesImpl.java
new file mode 100755
index 0000000..7e412f9
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/BlobBlockPropertiesImpl.java
@@ -0,0 +1,66 @@
+/*
+ * 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.azureblob.domain.internal;
+
+import org.jclouds.azureblob.domain.BlobBlockProperties;
+
+import com.google.common.base.Objects;
+
+/**
+ * Representation of the blocks which compose a Blob
+ */
+public class BlobBlockPropertiesImpl implements BlobBlockProperties {
+ private final String blockName;
+ private final long contentLength;
+ private final boolean committed;
+
+ public BlobBlockPropertiesImpl(String blockName, long contentLength, boolean committed) {
+ this.blockName = blockName;
+ this.contentLength = contentLength;
+ this.committed = committed;
+ }
+
+ @Override
+ public String getBlockName() {
+ return blockName;
+ }
+
+ @Override
+ public boolean isCommitted() {
+ return committed;
+ }
+
+ @Override
+ public long getContentLength() {
+ return contentLength;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ BlobBlockPropertiesImpl that = (BlobBlockPropertiesImpl) o;
+ return Objects.equal(blockName, that.blockName)
+ && Objects.equal(committed, that.committed)
+ && Objects.equal(contentLength, that.contentLength);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(blockName, contentLength, committed);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/ListBlobBlocksResponseImpl.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/ListBlobBlocksResponseImpl.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/ListBlobBlocksResponseImpl.java
new file mode 100644
index 0000000..e1fcf6e
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/ListBlobBlocksResponseImpl.java
@@ -0,0 +1,56 @@
+/*
+ * 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.azureblob.domain.internal;
+
+import org.jclouds.azureblob.domain.BlobBlockProperties;
+import org.jclouds.azureblob.domain.ListBlobBlocksResponse;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+
+import java.util.List;
+import com.google.common.base.Objects;
+
+/**
+ * Represents the list of blocks which compose a blob
+ */
+public class ListBlobBlocksResponseImpl implements ListBlobBlocksResponse {
+ private final List<BlobBlockProperties> blocks;
+
+ public ListBlobBlocksResponseImpl(List<BlobBlockProperties> blocks) {
+ this.blocks = checkNotNull(blocks, "block list must not be null");
+ }
+
+ @Override
+ public List<BlobBlockProperties> getBlocks() {
+ return blocks;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ListBlobBlocksResponseImpl that = (ListBlobBlocksResponseImpl) o;
+ return Objects.equal(blocks, that.blocks);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(blocks);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/main/java/org/jclouds/azureblob/predicates/validators/BlockIdValidator.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/predicates/validators/BlockIdValidator.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/predicates/validators/BlockIdValidator.java
new file mode 100644
index 0000000..9003f87
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/predicates/validators/BlockIdValidator.java
@@ -0,0 +1,41 @@
+/*
+ * 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.azureblob.predicates.validators;
+
+import com.google.inject.Singleton;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.predicates.Validator;
+
+/**
+ * Validates Block IDs used in Put Block:
+ *
+ * "A valid Base64 string value that identifies the block. Prior to encoding, the string must
+ * be less than or equal to 64 bytes in size. For a given blob, the length of the value
+ * specified for the blockid parameter must be the same size for each block. Note that the
+ * Base64 string must be URL-encoded."
+ *
+ * @see {http://msdn.microsoft.com/en-us/library/windowsazure/dd135726.aspx}
+ */
+@Singleton
+public class BlockIdValidator extends Validator<String> {
+ @Override
+ public void validate(@Nullable String s) throws IllegalArgumentException {
+ if (s.length() > 64)
+ throw new IllegalArgumentException("block id:" + s + "; Block Ids must be less than or equal to 64 bytes in size");
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/main/java/org/jclouds/azureblob/xml/BlobBlocksResultsHandler.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/xml/BlobBlocksResultsHandler.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/xml/BlobBlocksResultsHandler.java
new file mode 100755
index 0000000..4a95065
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/xml/BlobBlocksResultsHandler.java
@@ -0,0 +1,98 @@
+/*
+ * 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.azureblob.xml;
+
+import java.util.List;
+
+import org.jclouds.azureblob.domain.BlobBlockProperties;
+import org.jclouds.azureblob.domain.ListBlobBlocksResponse;
+import org.jclouds.azureblob.domain.internal.BlobBlockPropertiesImpl;
+import org.jclouds.azureblob.domain.internal.ListBlobBlocksResponseImpl;
+import org.jclouds.http.functions.ParseSax;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Parses the following document:
+ * <?xml version="1.0" encoding="utf-8"?>
+ * <BlockList>
+ * <CommittedBlocks>
+ * <Block>
+ * <Name>base64-encoded-block-id</Name>
+ * <Size>size-in-bytes</Size>
+ * </Block>
+ * <CommittedBlocks>
+ * </BlockList>
+ */
+public class BlobBlocksResultsHandler extends ParseSax.HandlerWithResult<ListBlobBlocksResponse> {
+
+ private StringBuilder currentText = new StringBuilder();
+ private boolean inCommitted = false;
+ private boolean inBlock = false;
+ private boolean inName = false;
+ private boolean inSize = false;
+ private String blockName;
+ private long size;
+ private List<BlobBlockProperties> blocks = Lists.newArrayList();
+
+ @Override
+ public ListBlobBlocksResponse getResult() {
+ return new ListBlobBlocksResponseImpl(blocks);
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes)
+ throws SAXException {
+ if ("CommittedBlocks".equals(qName)) {
+ inCommitted = true;
+ } else if ("UncommittedBlocks".equals(qName)) {
+ inCommitted = false;
+ } else if ("Block".equals(qName)) {
+ inBlock = true;
+ } else if ("Name".equals(qName)) {
+ inName = true;
+ } else if ("Size".equals(qName)) {
+ inSize = true;
+ }
+ }
+
+ public void endElement(String uri, String name, String qName) {
+ if ("CommittedBlocks".equals(qName)) {
+ inCommitted = false;
+ } else if ("UncommittedBlocks".equals(qName)) {
+ inCommitted = false;
+ } else if ("Block".equals(qName)) {
+ BlobBlockProperties block = new BlobBlockPropertiesImpl(blockName, size, inCommitted);
+ blocks.add(block);
+ inBlock = false;
+ } else if ("Name".equals(qName)) {
+ blockName = currentText.toString().trim();
+ inName = false;
+ } else if ("Size".equals(qName)) {
+ size = Long.parseLong(currentText.toString().trim());
+ inSize = false;
+ }
+ currentText = new StringBuilder();
+ }
+
+ public void characters(char ch[], int start, int length) {
+ currentText.append(ch, start, length);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/test/java/org/jclouds/azureblob/AzureBlobClientLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/test/java/org/jclouds/azureblob/AzureBlobClientLiveTest.java b/providers/azureblob/src/test/java/org/jclouds/azureblob/AzureBlobClientLiveTest.java
index 0941574..231b3f5 100644
--- a/providers/azureblob/src/test/java/org/jclouds/azureblob/AzureBlobClientLiveTest.java
+++ b/providers/azureblob/src/test/java/org/jclouds/azureblob/AzureBlobClientLiveTest.java
@@ -27,14 +27,17 @@ import java.io.ByteArrayInputStream;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.URI;
import java.security.SecureRandom;
+import java.util.Arrays;
import java.util.Set;
+import com.google.common.io.BaseEncoding;
import org.jclouds.azure.storage.AzureStorageResponseException;
import org.jclouds.azure.storage.domain.BoundedSet;
import org.jclouds.azure.storage.options.ListOptions;
import org.jclouds.azureblob.domain.AzureBlob;
import org.jclouds.azureblob.domain.BlobProperties;
import org.jclouds.azureblob.domain.ContainerProperties;
+import org.jclouds.azureblob.domain.ListBlobBlocksResponse;
import org.jclouds.azureblob.domain.ListBlobsResponse;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.azureblob.options.ListBlobsOptions;
@@ -43,6 +46,7 @@ import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
import org.jclouds.http.HttpResponseException;
import org.jclouds.http.options.GetOptions;
import org.jclouds.io.Payloads;
+import org.jclouds.io.payloads.ByteArrayPayload;
import org.jclouds.util.Strings2;
import org.jclouds.util.Throwables2;
import org.testng.annotations.Test;
@@ -124,7 +128,7 @@ public class AzureBlobClientLiveTest extends BaseBlobStoreIntegrationTest {
// Utils.toStringAndClose(url.openStream());
}
- @Test(timeOut = 5 * 60 * 1000)
+ @Test(timeOut = 10 * 60 * 1000)
public void testCreatePublicRootContainer() throws Exception {
try {
getApi().deleteRootContainer();
@@ -346,4 +350,31 @@ public class AzureBlobClientLiveTest extends BaseBlobStoreIntegrationTest {
getApi().deleteBlob(privateContainer, "object");
getApi().deleteBlob(privateContainer, "chunked-object");
}
+
+ @Test(timeOut = 5 * 60 * 1000)
+ public void testBlockOperations() throws Exception {
+ String blockContainer = prefix + new SecureRandom().nextInt();
+ String blockBlob = "myblockblob-" + new SecureRandom().nextInt();
+ String A = "A";
+ String B = "B";
+ String C = "C";
+
+ String blockIdA = BaseEncoding.base64().encode((blockBlob + "-" + A).getBytes());
+ String blockIdB = BaseEncoding.base64().encode((blockBlob + "-" + B).getBytes());
+ String blockIdC = BaseEncoding.base64().encode((blockBlob + "-" + C).getBytes());
+ getApi().createContainer(blockContainer);
+ getApi().putBlock(blockContainer, blockBlob, blockIdA, new ByteArrayPayload(A.getBytes()));
+ getApi().putBlock(blockContainer, blockBlob, blockIdB, new ByteArrayPayload(B.getBytes()));
+ getApi().putBlock(blockContainer, blockBlob, blockIdC, new ByteArrayPayload(C.getBytes()));
+ getApi().putBlockList(blockContainer, blockBlob, Arrays.asList(blockIdA, blockIdB, blockIdC));
+ ListBlobBlocksResponse blocks = getApi().getBlockList(blockContainer, blockBlob);
+ assertEquals(3, blocks.getBlocks().size());
+ assertEquals(blockIdA, blocks.getBlocks().get(0).getBlockName());
+ assertEquals(blockIdB, blocks.getBlocks().get(1).getBlockName());
+ assertEquals(blockIdC, blocks.getBlocks().get(2).getBlockName());
+ assertEquals(1, blocks.getBlocks().get(0).getContentLength());
+ assertEquals(1, blocks.getBlocks().get(1).getContentLength());
+ assertEquals(1, blocks.getBlocks().get(2).getContentLength());
+ getApi().deleteContainer(blockContainer);
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/test/java/org/jclouds/azureblob/blobstore/integration/AzureBlobIntegrationLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/test/java/org/jclouds/azureblob/blobstore/integration/AzureBlobIntegrationLiveTest.java b/providers/azureblob/src/test/java/org/jclouds/azureblob/blobstore/integration/AzureBlobIntegrationLiveTest.java
index 601c7e4..82b07b3 100644
--- a/providers/azureblob/src/test/java/org/jclouds/azureblob/blobstore/integration/AzureBlobIntegrationLiveTest.java
+++ b/providers/azureblob/src/test/java/org/jclouds/azureblob/blobstore/integration/AzureBlobIntegrationLiveTest.java
@@ -16,13 +16,23 @@
*/
package org.jclouds.azureblob.blobstore.integration;
+import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.util.concurrent.ExecutionException;
+import com.google.common.io.Files;
+import com.google.common.io.InputSupplier;
+import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.integration.internal.BaseBlobIntegrationTest;
+import org.jclouds.blobstore.options.PutOptions;
import org.testng.SkipException;
import org.testng.annotations.Test;
+import static org.testng.Assert.assertEquals;
+
+import static com.google.common.hash.Hashing.md5;
+import static org.jclouds.io.ByteSources.asByteSource;
/**
*
@@ -30,6 +40,9 @@ import org.testng.annotations.Test;
*/
@Test(groups = "live")
public class AzureBlobIntegrationLiveTest extends BaseBlobIntegrationTest {
+ private InputSupplier<InputStream> oneHundredOneConstitutions;
+ private byte[] oneHundredOneConstitutionsMD5;
+
public AzureBlobIntegrationLiveTest() {
provider = "azureblob";
}
@@ -38,6 +51,11 @@ public class AzureBlobIntegrationLiveTest extends BaseBlobIntegrationTest {
// this currently fails
}
+ @Override
+ public void testGetIfModifiedSince() throws InterruptedException {
+ // this currently fails!
+ }
+
public void testCreateBlobWithExpiry() throws InterruptedException {
throw new SkipException("Expires header unsupported: http://msdn.microsoft.com/en-us/library/windowsazure/dd179404.aspx#Subheading3");
}
@@ -55,4 +73,26 @@ public class AzureBlobIntegrationLiveTest extends BaseBlobIntegrationTest {
assert blob.getPayload().getContentMetadata().getContentDisposition() == null;
assert blob.getMetadata().getContentMetadata().getContentDisposition() == null;
}
+
+ /**
+ * Essentially copied from the AWS multipart chucked stream test
+ */
+ public void testMultipartChunkedFileStream() throws IOException, InterruptedException {
+ oneHundredOneConstitutions = getTestDataSupplier();
+ oneHundredOneConstitutionsMD5 = asByteSource(oneHundredOneConstitutions.getInput()).hash(md5()).asBytes();
+ File file = new File("target/const.txt");
+ Files.copy(oneHundredOneConstitutions, file);
+ String containerName = getContainerName();
+
+ try {
+ BlobStore blobStore = view.getBlobStore();
+ blobStore.createContainerInLocation(null, containerName);
+ Blob blob = blobStore.blobBuilder("const.txt").payload(file).build();
+ String expected = blobStore.putBlob(containerName, blob, PutOptions.Builder.multipart());
+ String etag = blobStore.blobMetadata(containerName, "const.txt").getETag();
+ assertEquals(etag, expected);
+ } finally {
+ returnContainer(containerName);
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/test/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategyTest.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/test/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategyTest.java b/providers/azureblob/src/test/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategyTest.java
new file mode 100644
index 0000000..edee3c8
--- /dev/null
+++ b/providers/azureblob/src/test/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategyTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.azureblob.blobstore.strategy;
+
+import org.jclouds.azureblob.AzureBlobClient;
+import org.jclouds.blobstore.domain.Blob;
+import org.jclouds.blobstore.domain.MutableBlobMetadata;
+import org.jclouds.blobstore.domain.internal.BlobImpl;
+import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
+import org.jclouds.io.MutableContentMetadata;
+import org.jclouds.io.Payload;
+import org.jclouds.io.PayloadSlicer;
+import org.jclouds.io.payloads.BaseMutableContentMetadata;
+import org.jclouds.io.payloads.StringPayload;
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+
+@Test(groups = "unit", testName = "AzureBlobBlockUploadStrategyTest")
+public class AzureBlobBlockUploadStrategyTest {
+
+ public void testExecute() throws Exception {
+ String container = "test-container";
+ String blobName = "test-blob";
+ long oneMB = 1048576L;
+ AzureBlobClient client = createMock(AzureBlobClient.class);
+ PayloadSlicer slicer = createMock(PayloadSlicer.class);
+ MutableBlobMetadata metadata = new MutableBlobMetadataImpl();
+ MutableContentMetadata contentMetadata = new BaseMutableContentMetadata();
+ contentMetadata.setContentLength(MultipartUploadStrategy.MAX_BLOCK_SIZE * 3 + oneMB);
+ metadata.setName(blobName);
+ metadata.setContentMetadata(contentMetadata);
+ Blob blob = new BlobImpl(metadata);
+ Payload payload = new StringPayload("ABCD");
+ payload.setContentMetadata(contentMetadata);
+ blob.setPayload(payload);
+
+ expect(slicer.slice(payload, 0, MultipartUploadStrategy.MAX_BLOCK_SIZE)).andReturn(payload);
+ expect(slicer.slice(payload, MultipartUploadStrategy.MAX_BLOCK_SIZE, MultipartUploadStrategy.MAX_BLOCK_SIZE)).andReturn(payload);
+ expect(slicer.slice(payload, MultipartUploadStrategy.MAX_BLOCK_SIZE * 2, MultipartUploadStrategy.MAX_BLOCK_SIZE)).andReturn(payload);
+ expect(slicer.slice(payload, MultipartUploadStrategy.MAX_BLOCK_SIZE * 3, oneMB)).andReturn(payload);
+ client.putBlock(eq(container), eq(blobName), anyObject(String.class), eq(payload));
+ expectLastCall().times(4);
+ expect(client.putBlockList(eq(container), eq(blobName), anyObject(List.class))).andReturn("Fake ETAG");
+
+ AzureBlobBlockUploadStrategy strat = new AzureBlobBlockUploadStrategy(client, slicer);
+ replay(slicer,client);
+ String etag = strat.execute(container, blob);
+ assertEquals(etag, "Fake ETAG");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/test/java/org/jclouds/azureblob/xml/BlobBlocksResultsHandlerTest.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/test/java/org/jclouds/azureblob/xml/BlobBlocksResultsHandlerTest.java b/providers/azureblob/src/test/java/org/jclouds/azureblob/xml/BlobBlocksResultsHandlerTest.java
new file mode 100644
index 0000000..4d5efdc
--- /dev/null
+++ b/providers/azureblob/src/test/java/org/jclouds/azureblob/xml/BlobBlocksResultsHandlerTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.azureblob.xml;
+
+import org.jclouds.azureblob.domain.BlobBlockProperties;
+import org.jclouds.azureblob.domain.ListBlobBlocksResponse;
+import org.jclouds.azureblob.domain.internal.BlobBlockPropertiesImpl;
+import org.jclouds.azureblob.domain.internal.ListBlobBlocksResponseImpl;
+import org.jclouds.http.functions.BaseHandlerTest;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertEquals;
+
+import java.io.InputStream;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Test XML Parsing of the Blob Block List
+ */
+@Test(groups = "unit", testName = "BlobBlocksResultsHandlerTest")
+public class BlobBlocksResultsHandlerTest extends BaseHandlerTest {
+
+ @BeforeTest
+ @Override
+ protected void setUpInjector() {
+ super.setUpInjector();
+ }
+
+ public void testGetResult() throws Exception {
+ InputStream is = getClass().getResourceAsStream("/test_list_blob_blocks.xml");
+
+ List<BlobBlockProperties> blocks = new LinkedList<BlobBlockProperties>();
+ blocks.add(new BlobBlockPropertiesImpl("blockIdA", 1234, true));
+ blocks.add(new BlobBlockPropertiesImpl("blockIdB", 4321, true));
+ blocks.add(new BlobBlockPropertiesImpl("blockIdC", 5678, false));
+ blocks.add(new BlobBlockPropertiesImpl("blockIdD", 8765, false));
+ ListBlobBlocksResponse expected = new ListBlobBlocksResponseImpl(blocks);
+
+ ListBlobBlocksResponse result = factory.create(
+ injector.getInstance(BlobBlocksResultsHandler.class)).parse(is);
+
+ assertEquals(expected, result);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/3a734b89/providers/azureblob/src/test/resources/test_list_blob_blocks.xml
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/test/resources/test_list_blob_blocks.xml b/providers/azureblob/src/test/resources/test_list_blob_blocks.xml
new file mode 100644
index 0000000..67f2325
--- /dev/null
+++ b/providers/azureblob/src/test/resources/test_list_blob_blocks.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<BlockList>
+ <CommittedBlocks>
+ <Block>
+ <Name>blockIdA</Name>
+ <Size>1234</Size>
+ </Block>
+ <Block>
+ <Name>blockIdB</Name>
+ <Size>4321</Size>
+ </Block>
+ </CommittedBlocks>
+ <UncommittedBlocks>
+ <Block>
+ <Name>blockIdC</Name>
+ <Size>5678</Size>
+ </Block>
+ <Block>
+ <Name>blockIdD</Name>
+ <Size>8765</Size>
+ </Block>
+ </UncommittedBlocks>
+</BlockList>
\ No newline at end of file
[3/3] git commit: Follow-up to Azureblob cleanup
Posted by ga...@apache.org.
Follow-up to Azureblob cleanup
See discussion at https://github.com/jclouds/jclouds/pull/66
Project: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/commit/2ebde8c5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/tree/2ebde8c5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/diff/2ebde8c5
Branch: refs/heads/1.6.x
Commit: 2ebde8c556afa92fabf51ab535321d84760aef2b
Parents: a6f6f04
Author: Andrew Phillips <de...@yahoo.co.uk>
Authored: Wed Jul 17 10:19:43 2013 -0400
Committer: Andrew Gaul <ga...@apache.org>
Committed: Wed Jul 17 10:35:24 2013 -0700
----------------------------------------------------------------------
.../azureblob/blobstore/strategy/AzureBlobBlockUploadStrategy.java | 2 +-
.../jclouds/azureblob/predicates/validators/BlockIdValidator.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/2ebde8c5/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategy.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategy.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategy.java
index 4475555..dc4cb5d 100644
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategy.java
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategy.java
@@ -82,7 +82,7 @@ public class AzureBlobBlockUploadStrategy implements MultipartUploadStrategy {
blockIds.add(blockId);
client.putBlock(container, blobName, blockId, block);
}
- checkState(bytesWritten == length, "Wrote " + bytesWritten + " bytes, but we wanted to write " + length + " bytes");
+ checkState(bytesWritten == length, "Wrote %s bytes, but we wanted to write %s bytes", bytesWritten, length);
return client.putBlockList(container, blobName, blockIds);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/2ebde8c5/providers/azureblob/src/main/java/org/jclouds/azureblob/predicates/validators/BlockIdValidator.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/predicates/validators/BlockIdValidator.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/predicates/validators/BlockIdValidator.java
index cd6d53f..c3ecedb 100644
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/predicates/validators/BlockIdValidator.java
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/predicates/validators/BlockIdValidator.java
@@ -33,7 +33,7 @@ import org.jclouds.predicates.Validator;
@Singleton
public class BlockIdValidator extends Validator<String> {
@Override
- public void validate(String s) throws IllegalArgumentException {
+ public void validate(@Nullable String s) throws IllegalArgumentException {
if (s == null || s.length() > 64)
throw new IllegalArgumentException("block id:" + s + "; Block Ids must be less than or equal to 64 bytes in size");
[2/3] git commit: Cleanup of Azureblob code;
as per pull request review. Additional items not covered here are
assigned specific bug ids.
Posted by ga...@apache.org.
Cleanup of Azureblob code; as per pull request review. Additional items
not covered here are assigned specific bug ids.
Project: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/commit/a6f6f04d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/tree/a6f6f04d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/diff/a6f6f04d
Branch: refs/heads/1.6.x
Commit: a6f6f04d753dc8d681b1f0f4969159b0ca699152
Parents: 3a734b8
Author: John Kew <jo...@socrata.com>
Authored: Thu Jul 11 16:12:07 2013 -0700
Committer: Andrew Gaul <ga...@apache.org>
Committed: Wed Jul 17 10:35:18 2013 -0700
----------------------------------------------------------------------
.../blobstore/strategy/AzureBlobBlockUploadStrategy.java | 5 +++--
.../azureblob/domain/internal/BlobBlockPropertiesImpl.java | 3 ++-
.../azureblob/predicates/validators/BlockIdValidator.java | 4 ++--
.../org/jclouds/azureblob/xml/BlobBlocksResultsHandler.java | 2 ++
4 files changed, 9 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/a6f6f04d/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategy.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategy.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategy.java
index d725875..4475555 100644
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategy.java
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/strategy/AzureBlobBlockUploadStrategy.java
@@ -35,6 +35,7 @@ import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
/**
* Decomposes a blob into blocks for upload and assembly through PutBlock and PutBlockList
@@ -57,7 +58,7 @@ public class AzureBlobBlockUploadStrategy implements MultipartUploadStrategy {
public String execute(String container, Blob blob) {
String blobName = blob.getMetadata().getName();
Payload payload = blob.getPayload();
- long length = payload.getContentMetadata().getContentLength();
+ Long length = payload.getContentMetadata().getContentLength();
checkNotNull(length,
"please invoke payload.getContentMetadata().setContentLength(length) prior to azure block upload");
checkArgument(length <= (MAX_NUMBER_OF_BLOCKS * MAX_BLOCK_SIZE));
@@ -81,7 +82,7 @@ public class AzureBlobBlockUploadStrategy implements MultipartUploadStrategy {
blockIds.add(blockId);
client.putBlock(container, blobName, blockId, block);
}
- assert bytesWritten == length;
+ checkState(bytesWritten == length, "Wrote " + bytesWritten + " bytes, but we wanted to write " + length + " bytes");
return client.putBlockList(container, blobName, blockIds);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/a6f6f04d/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/BlobBlockPropertiesImpl.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/BlobBlockPropertiesImpl.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/BlobBlockPropertiesImpl.java
index 7e412f9..b2d15d7 100755
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/BlobBlockPropertiesImpl.java
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/BlobBlockPropertiesImpl.java
@@ -19,6 +19,7 @@ package org.jclouds.azureblob.domain.internal;
import org.jclouds.azureblob.domain.BlobBlockProperties;
import com.google.common.base.Objects;
+import static com.google.common.base.Preconditions.checkNotNull;
/**
* Representation of the blocks which compose a Blob
@@ -29,7 +30,7 @@ public class BlobBlockPropertiesImpl implements BlobBlockProperties {
private final boolean committed;
public BlobBlockPropertiesImpl(String blockName, long contentLength, boolean committed) {
- this.blockName = blockName;
+ this.blockName = checkNotNull(blockName);
this.contentLength = contentLength;
this.committed = committed;
}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/a6f6f04d/providers/azureblob/src/main/java/org/jclouds/azureblob/predicates/validators/BlockIdValidator.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/predicates/validators/BlockIdValidator.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/predicates/validators/BlockIdValidator.java
index 9003f87..cd6d53f 100644
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/predicates/validators/BlockIdValidator.java
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/predicates/validators/BlockIdValidator.java
@@ -33,8 +33,8 @@ import org.jclouds.predicates.Validator;
@Singleton
public class BlockIdValidator extends Validator<String> {
@Override
- public void validate(@Nullable String s) throws IllegalArgumentException {
- if (s.length() > 64)
+ public void validate(String s) throws IllegalArgumentException {
+ if (s == null || s.length() > 64)
throw new IllegalArgumentException("block id:" + s + "; Block Ids must be less than or equal to 64 bytes in size");
}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/a6f6f04d/providers/azureblob/src/main/java/org/jclouds/azureblob/xml/BlobBlocksResultsHandler.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/xml/BlobBlocksResultsHandler.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/xml/BlobBlocksResultsHandler.java
index 4a95065..6a566e7 100755
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/xml/BlobBlocksResultsHandler.java
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/xml/BlobBlocksResultsHandler.java
@@ -30,6 +30,7 @@ import com.google.common.collect.Lists;
/**
* Parses the following document:
+ * <pre>
* <?xml version="1.0" encoding="utf-8"?>
* <BlockList>
* <CommittedBlocks>
@@ -39,6 +40,7 @@ import com.google.common.collect.Lists;
* </Block>
* <CommittedBlocks>
* </BlockList>
+ * </pre>
*/
public class BlobBlocksResultsHandler extends ParseSax.HandlerWithResult<ListBlobBlocksResponse> {