mirror of https://github.com/apache/jclouds.git
JCLOUDS-391: Azure multipart putBlob user metadata
This commit is contained in:
parent
787ce446cd
commit
1c781cc5fa
|
@ -43,6 +43,7 @@ import org.jclouds.azure.storage.filters.SharedKeyLiteAuthentication;
|
|||
import org.jclouds.azure.storage.options.ListOptions;
|
||||
import org.jclouds.azure.storage.reference.AzureStorageHeaders;
|
||||
import org.jclouds.azureblob.binders.BindAzureBlobMetadataToRequest;
|
||||
import org.jclouds.azureblob.binders.BindAzureBlobMetadataToMultipartRequest;
|
||||
import org.jclouds.azureblob.binders.BindAzureBlocksToRequest;
|
||||
import org.jclouds.azureblob.domain.AzureBlob;
|
||||
import org.jclouds.azureblob.domain.BlobProperties;
|
||||
|
@ -347,7 +348,10 @@ public interface AzureBlobClient extends Closeable {
|
|||
* 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.
|
||||
*
|
||||
* @deprecated call putBlockList(String, AzureBlob, List<String>) instead
|
||||
*/
|
||||
@Deprecated
|
||||
@Named("PutBlockList")
|
||||
@PUT
|
||||
@Path("{container}/{name}")
|
||||
|
@ -357,6 +361,20 @@ public interface AzureBlobClient extends Closeable {
|
|||
@PathParam("name") String name,
|
||||
@BinderParam(BindAzureBlocksToRequest.class) List<String> blockIdList);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@Named("PutBlockList")
|
||||
@PUT
|
||||
@Path("{container}/{name}")
|
||||
@ResponseParser(ParseETagHeader.class)
|
||||
@QueryParams(keys = { "comp" }, values = { "blocklist" })
|
||||
String putBlockList(@PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
|
||||
@PathParam("name") @ParamParser(BlobName.class) @BinderParam(BindAzureBlobMetadataToMultipartRequest.class) AzureBlob object,
|
||||
@BinderParam(BindAzureBlocksToRequest.class) List<String> blockIdList);
|
||||
|
||||
@Named("GetBlockList")
|
||||
@GET
|
||||
@Path("{container}/{name}")
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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 static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.azureblob.blobstore.functions.AzureBlobToBlob;
|
||||
import org.jclouds.azureblob.domain.AzureBlob;
|
||||
import org.jclouds.blobstore.binders.BindUserMetadataToHeadersWithPrefix;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
||||
public class BindAzureBlobMetadataToMultipartRequest implements Binder {
|
||||
|
||||
private final AzureBlobToBlob azureBlob2Blob;
|
||||
private final BindUserMetadataToHeadersWithPrefix blobBinder;
|
||||
|
||||
@Inject
|
||||
BindAzureBlobMetadataToMultipartRequest(AzureBlobToBlob azureBlob2Blob, BindUserMetadataToHeadersWithPrefix blobBinder) {
|
||||
this.azureBlob2Blob = azureBlob2Blob;
|
||||
this.blobBinder = blobBinder;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
|
||||
checkArgument(checkNotNull(input, "input") instanceof AzureBlob, "this binder is only valid for AzureBlobs!");
|
||||
checkNotNull(request, "request");
|
||||
AzureBlob blob = AzureBlob.class.cast(input);
|
||||
|
||||
checkArgument(blob.getPayload().getContentMetadata().getContentLength() != null
|
||||
&& blob.getPayload().getContentMetadata().getContentLength() >= 0, "size must be set");
|
||||
|
||||
return blobBinder.bindToRequest(request, azureBlob2Blob.apply(blob));
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ 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.azureblob.blobstore.functions.BlobToAzureBlob;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.reference.BlobStoreConstants;
|
||||
import org.jclouds.io.Payload;
|
||||
|
@ -46,11 +47,13 @@ public class AzureBlobBlockUploadStrategy implements MultipartUploadStrategy {
|
|||
|
||||
private final AzureBlobClient client;
|
||||
private final PayloadSlicer slicer;
|
||||
private final BlobToAzureBlob blobToAzureBlob;
|
||||
|
||||
@Inject
|
||||
public AzureBlobBlockUploadStrategy(AzureBlobClient client, PayloadSlicer slicer) {
|
||||
this.client = checkNotNull(client, "client");
|
||||
this.slicer = checkNotNull(slicer, "slicer");
|
||||
AzureBlobBlockUploadStrategy(AzureBlobClient client, PayloadSlicer slicer, BlobToAzureBlob blobToAzureBlob) {
|
||||
this.client = client;
|
||||
this.slicer = slicer;
|
||||
this.blobToAzureBlob = blobToAzureBlob;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -74,6 +77,6 @@ public class AzureBlobBlockUploadStrategy implements MultipartUploadStrategy {
|
|||
}
|
||||
|
||||
checkState(bytesWritten == length, "Wrote %s bytes, but we wanted to write %s bytes", bytesWritten, length);
|
||||
return client.putBlockList(container, blobName, blockIds);
|
||||
return client.putBlockList(container, blobToAzureBlob.apply(blob), blockIds);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,16 @@ package org.jclouds.azureblob.blobstore.integration;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.io.ByteSource;
|
||||
import com.google.common.io.Files;
|
||||
import org.jclouds.azureblob.blobstore.strategy.MultipartUploadStrategy;
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.integration.internal.BaseBlobIntegrationTest;
|
||||
import org.jclouds.blobstore.options.PutOptions;
|
||||
import org.jclouds.io.ByteStreams2;
|
||||
|
@ -133,4 +136,27 @@ public class AzureBlobIntegrationLiveTest extends BaseBlobIntegrationTest {
|
|||
returnContainer(containerName);
|
||||
}
|
||||
}
|
||||
|
||||
public void testMultipartUserMetadata() throws Exception {
|
||||
BlobStore blobStore = view.getBlobStore();
|
||||
String containerName = getContainerName();
|
||||
String blobName = "const.txt";
|
||||
ByteSource byteSource = TestUtils.randomByteSource().slice(0, MultipartUploadStrategy.MAX_BLOCK_SIZE + 1);
|
||||
Map<String, String> userMetadata = ImmutableMap.of("foo", "bar");
|
||||
|
||||
blobStore.createContainerInLocation(null, containerName);
|
||||
try {
|
||||
Blob blob = blobStore.blobBuilder(blobName)
|
||||
.payload(byteSource)
|
||||
.contentLength(byteSource.size())
|
||||
.userMetadata(userMetadata)
|
||||
.build();
|
||||
blobStore.putBlob(containerName, blob, PutOptions.Builder.multipart());
|
||||
|
||||
BlobMetadata blobMetadata = blobStore.blobMetadata(containerName, blobName);
|
||||
assertThat(blobMetadata.getUserMetadata()).isEqualTo(userMetadata);
|
||||
} finally {
|
||||
returnContainer(containerName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ import com.google.common.collect.ImmutableList;
|
|||
import com.google.common.io.ByteSource;
|
||||
import org.easymock.EasyMock;
|
||||
import org.jclouds.azureblob.AzureBlobClient;
|
||||
import org.jclouds.azureblob.blobstore.functions.BlobToAzureBlob;
|
||||
import org.jclouds.azureblob.domain.AzureBlob;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.MutableBlobMetadata;
|
||||
import org.jclouds.blobstore.domain.internal.BlobImpl;
|
||||
|
@ -54,6 +56,7 @@ public class AzureBlobBlockUploadStrategyTest {
|
|||
byte[] blobData = "ABCD".getBytes(Charsets.UTF_8);
|
||||
AzureBlobClient client = createMock(AzureBlobClient.class);
|
||||
PayloadSlicer slicer = createMock(PayloadSlicer.class);
|
||||
BlobToAzureBlob blobToAzureBlob = createMock(BlobToAzureBlob.class);
|
||||
MutableBlobMetadata metadata = new MutableBlobMetadataImpl();
|
||||
MutableContentMetadata contentMetadata = new BaseMutableContentMetadata();
|
||||
contentMetadata.setContentLength((long)blobData.length);
|
||||
|
@ -76,9 +79,9 @@ public class AzureBlobBlockUploadStrategyTest {
|
|||
client.putBlock(eq(container), eq(blobName), anyObject(String.class), eq(payloads.get(1)));
|
||||
client.putBlock(eq(container), eq(blobName), anyObject(String.class), eq(payloads.get(2)));
|
||||
client.putBlock(eq(container), eq(blobName), anyObject(String.class), eq(payloads.get(3)));
|
||||
expect(client.putBlockList(eq(container), eq(blobName), EasyMock.<List<String>>anyObject())).andReturn("Fake ETAG");
|
||||
expect(client.putBlockList(eq(container), anyObject(AzureBlob.class), EasyMock.<List<String>>anyObject())).andReturn("Fake ETAG");
|
||||
|
||||
AzureBlobBlockUploadStrategy strat = new AzureBlobBlockUploadStrategy(client, slicer);
|
||||
AzureBlobBlockUploadStrategy strat = new AzureBlobBlockUploadStrategy(client, slicer, blobToAzureBlob);
|
||||
replay(slicer, client);
|
||||
String etag = strat.execute(container, blob);
|
||||
assertEquals(etag, "Fake ETAG");
|
||||
|
@ -93,6 +96,7 @@ public class AzureBlobBlockUploadStrategyTest {
|
|||
|
||||
AzureBlobClient client = createNiceMock(AzureBlobClient.class);
|
||||
PayloadSlicer slicer = createNiceMock(PayloadSlicer.class);
|
||||
BlobToAzureBlob blobToAzureBlob = createMock(BlobToAzureBlob.class);
|
||||
|
||||
MutableBlobMetadata metadata = new MutableBlobMetadataImpl();
|
||||
MutableContentMetadata contentMetadata = new BaseMutableContentMetadata();
|
||||
|
@ -105,7 +109,7 @@ public class AzureBlobBlockUploadStrategyTest {
|
|||
payload.setContentMetadata(contentMetadata);
|
||||
blob.setPayload(payload);
|
||||
|
||||
AzureBlobBlockUploadStrategy strat = new AzureBlobBlockUploadStrategy(client, slicer);
|
||||
AzureBlobBlockUploadStrategy strat = new AzureBlobBlockUploadStrategy(client, slicer, blobToAzureBlob);
|
||||
strat.execute(container, blob);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue