All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.azure.storage.blob.specialized.AppendBlobClient Maven / Gradle / Ivy

There is a newer version: 12.29.0
Show newest version
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.storage.blob.specialized;

import com.azure.core.annotation.ReturnType;
import com.azure.core.annotation.ServiceClient;
import com.azure.core.annotation.ServiceMethod;
import com.azure.core.exception.UnexpectedLengthException;
import com.azure.core.http.rest.Response;
import com.azure.core.util.Context;
import com.azure.storage.blob.BlobClient;
import com.azure.storage.blob.BlobClientBuilder;
import com.azure.storage.blob.BlobContainerClient;
import com.azure.storage.blob.BlobServiceClient;
import com.azure.storage.blob.models.AppendBlobItem;
import com.azure.storage.blob.models.AppendBlobRequestConditions;
import com.azure.storage.blob.models.BlobHttpHeaders;
import com.azure.storage.blob.models.BlobRange;
import com.azure.storage.blob.models.BlobRequestConditions;
import com.azure.storage.blob.models.BlobStorageException;
import com.azure.storage.blob.models.CustomerProvidedKey;
import com.azure.storage.blob.options.AppendBlobAppendBlockFromUrlOptions;
import com.azure.storage.blob.options.AppendBlobCreateOptions;
import com.azure.storage.blob.options.AppendBlobSealOptions;
import com.azure.storage.common.Utility;
import com.azure.storage.common.implementation.Constants;
import com.azure.storage.common.implementation.StorageImplUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.InputStream;
import java.nio.ByteBuffer;
import java.time.Duration;
import java.util.Map;
import java.util.Objects;

import static com.azure.storage.common.implementation.StorageImplUtils.blockWithOptionalTimeout;

/**
 * Client to an append blob. It may only be instantiated through a {@link SpecializedBlobClientBuilder} or via the
 * method {@link BlobClient#getAppendBlobClient()}. This class does not hold any state about a particular blob, but is
 * instead a convenient way of sending appropriate requests to the resource on the service.
 *
 * 

* This client contains operations on a blob. Operations on a container are available on {@link BlobContainerClient}, * and operations on the service are available on {@link BlobServiceClient}. * *

* Please refer to the Azure * Docs for more information. */ @ServiceClient(builder = SpecializedBlobClientBuilder.class) public final class AppendBlobClient extends BlobClientBase { private final AppendBlobAsyncClient appendBlobAsyncClient; /** * Indicates the maximum number of bytes that can be sent in a call to appendBlock. */ public static final int MAX_APPEND_BLOCK_BYTES = AppendBlobAsyncClient.MAX_APPEND_BLOCK_BYTES; /** * Indicates the maximum number of blocks allowed in an append blob. */ public static final int MAX_BLOCKS = AppendBlobAsyncClient.MAX_BLOCKS; /** * Package-private constructor for use by {@link BlobClientBuilder}. * * @param appendBlobAsyncClient the async append blob client */ AppendBlobClient(AppendBlobAsyncClient appendBlobAsyncClient) { super(appendBlobAsyncClient); this.appendBlobAsyncClient = appendBlobAsyncClient; } /** * Creates a new {@link AppendBlobClient} with the specified {@code encryptionScope}. * * @param encryptionScope the encryption scope for the blob, pass {@code null} to use no encryption scope. * @return a {@link AppendBlobClient} with the specified {@code encryptionScope}. */ @Override public AppendBlobClient getEncryptionScopeClient(String encryptionScope) { return new AppendBlobClient(appendBlobAsyncClient.getEncryptionScopeAsyncClient(encryptionScope)); } /** * Creates a new {@link AppendBlobClient} with the specified {@code customerProvidedKey}. * * @param customerProvidedKey the {@link CustomerProvidedKey} for the blob, * pass {@code null} to use no customer provided key. * @return a {@link AppendBlobClient} with the specified {@code customerProvidedKey}. */ @Override public AppendBlobClient getCustomerProvidedKeyClient(CustomerProvidedKey customerProvidedKey) { return new AppendBlobClient(appendBlobAsyncClient.getCustomerProvidedKeyAsyncClient(customerProvidedKey)); } /** * Creates and opens an output stream to write data to the append blob. If the blob already exists on the service, * new data will get appended to the existing blob. * * @return A {@link BlobOutputStream} object used to write data to the blob. * @throws BlobStorageException If a storage service error occurred. */ public BlobOutputStream getBlobOutputStream() { return getBlobOutputStream(null); } /** * Creates and opens an output stream to write data to the append blob. If overwrite is specified {@code true}, * the existing blob will be deleted and recreated, should data exist on the blob. If overwrite is specified * {@code false}, new data will get appended to the existing blob. * * @return A {@link BlobOutputStream} object used to write data to the blob. * @param overwrite Whether an existing blob should be deleted and recreated, should data exist on the blob. * @throws BlobStorageException If a storage service error occurred. */ public BlobOutputStream getBlobOutputStream(boolean overwrite) { AppendBlobRequestConditions requestConditions = null; if (!overwrite) { requestConditions = new AppendBlobRequestConditions().setIfNoneMatch(Constants.HeaderConstants.ETAG_WILDCARD); } else { // creating new blob to overwrite existing blob create(true); } return getBlobOutputStream(requestConditions); } /** * Creates and opens an output stream to write data to the append blob. * * @param requestConditions A {@link BlobRequestConditions} object that represents the access conditions for the * blob. * @return A {@link BlobOutputStream} object used to write data to the blob. * @throws BlobStorageException If a storage service error occurred. */ public BlobOutputStream getBlobOutputStream(AppendBlobRequestConditions requestConditions) { return BlobOutputStream.appendBlobOutputStream(appendBlobAsyncClient, requestConditions); } /** * Creates a 0-length append blob. Call appendBlock to append data to an append blob. By default this method will * not overwrite an existing blob. * *

Code Samples

* * *
     * System.out.printf("Created AppendBlob at %s%n", client.create().getLastModified());
     * 
* * * @return The information of the created appended blob. */ @ServiceMethod(returns = ReturnType.SINGLE) public AppendBlobItem create() { return create(false); } /** * Creates a 0-length append blob. Call appendBlock to append data to an append blob. * *

Code Samples

* * *
     * boolean overwrite = false; // Default value
     * System.out.printf("Created AppendBlob at %s%n", client.create(overwrite).getLastModified());
     * 
* * * @param overwrite Whether or not to overwrite, should data exist on the blob. * * @return The information of the created appended blob. */ @ServiceMethod(returns = ReturnType.SINGLE) public AppendBlobItem create(boolean overwrite) { BlobRequestConditions blobRequestConditions = new BlobRequestConditions(); if (!overwrite) { blobRequestConditions.setIfNoneMatch(Constants.HeaderConstants.ETAG_WILDCARD); } return createWithResponse(null, null, blobRequestConditions, null, Context.NONE).getValue(); } /** * Creates a 0-length append blob. Call appendBlock to append data to an append blob. *

* To avoid overwriting, pass "*" to {@link BlobRequestConditions#setIfNoneMatch(String)}. * *

Code Samples

* * *
     * BlobHttpHeaders headers = new BlobHttpHeaders()
     *     .setContentType("binary")
     *     .setContentLanguage("en-US");
     * Map<String, String> metadata = Collections.singletonMap("metadata", "value");
     * BlobRequestConditions requestConditions = new BlobRequestConditions()
     *     .setLeaseId(leaseId)
     *     .setIfUnmodifiedSince(OffsetDateTime.now().minusDays(3));
     * Context context = new Context("key", "value");
     *
     * System.out.printf("Created AppendBlob at %s%n",
     *     client.createWithResponse(headers, metadata, requestConditions, timeout, context).getValue()
     *         .getLastModified());
     * 
* * * @param headers {@link BlobHttpHeaders} * @param metadata Metadata to associate with the blob. If there is leading or trailing whitespace in any * metadata key or value, it must be removed or encoded. * @param requestConditions {@link BlobRequestConditions} * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @param context Additional context that is passed through the Http pipeline during the service call. * @return A {@link Response} whose {@link Response#getValue() value} contains the created appended blob. */ @ServiceMethod(returns = ReturnType.SINGLE) public Response createWithResponse(BlobHttpHeaders headers, Map metadata, BlobRequestConditions requestConditions, Duration timeout, Context context) { return this.createWithResponse(new AppendBlobCreateOptions().setHeaders(headers).setMetadata(metadata) .setRequestConditions(requestConditions), timeout, context); } /** * Creates a 0-length append blob. Call appendBlock to append data to an append blob. *

* To avoid overwriting, pass "*" to {@link BlobRequestConditions#setIfNoneMatch(String)}. * *

Code Samples

* * *
     * BlobHttpHeaders headers = new BlobHttpHeaders()
     *     .setContentType("binary")
     *     .setContentLanguage("en-US");
     * Map<String, String> metadata = Collections.singletonMap("metadata", "value");
     * Map<String, String> tags = Collections.singletonMap("tags", "value");
     * BlobRequestConditions requestConditions = new BlobRequestConditions()
     *     .setIfUnmodifiedSince(OffsetDateTime.now().minusDays(3));
     * Context context = new Context("key", "value");
     *
     * System.out.printf("Created AppendBlob at %s%n",
     *     client.createWithResponse(new AppendBlobCreateOptions().setHeaders(headers).setMetadata(metadata)
     *         .setTags(tags).setRequestConditions(requestConditions), timeout, context).getValue()
     *         .getLastModified());
     * 
* * * @param options {@link AppendBlobCreateOptions} * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @param context Additional context that is passed through the Http pipeline during the service call. * @return A {@link Response} whose {@link Response#getValue() value} contains the created appended blob. */ @ServiceMethod(returns = ReturnType.SINGLE) public Response createWithResponse(AppendBlobCreateOptions options, Duration timeout, Context context) { return StorageImplUtils.blockWithOptionalTimeout(appendBlobAsyncClient. createWithResponse(options, context), timeout); } /** * Creates a 0-length append blob if it does not exist. Call appendBlock to append data to an append blob. * *

Code Samples

* * *
     * client.createIfNotExists();
     * System.out.println("Created AppendBlob");
     * 
* * * @return {@link AppendBlobItem} containing information of the created appended blob. */ @ServiceMethod(returns = ReturnType.SINGLE) public AppendBlobItem createIfNotExists() { return createIfNotExistsWithResponse(new AppendBlobCreateOptions(), null, null).getValue(); } /** * Creates a 0-length append blob if it does not exist. Call appendBlock to append data to an append blob. * *

Code Samples

* * *
     * BlobHttpHeaders headers = new BlobHttpHeaders()
     *     .setContentType("binary")
     *     .setContentLanguage("en-US");
     * Map<String, String> metadata = Collections.singletonMap("metadata", "value");
     * Map<String, String> tags = Collections.singletonMap("tags", "value");
     * Context context = new Context("key", "value");
     *
     * Response<AppendBlobItem> response = client.createIfNotExistsWithResponse(new AppendBlobCreateOptions()
     *     .setHeaders(headers).setMetadata(metadata).setTags(tags), timeout, context);
     * if (response.getStatusCode() == 409) {
     *     System.out.println("Already existed.");
     * } else {
     *     System.out.printf("Create completed with status %d%n", response.getStatusCode());
     * }
     * 
* * * @param options {@link AppendBlobCreateOptions} * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @param context Additional context that is passed through the Http pipeline during the service call. * @return A reactive response {@link Response} signaling completion, whose {@link Response#getValue() value} * contains the {@link AppendBlobItem} containing information about the append blob. If {@link Response}'s status * code is 201, a new append blob was successfully created. If status code is 409, an append blob already existed at * this location. */ @ServiceMethod(returns = ReturnType.SINGLE) public Response createIfNotExistsWithResponse(AppendBlobCreateOptions options, Duration timeout, Context context) { return StorageImplUtils.blockWithOptionalTimeout(appendBlobAsyncClient. createIfNotExistsWithResponse(options, context), timeout); } /** * Commits a new block of data to the end of the existing append blob. *

* Note that the data passed must be replayable if retries are enabled (the default). In other words, the * {@code Flux} must produce the same data each time it is subscribed to. * *

Code Samples

* * *
     * System.out.printf("AppendBlob has %d committed blocks%n",
     *     client.appendBlock(data, length).getBlobCommittedBlockCount());
     * 
* * * @param data The data to write to the blob. The data must be markable. This is in order to support retries. If * the data is not markable, consider using {@link #getBlobOutputStream()} and writing to the returned OutputStream. * Alternatively, consider wrapping your data source in a {@link java.io.BufferedInputStream} to add mark support. * @param length The exact length of the data. It is important that this value match precisely the length of the * data emitted by the {@code Flux}. * @return The information of the append blob operation. */ @ServiceMethod(returns = ReturnType.SINGLE) public AppendBlobItem appendBlock(InputStream data, long length) { return appendBlockWithResponse(data, length, null, null, null, Context.NONE).getValue(); } /** * Commits a new block of data to the end of the existing append blob. *

* Note that the data passed must be replayable if retries are enabled (the default). In other words, the * {@code Flux} must produce the same data each time it is subscribed to. * *

Code Samples

* * *
     * byte[] md5 = MessageDigest.getInstance("MD5").digest("data".getBytes(StandardCharsets.UTF_8));
     * AppendBlobRequestConditions requestConditions = new AppendBlobRequestConditions()
     *     .setAppendPosition(POSITION)
     *     .setMaxSize(maxSize);
     * Context context = new Context("key", "value");
     *
     * System.out.printf("AppendBlob has %d committed blocks%n",
     *     client.appendBlockWithResponse(data, length, md5, requestConditions, timeout, context)
     *         .getValue().getBlobCommittedBlockCount());
     * 
* * * @param data The data to write to the blob. The data must be markable. This is in order to support retries. If * the data is not markable, consider using {@link #getBlobOutputStream()} and writing to the returned OutputStream. * Alternatively, consider wrapping your data source in a {@link java.io.BufferedInputStream} to add mark support. * @param length The exact length of the data. It is important that this value match precisely the length of the * data emitted by the {@code Flux}. * @param contentMd5 An MD5 hash of the block content. This hash is used to verify the integrity of the block during * transport. When this header is specified, the storage service compares the hash of the content that has arrived * with this header value. Note that this MD5 hash is not stored with the blob. If the two hashes do not match, the * operation will fail. * @param appendBlobRequestConditions {@link AppendBlobRequestConditions} * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @param context Additional context that is passed through the Http pipeline during the service call. * @return A {@link Response} whose {@link Response#getValue() value} contains the append blob operation. * @throws UnexpectedLengthException when the length of data does not match the input {@code length}. * @throws NullPointerException if the input data is null. */ @ServiceMethod(returns = ReturnType.SINGLE) public Response appendBlockWithResponse(InputStream data, long length, byte[] contentMd5, AppendBlobRequestConditions appendBlobRequestConditions, Duration timeout, Context context) { Objects.requireNonNull(data, "'data' cannot be null."); Flux fbb = Utility.convertStreamToByteBuffer(data, length, MAX_APPEND_BLOCK_BYTES, true); Mono> response = appendBlobAsyncClient.appendBlockWithResponse(fbb, length, contentMd5, appendBlobRequestConditions, context); return StorageImplUtils.blockWithOptionalTimeout(response, timeout); } /** * Commits a new block of data from another blob to the end of this append blob. * *

Code Samples

* * *
     * System.out.printf("AppendBlob has %d committed blocks%n",
     *     client.appendBlockFromUrl(sourceUrl, new BlobRange(offset, count)).getBlobCommittedBlockCount());
     * 
* * * @param sourceUrl The url to the blob that will be the source of the copy. A source blob in the same storage * account can be authenticated via Shared Key. However, if the source is a blob in another account, the source blob * must either be public or must be authenticated via a shared access signature. If the source blob is public, no * authentication is required to perform the operation. * @param sourceRange The source {@link BlobRange} to copy. * @return The information of the append blob operation. */ @ServiceMethod(returns = ReturnType.SINGLE) public AppendBlobItem appendBlockFromUrl(String sourceUrl, BlobRange sourceRange) { return appendBlockFromUrlWithResponse(sourceUrl, sourceRange, null, null, null, null, Context.NONE).getValue(); } /** * Commits a new block of data from another blob to the end of this append blob. * *

Code Samples

* * *
     * AppendBlobRequestConditions appendBlobRequestConditions = new AppendBlobRequestConditions()
     *     .setAppendPosition(POSITION)
     *     .setMaxSize(maxSize);
     *
     * BlobRequestConditions modifiedRequestConditions = new BlobRequestConditions()
     *     .setIfUnmodifiedSince(OffsetDateTime.now().minusDays(3));
     *
     * Context context = new Context("key", "value");
     *
     * System.out.printf("AppendBlob has %d committed blocks%n",
     *     client.appendBlockFromUrlWithResponse(sourceUrl, new BlobRange(offset, count), null,
     *         appendBlobRequestConditions, modifiedRequestConditions, timeout,
     *         context).getValue().getBlobCommittedBlockCount());
     * 
* * * @param sourceUrl The url to the blob that will be the source of the copy. A source blob in the same storage * account can be authenticated via Shared Key. However, if the source is a blob in another account, the source blob * must either be public or must be authenticated via a shared access signature. If the source blob is public, no * authentication is required to perform the operation. * @param sourceRange {@link BlobRange} * @param sourceContentMd5 An MD5 hash of the block content from the source blob. If specified, the service will * calculate the MD5 of the received data and fail the request if it does not match the provided MD5. * @param destRequestConditions {@link AppendBlobRequestConditions} * @param sourceRequestConditions {@link BlobRequestConditions} * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @param context Additional context that is passed through the Http pipeline during the service call. * @return The information of the append blob operation. */ @ServiceMethod(returns = ReturnType.SINGLE) public Response appendBlockFromUrlWithResponse(String sourceUrl, BlobRange sourceRange, byte[] sourceContentMd5, AppendBlobRequestConditions destRequestConditions, BlobRequestConditions sourceRequestConditions, Duration timeout, Context context) { Mono> response = appendBlobAsyncClient.appendBlockFromUrlWithResponse( new AppendBlobAppendBlockFromUrlOptions(sourceUrl).setSourceRange(sourceRange) .setSourceContentMd5(sourceContentMd5).setDestinationRequestConditions(destRequestConditions) .setSourceRequestConditions(sourceRequestConditions), context); return StorageImplUtils.blockWithOptionalTimeout(response, timeout); } /** * Commits a new block of data from another blob to the end of this append blob. * *

Code Samples

* * *
     * AppendBlobRequestConditions appendBlobRequestConditions = new AppendBlobRequestConditions()
     *     .setAppendPosition(POSITION)
     *     .setMaxSize(maxSize);
     *
     * BlobRequestConditions modifiedRequestConditions = new BlobRequestConditions()
     *     .setIfUnmodifiedSince(OffsetDateTime.now().minusDays(3));
     *
     * Context context = new Context("key", "value");
     *
     * System.out.printf("AppendBlob has %d committed blocks%n",
     *     client.appendBlockFromUrlWithResponse(new AppendBlobAppendBlockFromUrlOptions(sourceUrl)
     *         .setSourceRange(new BlobRange(offset, count))
     *         .setDestinationRequestConditions(appendBlobRequestConditions)
     *         .setSourceRequestConditions(modifiedRequestConditions), timeout,
     *         context).getValue().getBlobCommittedBlockCount());
     * 
* * * @param options options for the operation * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @param context Additional context that is passed through the Http pipeline during the service call. * @return The information of the append blob operation. */ @ServiceMethod(returns = ReturnType.SINGLE) public Response appendBlockFromUrlWithResponse(AppendBlobAppendBlockFromUrlOptions options, Duration timeout, Context context) { Mono> response = appendBlobAsyncClient.appendBlockFromUrlWithResponse( options, context); return StorageImplUtils.blockWithOptionalTimeout(response, timeout); } /** * Seals an append blob, making it read only. Any subsequent appends will fail. * *

Code Samples

* * *
     * client.seal();
     * System.out.println("Sealed AppendBlob");
     * 
* */ @ServiceMethod(returns = ReturnType.SINGLE) public void seal() { sealWithResponse(new AppendBlobSealOptions(), null, Context.NONE); } /** * Seals an append blob, making it read only. Any subsequent appends will fail. * *

Code Samples

* * *
     * AppendBlobRequestConditions requestConditions = new AppendBlobRequestConditions().setLeaseId(leaseId)
     *     .setIfUnmodifiedSince(OffsetDateTime.now().minusDays(3));
     * Context context = new Context("key", "value");
     *
     * client.sealWithResponse(new AppendBlobSealOptions().setRequestConditions(requestConditions), timeout, context);
     * System.out.println("Sealed AppendBlob");
     * 
* * * @param options {@link AppendBlobSealOptions} * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @param context Additional context that is passed through the Http pipeline during the service call. * @return A reactive response signalling completion. */ @ServiceMethod(returns = ReturnType.SINGLE) public Response sealWithResponse(AppendBlobSealOptions options, Duration timeout, Context context) { Mono> response = appendBlobAsyncClient.sealWithResponse(options, context); return blockWithOptionalTimeout(response, timeout); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy