com.azure.storage.blob.batch.BlobBatchAsyncClient Maven / Gradle / Ivy
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.storage.blob.batch;
import com.azure.core.annotation.ReturnType;
import com.azure.core.annotation.ServiceClient;
import com.azure.core.annotation.ServiceMethod;
import com.azure.core.http.HttpHeaders;
import com.azure.core.http.HttpPipeline;
import com.azure.core.http.HttpRequest;
import com.azure.core.http.rest.PagedFlux;
import com.azure.core.http.rest.PagedResponse;
import com.azure.core.http.rest.Response;
import com.azure.core.util.Context;
import com.azure.core.util.FluxUtil;
import com.azure.core.util.IterableStream;
import com.azure.core.util.logging.ClientLogger;
import com.azure.storage.blob.BlobServiceVersion;
import com.azure.storage.blob.implementation.AzureBlobStorageImpl;
import com.azure.storage.blob.implementation.AzureBlobStorageImplBuilder;
import com.azure.storage.blob.models.AccessTier;
import com.azure.storage.blob.models.BlobStorageException;
import com.azure.storage.blob.models.DeleteSnapshotsOptionType;
import com.azure.storage.common.implementation.StorageImplUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import static com.azure.core.util.FluxUtil.monoError;
import static com.azure.core.util.FluxUtil.pagedFluxError;
import static com.azure.core.util.FluxUtil.withContext;
/**
* This class provides a client that contains all operations that apply to Azure Storage Blob batching.
*
* This client offers the ability to delete and set access tier on multiple blobs at once and to submit a {@link
* BlobBatch}.
*
* @see BlobBatch
* @see BlobBatchClientBuilder
*/
@ServiceClient(builder = BlobBatchClientBuilder.class, isAsync = true)
public final class BlobBatchAsyncClient {
private static final ClientLogger LOGGER = new ClientLogger(BlobBatchAsyncClient.class);
private final AzureBlobStorageImpl client;
private final boolean containerScoped;
private final BlobServiceVersion serviceVersion;
BlobBatchAsyncClient(String clientUrl, HttpPipeline pipeline, BlobServiceVersion version, boolean containerScoped) {
this.serviceVersion = version;
this.client = new AzureBlobStorageImplBuilder()
.url(clientUrl)
.pipeline(pipeline)
.version(version.getVersion())
.buildClient();
this.containerScoped = containerScoped;
}
AzureBlobStorageImpl getClient() {
return client;
}
/**
* Gets a {@link BlobBatch} used to configure a batching operation to send to Azure Storage blobs.
*
* @return a new {@link BlobBatch} instance.
*/
public BlobBatch getBlobBatch() {
return new BlobBatch(client.getUrl(), client.getHttpPipeline(), serviceVersion);
}
/**
* Submits a batch operation.
*
* If any request in a batch fails this will throw a {@link BlobStorageException}.
*
* Code samples
*
*
*
* BlobBatch batch = batchAsyncClient.getBlobBatch();
*
* Response<Void> deleteResponse1 = batch.deleteBlob("container", "blob1");
* Response<Void> deleteResponse2 = batch.deleteBlob("container", "blob2", DeleteSnapshotsOptionType.INCLUDE,
* new BlobRequestConditions().setLeaseId("leaseId"));
*
* batchAsyncClient.submitBatch(batch).subscribe(response -> {
* System.out.println("Batch submission completed successfully.");
* System.out.printf("Delete operation 1 completed with status code: %d%n", deleteResponse1.getStatusCode());
* System.out.printf("Delete operation 2 completed with status code: %d%n", deleteResponse2.getStatusCode());
* }, error -> System.err.printf("Batch submission failed. Error message: %s%n", error.getMessage()));
*
*
*
* @param batch Batch to submit.
* @return An empty response indicating that the batch operation has completed.
* @throws BlobStorageException If the batch request is malformed.
* @throws BlobBatchStorageException If any request in the {@link BlobBatch} failed.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono submitBatch(BlobBatch batch) {
try {
return withContext(context -> submitBatchWithResponse(batch, true, context)).flatMap(FluxUtil::toMono);
} catch (RuntimeException ex) {
return monoError(LOGGER, ex);
}
}
/**
* Submits a batch operation.
*
* If {@code throwOnAnyFailure} is {@code true} a {@link BlobStorageException} will be thrown if any request
* fails.
*
* Code samples
*
*
*
* BlobBatch batch = batchAsyncClient.getBlobBatch();
*
* Response<Void> deleteResponse1 = batch.deleteBlob("container", "blob1");
* Response<Void> deleteResponse2 = batch.deleteBlob("container", "blob2", DeleteSnapshotsOptionType.INCLUDE,
* new BlobRequestConditions().setLeaseId("leaseId"));
*
* batchAsyncClient.submitBatchWithResponse(batch, true).subscribe(response -> {
* System.out.printf("Batch submission completed with status code: %d%n", response.getStatusCode());
* System.out.printf("Delete operation 1 completed with status code: %d%n", deleteResponse1.getStatusCode());
* System.out.printf("Delete operation 2 completed with status code: %d%n", deleteResponse2.getStatusCode());
* }, error -> System.err.printf("Batch submission failed. Error message: %s%n", error.getMessage()));
*
*
*
* @param batch Batch to submit.
* @param throwOnAnyFailure Flag to indicate if an exception should be thrown if any request in the batch fails.
* @return A response only containing header and status code information, used to indicate that the batch operation
* has completed.
* @throws BlobStorageException If the batch request is malformed.
* @throws BlobBatchStorageException If {@code throwOnAnyFailure} is {@code true} and any request in the {@link
* BlobBatch} failed.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono> submitBatchWithResponse(BlobBatch batch, boolean throwOnAnyFailure) {
try {
return withContext(context -> submitBatchWithResponse(batch, throwOnAnyFailure,
context));
} catch (RuntimeException ex) {
return monoError(LOGGER, ex);
}
}
Mono> submitBatchWithResponse(BlobBatch batch, boolean throwOnAnyFailure, Context context) {
Context finalContext = context == null ? Context.NONE : context;
return batch.prepareBlobBatchSubmission()
.flatMap(batchOperationInfo -> containerScoped
? client.getContainers().submitBatchWithResponseAsync(null,
batchOperationInfo.getContentLength(), batchOperationInfo.getContentType(),
Flux.fromIterable(batchOperationInfo.getBody()), null, null, finalContext)
.flatMap(response ->
BlobBatchHelper.mapBatchResponse(batchOperationInfo, response, throwOnAnyFailure, LOGGER))
: client.getServices().submitBatchWithResponseAsync(batchOperationInfo.getContentLength(),
batchOperationInfo.getContentType(), Flux.fromIterable(batchOperationInfo.getBody()), null, null, finalContext)
.flatMap(response ->
BlobBatchHelper.mapBatchResponse(batchOperationInfo, response, throwOnAnyFailure, LOGGER)));
}
/**
* Delete multiple blobs in a single request to the service.
*
* Code samples
*
*
*
* List<String> blobUrls = new ArrayList<>();
* blobUrls.add(blobClient1.getBlobUrl());
* blobUrls.add(blobClient2.getBlobUrl());
* blobUrls.add(blobClient3.getBlobUrl());
*
* batchAsyncClient.deleteBlobs(blobUrls, DeleteSnapshotsOptionType.INCLUDE).subscribe(response ->
* System.out.printf("Deleting blob with URL %s completed with status code %d%n",
* response.getRequest().getUrl(), response.getStatusCode()),
* error -> System.err.printf("Deleting blob failed with exception: %s%n", error.getMessage()));
*
*
*
* @param blobUrls Urls of the blobs to delete. Blob names must be encoded to UTF-8.
* @param deleteOptions The deletion option for all blobs.
* @return The status of each delete operation.
* @throws BlobStorageException If the batch request is malformed.
* @throws BlobBatchStorageException If any of the delete operations fail.
*/
@ServiceMethod(returns = ReturnType.COLLECTION)
public PagedFlux> deleteBlobs(List blobUrls, DeleteSnapshotsOptionType deleteOptions) {
try {
return new PagedFlux<>(
() -> withContext(context -> submitDeleteBlobsBatch(blobUrls, deleteOptions, context)));
} catch (RuntimeException ex) {
return pagedFluxError(LOGGER, ex);
}
}
PagedFlux> deleteBlobsWithTimeout(List blobUrls, DeleteSnapshotsOptionType deleteOptions,
Duration timeout, Context context) {
return new PagedFlux<>(() ->
StorageImplUtils.applyOptionalTimeout(submitDeleteBlobsBatch(blobUrls, deleteOptions, context), timeout));
}
private Mono>> submitDeleteBlobsBatch(List blobUrls,
DeleteSnapshotsOptionType deleteOptions, Context context) {
return submitBatchHelper(blobUrls, (batch, blobUrl) -> batch.deleteBlob(blobUrl, deleteOptions, null), context);
}
/**
* Set access tier on multiple blobs in a single request to the service.
*
* Code samples
*
*
*
* List<String> blobUrls = new ArrayList<>();
* blobUrls.add(blobClient1.getBlobUrl());
* blobUrls.add(blobClient2.getBlobUrl());
* blobUrls.add(blobClient3.getBlobUrl());
*
* batchAsyncClient.setBlobsAccessTier(blobUrls, AccessTier.HOT).subscribe(response ->
* System.out.printf("Setting blob access tier with URL %s completed with status code %d%n",
* response.getRequest().getUrl(), response.getStatusCode()),
* error -> System.err.printf("Setting blob access tier failed with exception: %s%n", error.getMessage()));
*
*
*
* @param blobUrls Urls of the blobs to set their access tier. Blob names must be encoded to UTF-8.
* @param accessTier {@link AccessTier} to set on each blob.
* @return The status of each set tier operation.
* @throws BlobStorageException If the batch request is malformed.
* @throws BlobBatchStorageException If any of the set tier operations fail.
*/
@ServiceMethod(returns = ReturnType.COLLECTION)
public PagedFlux> setBlobsAccessTier(List blobUrls, AccessTier accessTier) {
try {
return new PagedFlux<>(() -> withContext(context -> submitSetTierBatch(blobUrls, accessTier, context)));
} catch (RuntimeException ex) {
return pagedFluxError(LOGGER, ex);
}
}
PagedFlux> setBlobsAccessTierWithTimeout(List blobUrls, AccessTier accessTier,
Duration timeout, Context context) {
return new PagedFlux<>(() ->
StorageImplUtils.applyOptionalTimeout(submitSetTierBatch(blobUrls, accessTier, context), timeout));
}
private Mono>> submitSetTierBatch(List blobUrls, AccessTier accessTier,
Context context) {
return submitBatchHelper(blobUrls, (batch, blobUrl) -> batch.setBlobAccessTier(blobUrl, accessTier), context);
}
/*
* This helper method creates the batch request, applies the requested batching operation to each blob, sends the
* request to the service, and returns the responses.
*/
private Mono>> submitBatchHelper(List blobUrls,
BiFunction> generator, Context context) {
BlobBatch batch = getBlobBatch();
List> responses = new ArrayList<>();
for (String blobUrl : blobUrls) {
responses.add(generator.apply(batch, blobUrl));
}
return submitBatchWithResponse(batch, true, context)
.map(response -> initPagedResponse(responses, response));
}
private PagedResponse> initPagedResponse(List> values, Response response) {
return new PagedResponse>() {
@Override
public IterableStream> getElements() {
return new IterableStream<>(values);
}
@Override
public String getContinuationToken() {
return null;
}
@Override
public int getStatusCode() {
return response.getStatusCode();
}
@Override
public HttpHeaders getHeaders() {
return response.getHeaders();
}
@Override
public HttpRequest getRequest() {
return response.getRequest();
}
@Override
public void close() {
}
};
}
}