diff --git a/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml b/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml index 8739e95c13ef..dcabb40ddc61 100755 --- a/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml +++ b/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml @@ -141,10 +141,8 @@ - - - - + + diff --git a/eng/code-quality-reports/src/main/resources/spotbugs/spotbugs-exclude.xml b/eng/code-quality-reports/src/main/resources/spotbugs/spotbugs-exclude.xml index f5210017b41e..4ed0344df783 100755 --- a/eng/code-quality-reports/src/main/resources/spotbugs/spotbugs-exclude.xml +++ b/eng/code-quality-reports/src/main/resources/spotbugs/spotbugs-exclude.xml @@ -453,8 +453,8 @@ - - + + @@ -579,7 +579,7 @@ - + diff --git a/eng/spotbugs-aggregate-report/pom.xml b/eng/spotbugs-aggregate-report/pom.xml index cab38e666c2d..bfaf59faac80 100644 --- a/eng/spotbugs-aggregate-report/pom.xml +++ b/eng/spotbugs-aggregate-report/pom.xml @@ -66,6 +66,7 @@ ..\..\sdk\core\azure-core-http-netty\src\main\java\com ..\..\sdk\core\azure-core-http-netty\src\samples\java\com ..\..\sdk\core\azure-core-http-okhttp\src\main\java\com + ..\..\sdk\core\azure-core-http-okhttp\src\samples\java\com ..\..\sdk\core\azure-core-management\src\main\java\com ..\..\sdk\core\azure-core-test\src\main\java\com ..\..\sdk\eventhubs\azure-messaging-eventhubs\src\main\java\com @@ -79,6 +80,7 @@ ..\..\sdk\storage\azure-storage-common\src\main\java\com + ..\..\sdk\storage\azure-storage-common\src\samples\java\com ..\..\sdk\storage\azure-storage-blob\src\main\java\com ..\..\sdk\storage\azure-storage-blob\src\samples\java\com ..\..\sdk\storage\azure-storage-blob-cryptography\src\main\java\com diff --git a/pom.client.xml b/pom.client.xml index 177ad83bf460..21b2e0801771 100644 --- a/pom.client.xml +++ b/pom.client.xml @@ -577,6 +577,7 @@ -snippetpath ${project.basedir}/sdk/keyvault/azure-keyvault-keys/src/samples/java -snippetpath ${project.basedir}/sdk/keyvault/azure-keyvault-secrets/src/samples/java -snippetpath ${project.basedir}/sdk/storage/azure-storage-blob/src/samples/java + -snippetpath ${project.basedir}/sdk/storage/azure-storage-common/src/samples/java -snippetpath ${project.basedir}/sdk/storage/azure-storage-file/src/samples/java -snippetpath ${project.basedir}/sdk/storage/azure-storage-queue/src/samples/java diff --git a/sdk/core/azure-core-http-okhttp/src/samples/java/com/azure/core/http/okhttp/OkHttpAsyncHttpClientBuilderJavaDocCodeSnippets.java b/sdk/core/azure-core-http-okhttp/src/samples/java/com/azure/core/http/okhttp/OkHttpAsyncHttpClientBuilderJavaDocCodeSnippets.java index 217454edf50c..acbe5308124e 100644 --- a/sdk/core/azure-core-http-okhttp/src/samples/java/com/azure/core/http/okhttp/OkHttpAsyncHttpClientBuilderJavaDocCodeSnippets.java +++ b/sdk/core/azure-core-http-okhttp/src/samples/java/com/azure/core/http/okhttp/OkHttpAsyncHttpClientBuilderJavaDocCodeSnippets.java @@ -26,7 +26,7 @@ public void simpleInstantiation() { // END: com.azure.core.http.okhttp.instantiation-simple } - private void proxySample() { + public void proxySample() { // BEGIN: com.azure.core.http.okhttp.OkHttpAsyncHttpClientBuilder#proxy final String proxyHost = ""; // e.g. localhost final int proxyPort = 9999; // Proxy port @@ -38,7 +38,7 @@ private void proxySample() { } - private void proxyBasicAuthenticationSample() { + public void proxyBasicAuthenticationSample() { // BEGIN: com.azure.core.http.okhttp.OkHttpAsyncHttpClientBuilder#setProxyAuthenticator final String proxyHost = ""; // e.g. localhost @@ -60,7 +60,7 @@ private void proxyBasicAuthenticationSample() { } - private void connectionTimeoutSample() { + public void connectionTimeoutSample() { // BEGIN: com.azure.core.http.okhttp.OkHttpAsyncHttpClientBuilder#connectionTimeout final Duration connectionTimeout = Duration.ofSeconds(250); // connection timeout of 250 seconds @@ -71,7 +71,7 @@ private void connectionTimeoutSample() { } - private void readTimeoutSample() { + public void readTimeoutSample() { // BEGIN: com.azure.core.http.okhttp.OkHttpAsyncHttpClientBuilder#readTimeout final Duration readTimeout = Duration.ofSeconds(100); // read timeout of 100 seconds @@ -82,7 +82,7 @@ private void readTimeoutSample() { } - private void usingExistingHttpClientSample() { + public void usingExistingHttpClientSample() { // BEGIN: com.azure.core.http.okhttp.using-existing-okhttp // Create an OkHttpClient with connection timeout of 250 seconds. diff --git a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobPartitionManager.java b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobPartitionManager.java index 13506b3d79ba..7656989a9302 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobPartitionManager.java +++ b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobPartitionManager.java @@ -3,6 +3,7 @@ package com.azure.messaging.eventhubs.checkpointstore.blob; +import com.azure.core.http.rest.Response; import com.azure.core.implementation.util.ImplUtils; import com.azure.core.util.logging.ClientLogger; import com.azure.messaging.eventhubs.EventProcessor; @@ -42,9 +43,10 @@ public class BlobPartitionManager implements PartitionManager { private static final String OFFSET = "Offset"; private static final String OWNER_ID = "OwnerId"; private static final String ETAG = "eTag"; + private static final String CLAIM_ERROR = "Couldn't claim ownership of partition {}, error {}"; private static final String BLOB_PATH_SEPARATOR = "/"; - private static final ByteBuffer UPLOAD_DATA = ByteBuffer.wrap("" .getBytes(UTF_8)); + private static final ByteBuffer UPLOAD_DATA = ByteBuffer.wrap("".getBytes(UTF_8)); private final ContainerAsyncClient containerAsyncClient; private final ClientLogger logger = new ClientLogger(BlobPartitionManager.class); @@ -90,57 +92,48 @@ public Flux listOwnership(String eventHubName, String consum @Override public Flux claimOwnership(PartitionOwnership... requestedPartitionOwnerships) { - return Flux.fromArray(requestedPartitionOwnerships).flatMap( - partitionOwnership -> { - - String partitionId = partitionOwnership.getPartitionId(); - String blobName = getBlobName(partitionOwnership.getEventHubName(), - partitionOwnership.getConsumerGroupName(), partitionId); - - if (!blobClients.containsKey(blobName)) { - blobClients.put(blobName, containerAsyncClient.getBlobAsyncClient(blobName)); - } - - BlobAsyncClient blobAsyncClient = blobClients.get(blobName); - - Metadata metadata = new Metadata(); - metadata.put(OWNER_ID, partitionOwnership.getOwnerId()); - Long offset = partitionOwnership.getOffset(); - metadata.put(OFFSET, offset == null ? null : String.valueOf(offset)); - Long sequenceNumber = partitionOwnership.getSequenceNumber(); - metadata.put(SEQUENCE_NUMBER, sequenceNumber == null ? null : String.valueOf(sequenceNumber)); - BlobAccessConditions blobAccessConditions = new BlobAccessConditions(); - if (ImplUtils.isNullOrEmpty(partitionOwnership.getETag())) { - // New blob should be created - blobAccessConditions.setModifiedAccessConditions(new ModifiedAccessConditions() - .setIfNoneMatch("*")); - return blobAsyncClient.asBlockBlobAsyncClient() - .uploadWithResponse(Flux.just(UPLOAD_DATA), 0, null, metadata, null, - blobAccessConditions) - .flatMapMany(response -> { - partitionOwnership.setETag(response.getHeaders().get(ETAG).getValue()); - return Mono.just(partitionOwnership); - }, error -> { - logger.info("Couldn't claim ownership of partition {}, error {}", partitionId, - error.getMessage()); - return Mono.empty(); - }, Mono::empty); - } else { - // update existing blob - blobAccessConditions.setModifiedAccessConditions(new ModifiedAccessConditions() - .setIfMatch(partitionOwnership.getETag())); - return blobAsyncClient.setMetadataWithResponse(metadata, blobAccessConditions) - .flatMapMany(response -> { - partitionOwnership.setETag(response.getHeaders().get(ETAG).getValue()); - return Mono.just(partitionOwnership); - }, error -> { - logger.info("Couldn't claim ownership of partition {}, error {}", partitionId, - error.getMessage()); - return Mono.empty(); - }, () -> Mono.empty()); - } + return Flux.fromArray(requestedPartitionOwnerships).flatMap(partitionOwnership -> { + String partitionId = partitionOwnership.getPartitionId(); + String blobName = getBlobName(partitionOwnership.getEventHubName(), + partitionOwnership.getConsumerGroupName(), partitionId); + + if (!blobClients.containsKey(blobName)) { + blobClients.put(blobName, containerAsyncClient.getBlobAsyncClient(blobName)); + } + + BlobAsyncClient blobAsyncClient = blobClients.get(blobName); + + Metadata metadata = new Metadata(); + metadata.put(OWNER_ID, partitionOwnership.getOwnerId()); + Long offset = partitionOwnership.getOffset(); + metadata.put(OFFSET, offset == null ? null : String.valueOf(offset)); + Long sequenceNumber = partitionOwnership.getSequenceNumber(); + metadata.put(SEQUENCE_NUMBER, sequenceNumber == null ? null : String.valueOf(sequenceNumber)); + BlobAccessConditions blobAccessConditions = new BlobAccessConditions(); + if (ImplUtils.isNullOrEmpty(partitionOwnership.getETag())) { + // New blob should be created + blobAccessConditions.setModifiedAccessConditions(new ModifiedAccessConditions().setIfNoneMatch("*")); + return blobAsyncClient.asBlockBlobAsyncClient() + .uploadWithResponse(Flux.just(UPLOAD_DATA), 0, null, metadata, null, blobAccessConditions) + .flatMapMany(response -> updateOwnershipETag(response, partitionOwnership), error -> { + logger.info(CLAIM_ERROR, partitionId, error.getMessage()); + return Mono.empty(); + }, Mono::empty); + } else { + // update existing blob + blobAccessConditions.setModifiedAccessConditions(new ModifiedAccessConditions() + .setIfMatch(partitionOwnership.getETag())); + return blobAsyncClient.setMetadataWithResponse(metadata, blobAccessConditions) + .flatMapMany(response -> updateOwnershipETag(response, partitionOwnership), error -> { + logger.info(CLAIM_ERROR, partitionId, error.getMessage()); + return Mono.empty(); + }, Mono::empty); } - ); + }); + } + + private Mono updateOwnershipETag(Response response, PartitionOwnership ownership) { + return Mono.just(ownership.setETag(response.getHeaders().get(ETAG).getValue())); } /** diff --git a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/test/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobPartitionManagerTest.java b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/test/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobPartitionManagerTest.java index 5a841063a780..b06a29cb9d76 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/test/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobPartitionManagerTest.java +++ b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/test/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobPartitionManagerTest.java @@ -12,7 +12,7 @@ import com.azure.messaging.eventhubs.models.Checkpoint; import com.azure.messaging.eventhubs.models.PartitionOwnership; import com.azure.storage.blob.BlobAsyncClient; -import com.azure.storage.blob.BlockBlobAsyncClient; +import com.azure.storage.blob.specialized.BlockBlobAsyncClient; import com.azure.storage.blob.ContainerAsyncClient; import com.azure.storage.blob.models.BlobAccessConditions; import com.azure.storage.blob.models.BlobItem; diff --git a/sdk/storage/azure-storage-blob/pom.xml b/sdk/storage/azure-storage-blob/pom.xml index 82af21f3a713..a9c6c14e255c 100644 --- a/sdk/storage/azure-storage-blob/pom.xml +++ b/sdk/storage/azure-storage-blob/pom.xml @@ -123,6 +123,15 @@ + + src/main/java + src/test/java + + + ${basedir}/src/test/resources + + + diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BaseBlobClientBuilder.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BaseBlobClientBuilder.java index 1a90f9c5b76b..3c8926c8133f 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BaseBlobClientBuilder.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BaseBlobClientBuilder.java @@ -3,6 +3,7 @@ package com.azure.storage.blob; +import com.azure.core.http.HttpPipeline; import com.azure.core.http.policy.UserAgentPolicy; import com.azure.storage.blob.models.CpkInfo; import com.azure.storage.blob.models.CustomerProvidedKey; @@ -10,32 +11,60 @@ import com.azure.storage.common.Constants; import com.azure.storage.common.policy.ResponseValidationPolicyBuilder; -abstract class BaseBlobClientBuilder> extends BaseClientBuilder { +/** + * Base builder for Azure Storage Blobs. + * @param Generic type that extends {@link BaseClientBuilder}. + */ +public abstract class BaseBlobClientBuilder> extends BaseClientBuilder { private static final String BLOB_ENDPOINT_MIDFIX = "blob"; - protected CpkInfo cpk; + protected CpkInfo customerProvidedKey; - @SuppressWarnings("unchecked") + /** + * Sets the {@link CustomerProvidedKey customer provided key} that is used to encrypt blob contents on the server. + * + * @param key Customer provided key containing the encryption key + * @return the updated builder object + */ public T customerProvidedKey(CustomerProvidedKey key) { - cpk = new CpkInfo() - .setEncryptionKey(key.getKey()) - .setEncryptionKeySha256(key.getKeySHA256()) - .setEncryptionAlgorithm(key.getEncryptionAlgorithm()); + if (key == null) { + customerProvidedKey = null; + } else { + customerProvidedKey = new CpkInfo() + .setEncryptionKey(key.getKey()) + .setEncryptionKeySha256(key.getKeySHA256()) + .setEncryptionAlgorithm(key.getEncryptionAlgorithm()); + } - return (T) this; + return getClazz().cast(this); } + /** + * Gets the {@link UserAgentPolicy user agent policy} that is used to set the User-Agent header for each request. + * + * @return the {@code UserAgentPolicy} that will be used in the {@link HttpPipeline}. + */ @Override protected final UserAgentPolicy getUserAgentPolicy() { return new UserAgentPolicy(BlobConfiguration.NAME, BlobConfiguration.VERSION, super.getConfiguration()); } + /** + * Gets the midfix used to create the resource URL. + * + * @return the Azure Storage Blob midfix. + */ @Override protected final String getServiceUrlMidfix() { return BLOB_ENDPOINT_MIDFIX; } + /** + * Configures the response validation rules that are applied to each request/response. + * + * @param builder Builder to assemble assertions together. + */ @Override protected final void applyServiceSpecificValidations(ResponseValidationPolicyBuilder builder) { // CPK diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java index c6d02c831d71..6adba7967424 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java @@ -3,143 +3,42 @@ package com.azure.storage.blob; -import com.azure.core.annotation.ServiceClient; -import com.azure.core.http.HttpPipeline; -import com.azure.core.http.HttpResponse; -import com.azure.core.http.rest.Response; -import com.azure.core.http.rest.SimpleResponse; -import com.azure.core.implementation.http.UrlBuilder; -import com.azure.core.implementation.util.FluxUtil; -import com.azure.core.util.Context; -import com.azure.core.util.logging.ClientLogger; import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; import com.azure.storage.blob.implementation.AzureBlobStorageImpl; -import com.azure.storage.blob.models.AccessTier; -import com.azure.storage.blob.models.BlobAccessConditions; -import com.azure.storage.blob.models.BlobHTTPHeaders; -import com.azure.storage.blob.models.BlobRange; -import com.azure.storage.blob.models.BlobStartCopyFromURLHeaders; import com.azure.storage.blob.models.CpkInfo; -import com.azure.storage.blob.models.DeleteSnapshotsOptionType; -import com.azure.storage.blob.models.LeaseAccessConditions; -import com.azure.storage.blob.models.Metadata; -import com.azure.storage.blob.models.ModifiedAccessConditions; -import com.azure.storage.blob.models.RehydratePriority; -import com.azure.storage.blob.models.ReliableDownloadOptions; -import com.azure.storage.blob.models.SourceModifiedAccessConditions; -import com.azure.storage.blob.models.StorageAccountInfo; -import com.azure.storage.blob.models.StorageException; -import com.azure.storage.blob.models.UserDelegationKey; -import com.azure.storage.common.Constants; -import com.azure.storage.common.IPRange; -import com.azure.storage.common.SASProtocol; -import com.azure.storage.common.Utility; -import com.azure.storage.common.credentials.SharedKeyCredential; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.UncheckedIOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.nio.ByteBuffer; -import java.nio.channels.AsynchronousFileChannel; -import java.nio.file.FileAlreadyExistsException; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.List; - -import static com.azure.core.implementation.util.FluxUtil.withContext; -import static com.azure.storage.blob.PostProcessor.postProcessResponse; +import com.azure.storage.blob.models.CustomerProvidedKey; +import com.azure.storage.blob.specialized.AppendBlobAsyncClient; +import com.azure.storage.blob.specialized.BlobAsyncClientBase; +import com.azure.storage.blob.specialized.BlockBlobAsyncClient; +import com.azure.storage.blob.specialized.PageBlobAsyncClient; +import com.azure.storage.blob.specialized.SpecializedBlobClientBuilder; /** - * Client to a blob of any type: block, append, or page. It may only be instantiated through a {@link BlobClientBuilder} - * or via the method {@link ContainerAsyncClient#getBlobAsyncClient(String)}. 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 class provides a client that contains generic blob operations for Azure Storage Blobs. Operations allowed by + * the client are downloading and copying a blob, retrieving and setting metadata, retrieving and setting HTTP headers, + * and deleting and un-deleting a blob. * *

- * This client offers the ability to download blobs. Note that uploading data is specific to each type of blob. Please - * refer to the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient} for upload options. This - * client can be converted into one of these clients easily through the methods {@link #asBlockBlobAsyncClient}, {@link - * #asPageBlobAsyncClient}, and {@link #asAppendBlobAsyncClient()}. + * This client is instantiated through {@link BlobClientBuilder} or retrieved via + * {@link ContainerAsyncClient#getBlobAsyncClient(String) getBlobClient}. * *

- * This client contains operations on a blob. Operations on a container are available on {@link ContainerAsyncClient}, - * and operations on the service are available on {@link BlobServiceAsyncClient}. + * For operations on a specific blob type (i.e append, block, or page) use + * {@link #asAppendBlobAsyncClient() asAppendBlobAsyncClient}, {@link #asBlockBlobAsyncClient() asBlockBlobAsyncClient}, + * or {@link #asPageBlobAsyncClient() asPageBlobAsyncClient} to construct a client that allows blob specific operations. * *

* Please refer to the Azure * Docs for more information. - * - *

- * Note this client is an async client that returns reactive responses from Spring Reactor Core project - * (https://projectreactor.io/). Calling the methods in this client will NOT start the actual network - * operation, until {@code .subscribe()} is called on the reactive response. You can simply convert one of these - * responses to a {@link java.util.concurrent.CompletableFuture} object through {@link Mono#toFuture()}. */ -@ServiceClient(builder = BlobClientBuilder.class, isAsync = true) -public class BlobAsyncClient { - private static final int BLOB_DEFAULT_DOWNLOAD_BLOCK_SIZE = 4 * Constants.MB; - private static final int BLOB_MAX_DOWNLOAD_BLOCK_SIZE = 100 * Constants.MB; - - private final ClientLogger logger = new ClientLogger(BlobAsyncClient.class); - - final AzureBlobStorageImpl azureBlobStorage; - protected final String snapshot; - protected final CpkInfo cpk; - +public class BlobAsyncClient extends BlobAsyncClientBase { /** * Package-private constructor for use by {@link BlobClientBuilder}. * * @param azureBlobStorage the API client for blob storage */ BlobAsyncClient(AzureBlobStorageImpl azureBlobStorage, String snapshot, CpkInfo cpk) { - this.azureBlobStorage = azureBlobStorage; - this.snapshot = snapshot; - this.cpk = cpk; - } - - /** - * Creates a new {@link BlockBlobAsyncClient} to this resource, maintaining configurations. Only do this for blobs - * that are known to be block blobs. - * - * @return A {@link BlockBlobAsyncClient} to this resource. - */ - public BlockBlobAsyncClient asBlockBlobAsyncClient() { - return new BlockBlobAsyncClient(new AzureBlobStorageBuilder() - .url(getBlobUrl().toString()) - .pipeline(azureBlobStorage.getHttpPipeline()) - .build(), snapshot, cpk); - } - - /** - * Creates a new {@link AppendBlobAsyncClient} to this resource, maintaining configurations. Only do this for blobs - * that are known to be append blobs. - * - * @return A {@link AppendBlobAsyncClient} to this resource. - */ - public AppendBlobAsyncClient asAppendBlobAsyncClient() { - return new AppendBlobAsyncClient(new AzureBlobStorageBuilder() - .url(getBlobUrl().toString()) - .pipeline(azureBlobStorage.getHttpPipeline()) - .build(), snapshot, cpk); - } - - /** - * Creates a new {@link PageBlobAsyncClient} to this resource, maintaining configurations. Only do this for blobs - * that are known to be page blobs. - * - * @return A {@link PageBlobAsyncClient} to this resource. - */ - public PageBlobAsyncClient asPageBlobAsyncClient() { - return new PageBlobAsyncClient(new AzureBlobStorageBuilder() - .url(getBlobUrl().toString()) - .pipeline(azureBlobStorage.getHttpPipeline()) - .build(), snapshot, cpk); + super(azureBlobStorage, snapshot, cpk); } /** @@ -148,1075 +47,52 @@ public PageBlobAsyncClient asPageBlobAsyncClient() { * @param snapshot the identifier for a specific snapshot of this blob * @return a {@link BlobAsyncClient} used to interact with the specific snapshot. */ + @Override public BlobAsyncClient getSnapshotClient(String snapshot) { return new BlobAsyncClient(new AzureBlobStorageBuilder() .url(getBlobUrl().toString()) .pipeline(azureBlobStorage.getHttpPipeline()) - .build(), snapshot, cpk); - } - - /** - * Initializes a {@link ContainerAsyncClient} object pointing to the container this blob is in. This method does not - * create a container. It simply constructs the client to the container and offers access to methods relevant to - * containers. - * - * @return A {@link ContainerAsyncClient} object pointing to the container containing the blob - */ - public ContainerAsyncClient getContainerAsyncClient() { - BlobURLParts parts = URLParser.parse(getBlobUrl()); - return new ContainerAsyncClient(new AzureBlobStorageBuilder() - .url(String.format("%s://%s/%s", parts.getScheme(), parts.getHost(), parts.getContainerName())) - .pipeline(azureBlobStorage.getHttpPipeline()) - .build(), cpk); - } - - /** - * Gets the URL of the blob represented by this client. - * - * @return the URL. - * @throws RuntimeException If the blob is using a malformed URL. - */ - public URL getBlobUrl() { - try { - UrlBuilder urlBuilder = UrlBuilder.parse(azureBlobStorage.getUrl()); - if (snapshot != null) { - urlBuilder.setQuery("snapshot=" + snapshot); - } - return urlBuilder.toURL(); - } catch (MalformedURLException e) { - throw logger.logExceptionAsError(new RuntimeException( - String.format("Invalid URL on %s: %s" + getClass().getSimpleName(), azureBlobStorage.getUrl()), e)); - } - } - - /** - * Gets the {@link HttpPipeline} powering this client. - * - * @return The pipeline. - */ - public HttpPipeline getHttpPipeline() { - return azureBlobStorage.getHttpPipeline(); - } - - /** - * Determines if the blob this client represents exists in the cloud. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.exists} - * - * @return true if the blob exists, false if it doesn't - */ - public Mono exists() { - return existsWithResponse().flatMap(FluxUtil::toMono); - } - - /** - * Determines if the blob this client represents exists in the cloud. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.existsWithResponse} - * - * @return true if the blob exists, false if it doesn't - */ - public Mono> existsWithResponse() { - return withContext(this::existsWithResponse); - } - - Mono> existsWithResponse(Context context) { - return this.getPropertiesWithResponse(null, context) - .map(cp -> (Response) new SimpleResponse<>(cp, true)) - .onErrorResume(t -> t instanceof StorageException && ((StorageException) t).getStatusCode() == 404, t -> { - HttpResponse response = ((StorageException) t).getResponse(); - return Mono.just(new SimpleResponse<>(response.getRequest(), response.getStatusCode(), - response.getHeaders(), false)); - }); - } - - /** - * Copies the data at the source URL to a blob. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.startCopyFromURL#URL} - * - *

For more information, see the - * Azure Docs

- * - * @param sourceURL The source URL to copy from. URLs outside of Azure may only be copied to block blobs. - * @return A reactive response containing the copy ID for the long running operation. - */ - public Mono startCopyFromURL(URL sourceURL) { - return startCopyFromURLWithResponse(sourceURL, null, null, null, null, null).flatMap(FluxUtil::toMono); - } - - /** - * Copies the data at the source URL to a blob. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.startCopyFromURLWithResponse#URL-Metadata-AccessTier-RehydratePriority-ModifiedAccessConditions-BlobAccessConditions} - * - *

For more information, see the - * Azure Docs

- * - * @param sourceURL The source URL to copy from. URLs outside of Azure may only be copied to block blobs. - * @param metadata {@link Metadata} - * @param tier {@link AccessTier} for the destination blob. - * @param priority {@link RehydratePriority} for rehydrating the blob. - * @param sourceModifiedAccessConditions {@link ModifiedAccessConditions} against the source. Standard HTTP Access - * conditions related to the modification of data. ETag and LastModifiedTime are used to construct conditions - * related to when the blob was changed relative to the given request. The request will fail if the specified - * condition is not satisfied. - * @param destAccessConditions {@link BlobAccessConditions} against the destination. - * @return A reactive response containing the copy ID for the long running operation. - */ - public Mono> startCopyFromURLWithResponse(URL sourceURL, Metadata metadata, AccessTier tier, - RehydratePriority priority, ModifiedAccessConditions sourceModifiedAccessConditions, - BlobAccessConditions destAccessConditions) { - return withContext(context -> startCopyFromURLWithResponse(sourceURL, metadata, tier, priority, - sourceModifiedAccessConditions, destAccessConditions, context)); - } - - Mono> startCopyFromURLWithResponse(URL sourceURL, Metadata metadata, AccessTier tier, - RehydratePriority priority, ModifiedAccessConditions sourceModifiedAccessConditions, - BlobAccessConditions destAccessConditions, Context context) { - metadata = metadata == null ? new Metadata() : metadata; - sourceModifiedAccessConditions = sourceModifiedAccessConditions == null - ? new ModifiedAccessConditions() : sourceModifiedAccessConditions; - destAccessConditions = destAccessConditions == null ? new BlobAccessConditions() : destAccessConditions; - - // We want to hide the SourceAccessConditions type from the user for consistency's sake, so we convert here. - SourceModifiedAccessConditions sourceConditions = new SourceModifiedAccessConditions() - .setSourceIfModifiedSince(sourceModifiedAccessConditions.getIfModifiedSince()) - .setSourceIfUnmodifiedSince(sourceModifiedAccessConditions.getIfUnmodifiedSince()) - .setSourceIfMatch(sourceModifiedAccessConditions.getIfMatch()) - .setSourceIfNoneMatch(sourceModifiedAccessConditions.getIfNoneMatch()); - - return postProcessResponse(this.azureBlobStorage.blobs().startCopyFromURLWithRestResponseAsync( - null, null, sourceURL, null, metadata, tier, priority, null, sourceConditions, - destAccessConditions.getModifiedAccessConditions(), destAccessConditions.getLeaseAccessConditions(), - context)) - .map(rb -> new SimpleResponse<>(rb, rb.getDeserializedHeaders().getCopyId())); - } - - /** - * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.abortCopyFromURL#String} - * - *

For more information, see the - * Azure Docs

- * - * @param copyId The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link - * BlobStartCopyFromURLHeaders} object. - * @return A reactive response signalling completion. - */ - public Mono abortCopyFromURL(String copyId) { - return abortCopyFromURLWithResponse(copyId, null).flatMap(FluxUtil::toMono); - } - - /** - * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.abortCopyFromURLWithResponse#String-LeaseAccessConditions} - * - *

For more information, see the - * Azure Docs

- * - * @param copyId The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link - * BlobStartCopyFromURLHeaders} object. - * @param leaseAccessConditions By setting lease access conditions, requests will fail if the provided lease does - * not match the active lease on the blob. - * @return A reactive response signalling completion. - */ - public Mono> abortCopyFromURLWithResponse(String copyId, - LeaseAccessConditions leaseAccessConditions) { - return withContext(context -> abortCopyFromURLWithResponse(copyId, leaseAccessConditions, context)); - } - - Mono> abortCopyFromURLWithResponse(String copyId, LeaseAccessConditions leaseAccessConditions, - Context context) { - return postProcessResponse(this.azureBlobStorage.blobs().abortCopyFromURLWithRestResponseAsync( - null, null, copyId, null, null, leaseAccessConditions, context)) - .map(response -> new SimpleResponse<>(response, null)); - } - - /** - * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.copyFromURL#URL} - * - *

For more information, see the - * Azure Docs

- * - * @param copySource The source URL to copy from. - * @return A reactive response containing the copy ID for the long running operation. - */ - public Mono copyFromURL(URL copySource) { - return copyFromURLWithResponse(copySource, null, null, null, null).flatMap(FluxUtil::toMono); - } - - /** - * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.copyFromURLWithResponse#URL-Metadata-AccessTier-ModifiedAccessConditions-BlobAccessConditions} - * - *

For more information, see the - * Azure Docs

- * - * @param copySource The source URL to copy from. URLs outside of Azure may only be copied to block blobs. - * @param metadata {@link Metadata} - * @param tier {@link AccessTier} for the destination blob. - * @param sourceModifiedAccessConditions {@link ModifiedAccessConditions} against the source. Standard HTTP Access - * conditions related to the modification of data. ETag and LastModifiedTime are used to construct conditions - * related to when the blob was changed relative to the given request. The request will fail if the specified - * condition is not satisfied. - * @param destAccessConditions {@link BlobAccessConditions} against the destination. - * @return A reactive response containing the copy ID for the long running operation. - */ - public Mono> copyFromURLWithResponse(URL copySource, Metadata metadata, AccessTier tier, - ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions) { - return withContext(context -> copyFromURLWithResponse(copySource, metadata, tier, - sourceModifiedAccessConditions, destAccessConditions, context)); - } - - Mono> copyFromURLWithResponse(URL copySource, Metadata metadata, AccessTier tier, - ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions, - Context context) { - metadata = metadata == null ? new Metadata() : metadata; - sourceModifiedAccessConditions = sourceModifiedAccessConditions == null - ? new ModifiedAccessConditions() : sourceModifiedAccessConditions; - destAccessConditions = destAccessConditions == null ? new BlobAccessConditions() : destAccessConditions; - - // We want to hide the SourceAccessConditions type from the user for consistency's sake, so we convert here. - SourceModifiedAccessConditions sourceConditions = new SourceModifiedAccessConditions() - .setSourceIfModifiedSince(sourceModifiedAccessConditions.getIfModifiedSince()) - .setSourceIfUnmodifiedSince(sourceModifiedAccessConditions.getIfUnmodifiedSince()) - .setSourceIfMatch(sourceModifiedAccessConditions.getIfMatch()) - .setSourceIfNoneMatch(sourceModifiedAccessConditions.getIfNoneMatch()); - - return postProcessResponse(this.azureBlobStorage.blobs().copyFromURLWithRestResponseAsync( - null, null, copySource, null, metadata, tier, null, sourceConditions, - destAccessConditions.getModifiedAccessConditions(), destAccessConditions.getLeaseAccessConditions(), - context)) - .map(rb -> new SimpleResponse<>(rb, rb.getDeserializedHeaders().getCopyId())); + .build(), getSnapshotId(), getCustomerProvidedKey()); } /** - * Reads the entire blob. Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or - * {@link AppendBlobClient}. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.download} + * Creates a new {@link AppendBlobAsyncClient} associated to this blob. * - *

For more information, see the - * Azure Docs

- * - * @return A reactive response containing the blob data. + * @return a {@link AppendBlobAsyncClient} associated to this blob. */ - public Mono> download() { - return downloadWithResponse(null, null, null, false).flatMap(FluxUtil::toMono); - } - - /** - * Reads a range of bytes from a blob. Uploading data must be done from the {@link BlockBlobClient}, {@link - * PageBlobClient}, or {@link AppendBlobClient}. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.downloadWithResponse#BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean} - * - *

For more information, see the - * Azure Docs

- * - * @param range {@link BlobRange} - * @param options {@link ReliableDownloadOptions} - * @param accessConditions {@link BlobAccessConditions} - * @param rangeGetContentMD5 Whether the contentMD5 for the specified blob range should be returned. - * @return A reactive response containing the blob data. - */ - public Mono>> downloadWithResponse(BlobRange range, ReliableDownloadOptions options, - BlobAccessConditions accessConditions, boolean rangeGetContentMD5) { - return withContext(context -> downloadWithResponse(range, options, accessConditions, rangeGetContentMD5, - context)); - } - - Mono>> downloadWithResponse(BlobRange range, ReliableDownloadOptions options, - BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Context context) { - return download(range, accessConditions, rangeGetContentMD5, context) - .map(response -> new SimpleResponse<>( - response.getRawResponse(), - response.body(options).switchIfEmpty(Flux.just(ByteBuffer.wrap(new byte[0]))))); - } - - /** - * Reads a range of bytes from a blob. The response also includes the blob's properties and metadata. For more - * information, see the Azure Docs. - *

- * Note that the response body has reliable download functionality built in, meaning that a failed download stream - * will be automatically retried. This behavior may be configured with {@link ReliableDownloadOptions}. - * - * @param range {@link BlobRange} - * @param accessConditions {@link BlobAccessConditions} - * @param rangeGetContentMD5 Whether the contentMD5 for the specified blob range should be returned. - * @return Emits the successful response. - */ - Mono download(BlobRange range, BlobAccessConditions accessConditions, - boolean rangeGetContentMD5) { - return withContext(context -> download(range, accessConditions, rangeGetContentMD5, context)); - } - - Mono download(BlobRange range, BlobAccessConditions accessConditions, - boolean rangeGetContentMD5, Context context) { - range = range == null ? new BlobRange(0) : range; - Boolean getMD5 = rangeGetContentMD5 ? rangeGetContentMD5 : null; - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - HTTPGetterInfo info = new HTTPGetterInfo() - .setOffset(range.getOffset()) - .setCount(range.getCount()) - .setETag(accessConditions.getModifiedAccessConditions().getIfMatch()); - - // TODO: range is BlobRange but expected as String - // TODO: figure out correct response - return postProcessResponse(this.azureBlobStorage.blobs().downloadWithRestResponseAsync( - null, null, snapshot, null, range.toHeaderValue(), getMD5, null, null, - accessConditions.getLeaseAccessConditions(), cpk, accessConditions.getModifiedAccessConditions(), context)) - // Convert the autorest response to a DownloadAsyncResponse, which enable reliable download. - .map(response -> { - // If there wasn't an etag originally specified, lock on the one returned. - info.setETag(response.getDeserializedHeaders().getETag()); - return new DownloadAsyncResponse(response, info, - // In the event of a stream failure, make a new request to pick up where we left off. - newInfo -> - this.download(new BlobRange(newInfo.getOffset(), newInfo.getCount()), - new BlobAccessConditions().setModifiedAccessConditions( - new ModifiedAccessConditions().setIfMatch(info.getETag())), false, context)); - }); - } - - - /** - * Downloads the entire blob into a file specified by the path. - * - *

The file will be created and must not exist, if the file already exists a {@link FileAlreadyExistsException} - * will be thrown.

- * - *

Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link - * AppendBlobClient}.

- * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.downloadToFile#String} - * - *

For more information, see the - * Azure Docs

- * - * @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written. - * @return An empty response - */ - public Mono downloadToFile(String filePath) { - return downloadToFile(filePath, null, BLOB_DEFAULT_DOWNLOAD_BLOCK_SIZE, null, null, false); - } - - /** - * Downloads the entire blob into a file specified by the path. - * - *

The file will be created and must not exist, if the file already exists a {@link FileAlreadyExistsException} - * will be thrown.

- * - *

Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link - * AppendBlobClient}.

- * - *

This method makes an extra HTTP call to get the length of the blob in the beginning. To avoid this extra - * call, - * provide the {@link BlobRange} parameter.

- * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.downloadToFile#String-BlobRange-Integer-ReliableDownloadOptions-BlobAccessConditions-boolean} - * - *

For more information, see the - * Azure Docs

- * - * @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written. - * @param range {@link BlobRange} - * @param blockSize the size of a chunk to download at a time, in bytes - * @param options {@link ReliableDownloadOptions} - * @param accessConditions {@link BlobAccessConditions} - * @param rangeGetContentMD5 Whether the contentMD5 for the specified blob range should be returned. - * @return An empty response - * @throws IllegalArgumentException If {@code blockSize} is less than 0 or greater than 100MB. - * @throws UncheckedIOException If an I/O error occurs. - */ - public Mono downloadToFile(String filePath, BlobRange range, Integer blockSize, - ReliableDownloadOptions options, BlobAccessConditions accessConditions, boolean rangeGetContentMD5) { - return withContext(context -> downloadToFile(filePath, range, blockSize, options, accessConditions, - rangeGetContentMD5, context)); - } - - Mono downloadToFile(String filePath, BlobRange range, Integer blockSize, ReliableDownloadOptions options, - BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Context context) { - if (blockSize != null) { - Utility.assertInBounds("blockSize", blockSize, 0, BLOB_MAX_DOWNLOAD_BLOCK_SIZE); - } - - return Mono.using(() -> downloadToFileResourceSupplier(filePath), - channel -> Mono.justOrEmpty(range) - .switchIfEmpty(getFullBlobRange(accessConditions)) - .flatMapMany(rg -> Flux.fromIterable(sliceBlobRange(rg, blockSize))) - .flatMap(chunk -> this.download(chunk, accessConditions, rangeGetContentMD5, context) - .subscribeOn(Schedulers.elastic()) - .flatMap(dar -> FluxUtil.writeFile(dar.body(options), channel, - chunk.getOffset() - (range == null ? 0 : range.getOffset())))) - .then(), this::downloadToFileCleanup); - } - - private AsynchronousFileChannel downloadToFileResourceSupplier(String filePath) { - try { - return AsynchronousFileChannel.open(Paths.get(filePath), StandardOpenOption.READ, StandardOpenOption.WRITE, - StandardOpenOption.CREATE_NEW); - } catch (IOException e) { - throw logger.logExceptionAsError(new UncheckedIOException(e)); - } - } - - private void downloadToFileCleanup(AsynchronousFileChannel channel) { - try { - channel.close(); - } catch (IOException e) { - throw logger.logExceptionAsError(new UncheckedIOException(e)); - } - } - - private Mono getFullBlobRange(BlobAccessConditions accessConditions) { - return getPropertiesWithResponse(accessConditions).map(rb -> new BlobRange(0, rb.getValue().getBlobSize())); - } - - private List sliceBlobRange(BlobRange blobRange, Integer blockSize) { - if (blockSize == null) { - blockSize = BLOB_DEFAULT_DOWNLOAD_BLOCK_SIZE; - } - long offset = blobRange.getOffset(); - long length = blobRange.getCount(); - List chunks = new ArrayList<>(); - for (long pos = offset; pos < offset + length; pos += blockSize) { - long count = blockSize; - if (pos + count > offset + length) { - count = offset + length - pos; - } - chunks.add(new BlobRange(pos, count)); - } - return chunks; - } - - /** - * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.delete} - * - *

For more information, see the - * Azure Docs

- * - * @return A reactive response signalling completion. - */ - public Mono delete() { - return deleteWithResponse(null, null).flatMap(FluxUtil::toMono); - } - - /** - * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.deleteWithResponse#DeleteSnapshotsOptionType-BlobAccessConditions} - * - *

For more information, see the - * Azure Docs

- * - * @param deleteBlobSnapshotOptions Specifies the behavior for deleting the snapshots on this blob. {@code Include} - * will delete the base blob and all snapshots. {@code Only} will delete only the snapshots. If a snapshot is being - * deleted, you must pass null. - * @param accessConditions {@link BlobAccessConditions} - * @return A reactive response signalling completion. - */ - public Mono> deleteWithResponse(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, - BlobAccessConditions accessConditions) { - return withContext(context -> deleteWithResponse(deleteBlobSnapshotOptions, accessConditions, context)); - } - - Mono> deleteWithResponse(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, - BlobAccessConditions accessConditions, Context context) { - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - return postProcessResponse(this.azureBlobStorage.blobs().deleteWithRestResponseAsync( - null, null, snapshot, null, deleteBlobSnapshotOptions, - null, accessConditions.getLeaseAccessConditions(), accessConditions.getModifiedAccessConditions(), - context)) - .map(response -> new SimpleResponse<>(response, null)); - } - - /** - * Returns the blob's metadata and properties. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.getProperties} - * - *

For more information, see the - * Azure Docs

- * - * @return A reactive response containing the blob properties and metadata. - */ - public Mono getProperties() { - return getPropertiesWithResponse(null).flatMap(FluxUtil::toMono); - } - - /** - * Returns the blob's metadata and properties. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.getPropertiesWithResponse#BlobAccessConditions} - * - *

For more information, see the - * Azure Docs

- * - * @param accessConditions {@link BlobAccessConditions} - * @return A reactive response containing the blob properties and metadata. - */ - public Mono> getPropertiesWithResponse(BlobAccessConditions accessConditions) { - return withContext(context -> getPropertiesWithResponse(accessConditions, context)); - } - - Mono> getPropertiesWithResponse(BlobAccessConditions accessConditions, Context context) { - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - return postProcessResponse(this.azureBlobStorage.blobs().getPropertiesWithRestResponseAsync( - null, null, snapshot, null, null, accessConditions.getLeaseAccessConditions(), cpk, - accessConditions.getModifiedAccessConditions(), context)) - .map(rb -> new SimpleResponse<>(rb, new BlobProperties(rb.getDeserializedHeaders()))); - } - - /** - * Changes a blob's HTTP header properties. if only one HTTP header is updated, the others will all be erased. In - * order to preserve existing values, they must be passed alongside the header being changed. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.setHTTPHeaders#BlobHTTPHeaders} - * - *

For more information, see the - * Azure Docs

- * - * @param headers {@link BlobHTTPHeaders} - * @return A reactive response signalling completion. - */ - public Mono setHTTPHeaders(BlobHTTPHeaders headers) { - return setHTTPHeadersWithResponse(headers, null).flatMap(FluxUtil::toMono); - } - - /** - * Changes a blob's HTTP header properties. if only one HTTP header is updated, the others will all be erased. In - * order to preserve existing values, they must be passed alongside the header being changed. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.setHTTPHeadersWithResponse#BlobHTTPHeaders-BlobAccessConditions} - * - *

For more information, see the - * Azure Docs

- * - * @param headers {@link BlobHTTPHeaders} - * @param accessConditions {@link BlobAccessConditions} - * @return A reactive response signalling completion. - */ - public Mono> setHTTPHeadersWithResponse(BlobHTTPHeaders headers, - BlobAccessConditions accessConditions) { - return withContext(context -> setHTTPHeadersWithResponse(headers, accessConditions, context)); - } - - Mono> setHTTPHeadersWithResponse(BlobHTTPHeaders headers, BlobAccessConditions accessConditions, - Context context) { - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - return postProcessResponse(this.azureBlobStorage.blobs().setHTTPHeadersWithRestResponseAsync( - null, null, null, null, headers, - accessConditions.getLeaseAccessConditions(), accessConditions.getModifiedAccessConditions(), context)) - .map(response -> new SimpleResponse<>(response, null)); - } - - /** - * Changes a blob's metadata. The specified metadata in this method will replace existing metadata. If old values - * must be preserved, they must be downloaded and included in the call to this method. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.setMetadata#Metadata} - * - *

For more information, see the - * Azure Docs

- * - * @param metadata {@link Metadata} - * @return A reactive response signalling completion. - */ - public Mono setMetadata(Metadata metadata) { - return setMetadataWithResponse(metadata, null).flatMap(FluxUtil::toMono); - } - - /** - * Changes a blob's metadata. The specified metadata in this method will replace existing metadata. If old values - * must be preserved, they must be downloaded and included in the call to this method. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.setMetadataWithResponse#Metadata-BlobAccessConditions} - * - *

For more information, see the - * Azure Docs

- * - * @param metadata {@link Metadata} - * @param accessConditions {@link BlobAccessConditions} - * @return A reactive response signalling completion. - */ - public Mono> setMetadataWithResponse(Metadata metadata, BlobAccessConditions accessConditions) { - return withContext(context -> setMetadataWithResponse(metadata, accessConditions, context)); - } - - Mono> setMetadataWithResponse(Metadata metadata, BlobAccessConditions accessConditions, - Context context) { - metadata = metadata == null ? new Metadata() : metadata; - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - return postProcessResponse(this.azureBlobStorage.blobs().setMetadataWithRestResponseAsync( - null, null, null, metadata, null, accessConditions.getLeaseAccessConditions(), cpk, - accessConditions.getModifiedAccessConditions(), context)) - .map(response -> new SimpleResponse<>(response, null)); - } - - /** - * Creates a read-only snapshot of the blob. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.createSnapshot} - * - *

For more information, see the - * Azure Docs

- * - * @return A response containing a {@link BlobAsyncClient} which is used to interact with the created snapshot, use - * {@link BlobAsyncClient#getSnapshotId()} to get the identifier for the snapshot. - */ - public Mono createSnapshot() { - return createSnapshotWithResponse(null, null).flatMap(FluxUtil::toMono); - } - - /** - * Creates a read-only snapshot of the blob. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.createSnapshotWithResponse#Metadata-BlobAccessConditions} - * - *

For more information, see the - * Azure Docs

- * - * @param metadata {@link Metadata} - * @param accessConditions {@link BlobAccessConditions} - * @return A response containing a {@link BlobAsyncClient} which is used to interact with the created snapshot, use - * {@link BlobAsyncClient#getSnapshotId()} to get the identifier for the snapshot. - */ - public Mono> createSnapshotWithResponse(Metadata metadata, - BlobAccessConditions accessConditions) { - return withContext(context -> createSnapshotWithResponse(metadata, accessConditions, context)); - } - - Mono> createSnapshotWithResponse(Metadata metadata, BlobAccessConditions accessConditions, - Context context) { - metadata = metadata == null ? new Metadata() : metadata; - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - return postProcessResponse(this.azureBlobStorage.blobs().createSnapshotWithRestResponseAsync( - null, null, null, metadata, null, cpk, accessConditions.getModifiedAccessConditions(), - accessConditions.getLeaseAccessConditions(), context)) - .map(rb -> new SimpleResponse<>(rb, this.getSnapshotClient(rb.getDeserializedHeaders().getSnapshot()))); - } - - /** - * Sets the tier on a blob. The operation is allowed on a page blob in a premium storage account or a block blob in - * a blob storage or GPV2 account. A premium page blob's tier determines the allowed size, IOPS, and bandwidth of - * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's - * etag. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.setTier#AccessTier} - * - *

For more information, see the - * Azure Docs

- * - * @param tier The new tier for the blob. - * @return A reactive response signalling completion. - */ - public Mono setTier(AccessTier tier) { - return setTierWithResponse(tier, null, null).flatMap(FluxUtil::toMono); - } - - /** - * Sets the tier on a blob. The operation is allowed on a page blob in a premium storage account or a block blob in - * a blob storage or GPV2 account. A premium page blob's tier determines the allowed size, IOPS, and bandwidth of - * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's - * etag. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.setTierWithResponse#AccessTier-RehydratePriority-LeaseAccessConditions} - * - *

For more information, see the - * Azure Docs

- * - * @param tier The new tier for the blob. - * @param priority Optional priority to set for re-hydrating blobs. - * @param leaseAccessConditions By setting lease access conditions, requests will fail if the provided lease does - * not match the active lease on the blob. - * @return A reactive response signalling completion. - */ - public Mono> setTierWithResponse(AccessTier tier, RehydratePriority priority, - LeaseAccessConditions leaseAccessConditions) { - return withContext(context -> setTierWithResponse(tier, priority, leaseAccessConditions, context)); - } - - Mono> setTierWithResponse(AccessTier tier, RehydratePriority priority, - LeaseAccessConditions leaseAccessConditions, Context context) { - Utility.assertNotNull("tier", tier); - - return postProcessResponse(this.azureBlobStorage.blobs().setTierWithRestResponseAsync( - null, null, tier, null, priority, null, leaseAccessConditions, context)) - .map(response -> new SimpleResponse<>(response, null)); - } - - /** - * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.undelete} - * - *

For more information, see the - * Azure Docs

- * - * @return A reactive response signalling completion. - */ - public Mono undelete() { - return undeleteWithResponse().flatMap(FluxUtil::toMono); - } - - /** - * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.undeleteWithResponse} - * - *

For more information, see the - * Azure Docs

- * - * @return A reactive response signalling completion. - */ - public Mono> undeleteWithResponse() { - return withContext(this::undeleteWithResponse); - } - - Mono> undeleteWithResponse(Context context) { - return postProcessResponse(this.azureBlobStorage.blobs().undeleteWithRestResponseAsync(null, - null, context)) - .map(response -> new SimpleResponse<>(response, null)); - } - - /** - * Returns the sku name and account kind for the account. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.getAccountInfo} - * - *

For more information, see the - * Azure Docs

- * - * @return a reactor response containing the sku name and account kind. - */ - public Mono getAccountInfo() { - return getAccountInfoWithResponse().flatMap(FluxUtil::toMono); - } - - /** - * Returns the sku name and account kind for the account. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.getAccountInfoWithResponse} - * - *

For more information, see the - * Azure Docs

- * - * @return a reactor response containing the sku name and account kind. - */ - public Mono> getAccountInfoWithResponse() { - return withContext(this::getAccountInfoWithResponse); - } - - Mono> getAccountInfoWithResponse(Context context) { - return postProcessResponse( - this.azureBlobStorage.blobs().getAccountInfoWithRestResponseAsync(null, null, context)) - .map(rb -> new SimpleResponse<>(rb, new StorageAccountInfo(rb.getDeserializedHeaders()))); - } - - /** - * Generates a user delegation SAS with the specified parameters - * - * @param userDelegationKey The {@code UserDelegationKey} user delegation key for the SAS - * @param accountName The {@code String} account name for the SAS - * @param permissions The {@code ContainerSASPermissions} permission for the SAS - * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS - * @return A string that represents the SAS token - */ - public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, String accountName, - BlobSASPermission permissions, OffsetDateTime expiryTime) { - return this.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime, null /* - startTime */, null /* version */, null /*sasProtocol */, null /* ipRange */, null /* cacheControl */, null - /*contentDisposition */, null /* contentEncoding */, null /* contentLanguage */, null /* contentType */); - } - - /** - * Generates a user delegation SAS token with the specified parameters - * - * @param userDelegationKey The {@code UserDelegationKey} user delegation key for the SAS - * @param accountName The {@code String} account name for the SAS - * @param permissions The {@code ContainerSASPermissions} permission for the SAS - * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS - * @param startTime An optional {@code OffsetDateTime} start time for the SAS - * @param version An optional {@code String} version for the SAS - * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS - * @param ipRange An optional {@code IPRange} ip address range for the SAS - * @return A string that represents the SAS token - */ - public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, String accountName, - BlobSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, - SASProtocol sasProtocol, IPRange ipRange) { - return this.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime, startTime, - version, sasProtocol, ipRange, null /* cacheControl */, null /* contentDisposition */, null /* - contentEncoding */, null /* contentLanguage */, null /* contentType */); - } - - /** - * Generates a user delegation SAS token with the specified parameters - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.generateUserDelegationSAS#UserDelegationKey-String-BlobSASPermission-OffsetDateTime-OffsetDateTime-String-SASProtocol-IPRange-String-String-String-String-String} - * - *

For more information, see the - * Azure - * Docs

- * - * @param userDelegationKey The {@code UserDelegationKey} user delegation key for the SAS - * @param accountName The {@code String} account name for the SAS - * @param permissions The {@code BlobSASPermission} permission for the SAS - * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS - * @param startTime An optional {@code OffsetDateTime} start time for the SAS - * @param version An optional {@code String} version for the SAS - * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS - * @param ipRange An optional {@code IPRange} ip address range for the SAS - * @param cacheControl An optional {@code String} cache-control header for the SAS. - * @param contentDisposition An optional {@code String} content-disposition header for the SAS. - * @param contentEncoding An optional {@code String} content-encoding header for the SAS. - * @param contentLanguage An optional {@code String} content-language header for the SAS. - * @param contentType An optional {@code String} content-type header for the SAS. - * @return A string that represents the SAS token - */ - public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, String accountName, - BlobSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, - SASProtocol sasProtocol, IPRange ipRange, String cacheControl, String contentDisposition, - String contentEncoding, String contentLanguage, String contentType) { - - BlobServiceSASSignatureValues blobServiceSASSignatureValues = new BlobServiceSASSignatureValues(version, - sasProtocol, startTime, expiryTime, permissions == null ? null : permissions.toString(), ipRange, - null /* identifier*/, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); - - BlobServiceSASSignatureValues values = configureServiceSASSignatureValues(blobServiceSASSignatureValues, - accountName); - - BlobServiceSASQueryParameters blobServiceSasQueryParameters = - values.generateSASQueryParameters(userDelegationKey); - - return blobServiceSasQueryParameters.encode(); - } - - /** - * Generates a SAS token with the specified parameters - * - * @param permissions The {@code BlobSASPermission} permission for the SAS - * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS - * @return A string that represents the SAS token - */ - public String generateSAS(BlobSASPermission permissions, OffsetDateTime expiryTime) { - return this.generateSAS(null, permissions, expiryTime, null /* startTime */, /* identifier */ null /* - version */, null /* sasProtocol */, null /* ipRange */, null /* cacheControl */, null /* contentLanguage*/, - null /* contentEncoding */, null /* contentLanguage */, null /* contentType */); + public AppendBlobAsyncClient asAppendBlobAsyncClient() { + return prepareBuilder().buildAppendBlobAsyncClient(); } /** - * Generates a SAS token with the specified parameters + * Creates a new {@link BlockBlobAsyncClient} associated to this blob. * - * @param identifier The {@code String} name of the access policy on the container this SAS references if any - * @return A string that represents the SAS token + * @return a {@link BlockBlobAsyncClient} associated to this blob. */ - public String generateSAS(String identifier) { - return this.generateSAS(identifier, null /* permissions */, null /* expiryTime */, null /* startTime */, - null /* version */, null /* sasProtocol */, null /* ipRange */, null /* cacheControl */, null /* - contentLanguage*/, null /* contentEncoding */, null /* contentLanguage */, null /* contentType */); + public BlockBlobAsyncClient asBlockBlobAsyncClient() { + return prepareBuilder().buildBlockBlobAsyncClient(); } /** - * Generates a SAS token with the specified parameters + * Creates a new {@link PageBlobAsyncClient} associated to this blob. * - * @param identifier The {@code String} name of the access policy on the container this SAS references if any - * @param permissions The {@code BlobSASPermission} permission for the SAS - * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS - * @param startTime An optional {@code OffsetDateTime} start time for the SAS - * @param version An optional {@code String} version for the SAS - * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS - * @param ipRange An optional {@code IPRange} ip address range for the SAS - * @return A string that represents the SAS token + * @return a {@link PageBlobAsyncClient} associated to this blob. */ - public String generateSAS(String identifier, BlobSASPermission permissions, OffsetDateTime expiryTime, - OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange) { - return this.generateSAS(identifier, permissions, expiryTime, startTime, version, sasProtocol, ipRange, null - /* cacheControl */, null /* contentLanguage*/, null /* contentEncoding */, null /* contentLanguage */, - null /* contentType */); - } - - /** - * Generates a SAS token with the specified parameters - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.generateSAS#String-BlobSASPermission-OffsetDateTime-OffsetDateTime-String-SASProtocol-IPRange-String-String-String-String-String} - * - *

For more information, see the - * Azure Docs

- * - * @param identifier The {@code String} name of the access policy on the container this SAS references if any - * @param permissions The {@code BlobSASPermission} permission for the SAS - * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS - * @param startTime An optional {@code OffsetDateTime} start time for the SAS - * @param version An optional {@code String} version for the SAS - * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS - * @param ipRange An optional {@code IPRange} ip address range for the SAS - * @param cacheControl An optional {@code String} cache-control header for the SAS. - * @param contentDisposition An optional {@code String} content-disposition header for the SAS. - * @param contentEncoding An optional {@code String} content-encoding header for the SAS. - * @param contentLanguage An optional {@code String} content-language header for the SAS. - * @param contentType An optional {@code String} content-type header for the SAS. - * @return A string that represents the SAS token - */ - public String generateSAS(String identifier, BlobSASPermission permissions, OffsetDateTime expiryTime, - OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange, String cacheControl, - String contentDisposition, String contentEncoding, String contentLanguage, String contentType) { - - BlobServiceSASSignatureValues blobServiceSASSignatureValues = new BlobServiceSASSignatureValues(version, - sasProtocol, startTime, expiryTime, permissions == null ? null : permissions.toString(), ipRange, - identifier, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); - - SharedKeyCredential sharedKeyCredential = - Utility.getSharedKeyCredential(this.azureBlobStorage.getHttpPipeline()); - - Utility.assertNotNull("sharedKeyCredential", sharedKeyCredential); - - BlobServiceSASSignatureValues values = configureServiceSASSignatureValues(blobServiceSASSignatureValues, - sharedKeyCredential.getAccountName()); - - BlobServiceSASQueryParameters blobServiceSasQueryParameters = - values.generateSASQueryParameters(sharedKeyCredential); - - return blobServiceSasQueryParameters.encode(); + public PageBlobAsyncClient asPageBlobAsyncClient() { + return prepareBuilder().buildPageBlobAsyncClient(); } - /** - * Sets blobServiceSASSignatureValues parameters dependent on the current blob type - */ - BlobServiceSASSignatureValues configureServiceSASSignatureValues( - BlobServiceSASSignatureValues blobServiceSASSignatureValues, String accountName) { - - // Set canonical name - blobServiceSASSignatureValues.setCanonicalName(this.azureBlobStorage.getUrl(), accountName); + private SpecializedBlobClientBuilder prepareBuilder() { + SpecializedBlobClientBuilder builder = new SpecializedBlobClientBuilder() + .pipeline(getHttpPipeline()) + .endpoint(getBlobUrl().toString()) + .snapshot(getSnapshotId()); - // Set snapshotId - blobServiceSASSignatureValues.setSnapshotId(getSnapshotId()); - - // Set resource - if (isSnapshot()) { - blobServiceSASSignatureValues.setResource(Constants.UrlConstants.SAS_BLOB_SNAPSHOT_CONSTANT); - } else { - blobServiceSASSignatureValues.setResource(Constants.UrlConstants.SAS_BLOB_CONSTANT); + CpkInfo cpk = getCustomerProvidedKey(); + if (cpk != null) { + builder.customerProvidedKey(new CustomerProvidedKey(cpk.getEncryptionKey())); } - return blobServiceSASSignatureValues; - } - - /** - * Gets the snapshotId for a blob resource - * - * @return A string that represents the snapshotId of the snapshot blob - */ - public String getSnapshotId() { - return this.snapshot; - } - - /** - * Determines if a blob is a snapshot - * - * @return A boolean that indicates if a blob is a snapshot - */ - public boolean isSnapshot() { - return this.snapshot != null; - } - - /** - * Get the container name. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.getContainerName} - * - * @return The name of the container. - */ - public final String getContainerName() { - return URLParser.parse(this.azureBlobStorage.getUrl(), logger).getContainerName(); - } - - /** - * Get the blob name. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobAsyncClient.getBlobName} - * - * @return The name of the blob. - */ - public final String getBlobName() { - return URLParser.parse(this.azureBlobStorage.getUrl(), logger).getBlobName(); + return builder; } } diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobClient.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobClient.java index cad8bdc0199a..ad5826626ec5 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobClient.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobClient.java @@ -3,102 +3,43 @@ package com.azure.storage.blob; -import com.azure.core.http.HttpPipeline; -import com.azure.core.http.rest.Response; -import com.azure.core.http.rest.SimpleResponse; import com.azure.core.annotation.ServiceClient; -import com.azure.core.implementation.util.FluxUtil; -import com.azure.core.util.Context; -import com.azure.core.util.logging.ClientLogger; -import com.azure.storage.blob.models.AccessTier; -import com.azure.storage.blob.models.BlobAccessConditions; -import com.azure.storage.blob.models.BlobHTTPHeaders; -import com.azure.storage.blob.models.BlobRange; -import com.azure.storage.blob.models.BlobStartCopyFromURLHeaders; -import com.azure.storage.blob.models.DeleteSnapshotsOptionType; -import com.azure.storage.blob.models.LeaseAccessConditions; -import com.azure.storage.blob.models.Metadata; -import com.azure.storage.blob.models.ModifiedAccessConditions; -import com.azure.storage.blob.models.RehydratePriority; -import com.azure.storage.blob.models.ReliableDownloadOptions; -import com.azure.storage.blob.models.StorageAccountInfo; -import com.azure.storage.blob.models.StorageException; -import com.azure.storage.blob.models.UserDelegationKey; -import com.azure.storage.common.IPRange; -import com.azure.storage.common.SASProtocol; -import com.azure.storage.common.Utility; -import reactor.core.publisher.Mono; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.UncheckedIOException; -import java.net.URL; -import java.nio.file.FileAlreadyExistsException; -import java.time.Duration; -import java.time.OffsetDateTime; +import com.azure.storage.blob.specialized.AppendBlobClient; +import com.azure.storage.blob.specialized.BlobClientBase; +import com.azure.storage.blob.specialized.BlockBlobClient; +import com.azure.storage.blob.specialized.PageBlobClient; +import com.azure.storage.blob.specialized.SpecializedBlobClientBuilder; /** - * Client to a blob of any type: block, append, or page. It may only be instantiated through a {@link BlobClientBuilder} - * or via the method {@link ContainerClient#getBlobClient(String)}. 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 class provides a client that contains generic blob operations for Azure Storage Blobs. Operations allowed by + * the client are downloading and copying a blob, retrieving and setting metadata, retrieving and setting HTTP headers, + * and deleting and un-deleting a blob. * *

- * This client offers the ability to download blobs. Note that uploading data is specific to each type of blob. Please - * refer to the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient} for upload options. This - * client can be converted into one of these clients easily through the methods {@link #asBlockBlobClient}, {@link - * #asPageBlobClient}, and {@link #asAppendBlobClient}. + * This client is instantiated through {@link BlobClientBuilder} or retrieved via + * {@link ContainerClient#getBlobClient(String) getBlobClient}. * *

- * This client contains operations on a blob. Operations on a container are available on {@link ContainerClient}, and - * operations on the service are available on {@link BlobServiceClient}. + * For operations on a specific blob type (i.e append, block, or page) use + * {@link #asAppendBlobClient() asAppendBlobClient}, {@link #asBlockBlobClient() asBlockBlobClient}, or + * {@link #asPageBlobClient() asPageBlobClient} to construct a client that allows blob specific operations. * *

* Please refer to the Azure * Docs for more information. */ @ServiceClient(builder = BlobClientBuilder.class) -public class BlobClient { - private final ClientLogger logger = new ClientLogger(BlobClient.class); - - private final BlobAsyncClient blobAsyncClient; +public class BlobClient extends BlobClientBase { + private final BlobAsyncClient client; /** * Package-private constructor for use by {@link BlobClientBuilder}. * - * @param blobAsyncClient the async blob client - */ - BlobClient(BlobAsyncClient blobAsyncClient) { - this.blobAsyncClient = blobAsyncClient; - } - - /** - * Creates a new {@link BlockBlobClient} to this resource, maintaining configurations. Only do this for blobs that - * are known to be block blobs. - * - * @return A {@link BlockBlobClient} to this resource. - */ - public BlockBlobClient asBlockBlobClient() { - return new BlockBlobClient(blobAsyncClient.asBlockBlobAsyncClient()); - } - - /** - * Creates a new {@link AppendBlobClient} to this resource, maintaining configurations. Only do this for blobs that - * are known to be append blobs. - * - * @return A {@link AppendBlobClient} to this resource. + * @param client the async blob client */ - public AppendBlobClient asAppendBlobClient() { - return new AppendBlobClient(blobAsyncClient.asAppendBlobAsyncClient()); - } - - /** - * Creates a new {@link PageBlobClient} to this resource, maintaining configurations. Only do this for blobs that - * are known to be page blobs. - * - * @return A {@link PageBlobClient} to this resource. - */ - public PageBlobClient asPageBlobClient() { - return new PageBlobClient(blobAsyncClient.asPageBlobAsyncClient()); + BlobClient(BlobAsyncClient client) { + super(client); + this.client = client; } /** @@ -107,858 +48,41 @@ public PageBlobClient asPageBlobClient() { * @param snapshot the identifier for a specific snapshot of this blob * @return a {@link BlobClient} used to interact with the specific snapshot. */ + @Override public BlobClient getSnapshotClient(String snapshot) { - return new BlobClient(blobAsyncClient.getSnapshotClient(snapshot)); - } - - /** - * Initializes a {@link ContainerClient} object pointing to the container this blob is in. This method does not - * create a container. It simply constructs the URL to the container and offers access to methods relevant to - * containers. - * - * @return A {@link ContainerClient} object pointing to the container containing the blob - */ - public ContainerClient getContainerClient() { - return new ContainerClient(blobAsyncClient.getContainerAsyncClient()); - } - - /** - * Gets the URL of the blob represented by this client. - * - * @return the URL. - */ - public URL getBlobUrl() { - return blobAsyncClient.getBlobUrl(); - } - - /** - * Gets the {@link HttpPipeline} powering this client. - * - * @return The pipeline. - */ - public HttpPipeline getHttpPipeline() { - return blobAsyncClient.getHttpPipeline(); - } - - /** - * Opens a blob input stream to download the blob. - *

- * - * @return An InputStream object that represents the stream to use for reading from the blob. - * @throws StorageException If a storage service error occurred. - */ - public final BlobInputStream openInputStream() { - return openInputStream(new BlobRange(0), null); - } - - /** - * Opens a blob input stream to download the specified range of the blob. - *

- * - * @param range {@link BlobRange} - * @param accessConditions An {@link BlobAccessConditions} object that represents the access conditions for the - * blob. - * @return An InputStream object that represents the stream to use for reading from the blob. - * @throws StorageException If a storage service error occurred. - */ - public final BlobInputStream openInputStream(BlobRange range, BlobAccessConditions accessConditions) { - return new BlobInputStream(blobAsyncClient, range.getOffset(), range.getCount(), accessConditions); - } - - /** - * Gets if the container this client represents exists in the cloud. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.exists} - * - * @return true if the container exists, false if it doesn't - */ - public boolean exists() { - return existsWithResponse(null, Context.NONE).getValue(); - } - - /** - * Gets if the container this client represents exists in the cloud. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.existsWithResponse#Duration-Context} - * - * @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 true if the container exists, false if it doesn't - */ - public Response existsWithResponse(Duration timeout, Context context) { - Mono> response = blobAsyncClient.existsWithResponse(context); - - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Copies the data at the source URL to a blob. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.startCopyFromURL#URL} - * - *

For more information, see the - * Azure Docs

- * - * @param sourceURL The source URL to copy from. URLs outside of Azure may only be copied to block blobs. - * @return The copy ID for the long running operation. - */ - public String startCopyFromURL(URL sourceURL) { - return startCopyFromURLWithResponse(sourceURL, null, null, null, null, null, null, Context.NONE).getValue(); - } - - /** - * Copies the data at the source URL to a blob. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.startCopyFromURLWithResponse#URL-Metadata-AccessTier-RehydratePriority-ModifiedAccessConditions-BlobAccessConditions-Duration-Context} - * - *

For more information, see the - * Azure Docs

- * - * @param sourceURL The source URL to copy from. URLs outside of Azure may only be copied to block blobs. - * @param metadata {@link Metadata} - * @param tier {@link AccessTier} for the destination blob. - * @param priority {@link RehydratePriority} for rehydrating the blob. - * @param sourceModifiedAccessConditions {@link ModifiedAccessConditions} against the source. Standard HTTP Access - * conditions related to the modification of data. ETag and LastModifiedTime are used to construct conditions - * related to when the blob was changed relative to the given request. The request will fail if the specified - * condition is not satisfied. - * @param destAccessConditions {@link BlobAccessConditions} against the destination. - * @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 copy ID for the long running operation. - */ - public Response startCopyFromURLWithResponse(URL sourceURL, Metadata metadata, AccessTier tier, - RehydratePriority priority, ModifiedAccessConditions sourceModifiedAccessConditions, - BlobAccessConditions destAccessConditions, Duration timeout, Context context) { - Mono> response = blobAsyncClient - .startCopyFromURLWithResponse(sourceURL, metadata, tier, priority, sourceModifiedAccessConditions, - destAccessConditions, context); - - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.abortCopyFromURL#String} - * - *

For more information, see the - * Azure Docs

- * - * @param copyId The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link - * BlobStartCopyFromURLHeaders} object. - */ - public void abortCopyFromURL(String copyId) { - abortCopyFromURLWithResponse(copyId, null, null, Context.NONE); - } - - /** - * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.abortCopyFromURLWithResponse#String-LeaseAccessConditions-Duration-Context} - * - *

For more information, see the - * Azure Docs

- * - * @param copyId The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link - * BlobStartCopyFromURLHeaders} object. - * @param leaseAccessConditions By setting lease access conditions, requests will fail if the provided lease does - * not match the active lease on the blob. - * @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 response containing status code and HTTP headers. - */ - public Response abortCopyFromURLWithResponse(String copyId, LeaseAccessConditions leaseAccessConditions, - Duration timeout, Context context) { - Mono> response = blobAsyncClient.abortCopyFromURLWithResponse(copyId, leaseAccessConditions, - context); - - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.copyFromURL#URL} - * - *

For more information, see the - * Azure Docs

- * - * @param copySource The source URL to copy from. - * @return The copy ID for the long running operation. - */ - public String copyFromURL(URL copySource) { - return copyFromURLWithResponse(copySource, null, null, null, null, null, Context.NONE).getValue(); - } - - /** - * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.copyFromURLWithResponse#URL-Metadata-AccessTier-ModifiedAccessConditions-BlobAccessConditions-Duration-Context} - * - *

For more information, see the - * Azure Docs

- * - * @param copySource The source URL to copy from. URLs outside of Azure may only be copied to block blobs. - * @param metadata {@link Metadata} - * @param tier {@link AccessTier} for the destination blob. - * @param sourceModifiedAccessConditions {@link ModifiedAccessConditions} against the source. Standard HTTP Access - * conditions related to the modification of data. ETag and LastModifiedTime are used to construct conditions - * related to when the blob was changed relative to the given request. The request will fail if the specified - * condition is not satisfied. - * @param destAccessConditions {@link BlobAccessConditions} against the destination. - * @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 copy ID for the long running operation. - */ - public Response copyFromURLWithResponse(URL copySource, Metadata metadata, AccessTier tier, - ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions, - Duration timeout, Context context) { - Mono> response = blobAsyncClient - .copyFromURLWithResponse(copySource, metadata, tier, sourceModifiedAccessConditions, destAccessConditions, - context); - - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Downloads the entire blob into an output stream. Uploading data must be done from the {@link BlockBlobClient}, - * {@link PageBlobClient}, or {@link AppendBlobClient}. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.download#OutputStream} - * - *

For more information, see the - * Azure Docs

- * - * @param stream A non-null {@link OutputStream} instance where the downloaded data will be written. - * @throws UncheckedIOException If an I/O error occurs. - */ - public void download(OutputStream stream) { - downloadWithResponse(stream, null, null, null, false, null, Context.NONE); - } - - /** - * Downloads a range of bytes from a blob into an output stream. Uploading data must be done from the {@link - * BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient}. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.downloadWithResponse#OutputStream-BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration-Context} - * - *

For more information, see the - * Azure Docs

- * - * @param stream A non-null {@link OutputStream} instance where the downloaded data will be written. - * @param range {@link BlobRange} - * @param options {@link ReliableDownloadOptions} - * @param accessConditions {@link BlobAccessConditions} - * @param rangeGetContentMD5 Whether the contentMD5 for the specified blob range should be returned. - * @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 response containing status code and HTTP headers. - * @throws UncheckedIOException If an I/O error occurs. - * @throws NullPointerException If stream is null - */ - public Response downloadWithResponse(OutputStream stream, BlobRange range, ReliableDownloadOptions options, - BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Duration timeout, Context context) { - Utility.assertNotNull("stream", stream); - Mono> download = blobAsyncClient - .downloadWithResponse(range, options, accessConditions, rangeGetContentMD5, context) - .flatMapMany(res -> res.getValue() - .doOnNext(bf -> { - try { - stream.write(FluxUtil.byteBufferToArray(bf)); - } catch (IOException e) { - throw logger.logExceptionAsError(new UncheckedIOException(e)); - } - }).map(bf -> res)) - .last() - .map(response -> new SimpleResponse<>(response, null)); - - return Utility.blockWithOptionalTimeout(download, timeout); - } - - /** - * Downloads the entire blob into a file specified by the path. - * - *

The file will be created and must not exist, if the file already exists a {@link FileAlreadyExistsException} - * will be thrown.

- * - *

Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link - * AppendBlobClient}.

- * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.downloadToFile#String} - * - *

For more information, see the - * Azure Docs

- * - * @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written. - * @throws UncheckedIOException If an I/O error occurs - */ - public void downloadToFile(String filePath) { - downloadToFile(filePath, null, null, null, null, false, null, Context.NONE); - } - - /** - * Downloads the entire blob into a file specified by the path. - * - *

The file will be created and must not exist, if the file already exists a {@link FileAlreadyExistsException} - * will be thrown.

- * - *

Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link - * AppendBlobClient}.

- * - *

This method makes an extra HTTP call to get the length of the blob in the beginning. To avoid this extra - * call, provide the {@link BlobRange} parameter.

- * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.downloadToFile#String-BlobRange-Integer-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration-Context} - * - *

For more information, see the - * Azure Docs

- * - * @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written. - * @param range {@link BlobRange} - * @param blockSize the size of a chunk to download at a time, in bytes - * @param options {@link ReliableDownloadOptions} - * @param accessConditions {@link BlobAccessConditions} - * @param rangeGetContentMD5 Whether the contentMD5 for the specified blob range should be returned. - * @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. - * @throws UncheckedIOException If an I/O error occurs - */ - public void downloadToFile(String filePath, BlobRange range, Integer blockSize, ReliableDownloadOptions options, - BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Duration timeout, Context context) { - Mono download = blobAsyncClient.downloadToFile(filePath, range, blockSize, options, accessConditions, - rangeGetContentMD5, context); - - Utility.blockWithOptionalTimeout(download, timeout); - } - - /** - * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.delete} - * - *

For more information, see the - * Azure Docs

- */ - public void delete() { - deleteWithResponse(null, null, null, Context.NONE); - } - - /** - * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.deleteWithResponse#DeleteSnapshotsOptionType-BlobAccessConditions-Duration-Context} - * - *

For more information, see the - * Azure Docs

- * - * @param deleteBlobSnapshotOptions Specifies the behavior for deleting the snapshots on this blob. {@code Include} - * will delete the base blob and all snapshots. {@code Only} will delete only the snapshots. If a snapshot is being - * deleted, you must pass null. - * @param accessConditions {@link BlobAccessConditions} - * @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 response containing status code and HTTP headers. - */ - public Response deleteWithResponse(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, - BlobAccessConditions accessConditions, Duration timeout, Context context) { - Mono> response = blobAsyncClient - .deleteWithResponse(deleteBlobSnapshotOptions, accessConditions, context); - - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Returns the blob's metadata and properties. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.getProperties} - * - *

For more information, see the - * Azure Docs

- * - * @return The blob properties and metadata. - */ - public BlobProperties getProperties() { - return getPropertiesWithResponse(null, null, Context.NONE).getValue(); - } - - /** - * Returns the blob's metadata and properties. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.getPropertiesWithResponse#BlobAccessConditions-Duration-Context} - * - *

For more information, see the - * Azure Docs

- * - * @param accessConditions {@link BlobAccessConditions} - * @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 blob properties and metadata. - */ - public Response getPropertiesWithResponse(BlobAccessConditions accessConditions, Duration timeout, - Context context) { - Mono> response = blobAsyncClient.getPropertiesWithResponse(accessConditions, context); - - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Changes a blob's HTTP header properties. if only one HTTP header is updated, the others will all be erased. In - * order to preserve existing values, they must be passed alongside the header being changed. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.setHTTPHeaders#BlobHTTPHeaders} - * - *

For more information, see the - * Azure Docs

- * - * @param headers {@link BlobHTTPHeaders} - */ - public void setHTTPHeaders(BlobHTTPHeaders headers) { - setHTTPHeadersWithResponse(headers, null, null, Context.NONE); + return new BlobClient(client.getSnapshotClient(snapshot)); } /** - * Changes a blob's HTTP header properties. if only one HTTP header is updated, the others will all be erased. In - * order to preserve existing values, they must be passed alongside the header being changed. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.setHTTPHeadersWithResponse#BlobHTTPHeaders-BlobAccessConditions-Duration-Context} - * - *

For more information, see the - * Azure Docs

- * - * @param headers {@link BlobHTTPHeaders} - * @param accessConditions {@link BlobAccessConditions} - * @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 response containing status code and HTTP headers. - */ - public Response setHTTPHeadersWithResponse(BlobHTTPHeaders headers, BlobAccessConditions accessConditions, - Duration timeout, Context context) { - Mono> response = blobAsyncClient - .setHTTPHeadersWithResponse(headers, accessConditions, context); - - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Changes a blob's metadata. The specified metadata in this method will replace existing metadata. If old values - * must be preserved, they must be downloaded and included in the call to this method. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.setMetadata#Metadata} - * - *

For more information, see the - * Azure Docs

- * - * @param metadata {@link Metadata} - */ - public void setMetadata(Metadata metadata) { - setMetadataWithResponse(metadata, null, null, Context.NONE); - } - - /** - * Changes a blob's metadata. The specified metadata in this method will replace existing metadata. If old values - * must be preserved, they must be downloaded and included in the call to this method. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.setMetadataWithResponse#Metadata-BlobAccessConditions-Duration-Context} - * - *

For more information, see the - * Azure Docs

- * - * @param metadata {@link Metadata} - * @param accessConditions {@link BlobAccessConditions} - * @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 response containing status code and HTTP headers. - */ - public Response setMetadataWithResponse(Metadata metadata, BlobAccessConditions accessConditions, - Duration timeout, Context context) { - Mono> response = blobAsyncClient.setMetadataWithResponse(metadata, accessConditions, context); - - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Creates a read-only snapshot of the blob. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.createSnapshot} - * - *

For more information, see the - * Azure Docs

- * - * @return A response containing a {@link BlobClient} which is used to interact with the created snapshot, use - * {@link BlobClient#getSnapshotId()} to get the identifier for the snapshot. - */ - public BlobClient createSnapshot() { - return createSnapshotWithResponse(null, null, null, Context.NONE).getValue(); - } - - - /** - * Creates a read-only snapshot of the blob. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.createSnapshotWithResponse#Metadata-BlobAccessConditions-Duration-Context} - * - *

For more information, see the - * Azure Docs

- * - * @param metadata {@link Metadata} - * @param accessConditions {@link BlobAccessConditions} - * @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 response containing a {@link BlobClient} which is used to interact with the created snapshot, use - * {@link BlobClient#getSnapshotId()} to get the identifier for the snapshot. - */ - public Response createSnapshotWithResponse(Metadata metadata, BlobAccessConditions accessConditions, - Duration timeout, Context context) { - Mono> response = blobAsyncClient - .createSnapshotWithResponse(metadata, accessConditions, context) - .map(rb -> new SimpleResponse<>(rb, new BlobClient(rb.getValue()))); - - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Sets the tier on a blob. The operation is allowed on a page blob in a premium storage account or a block blob in - * a blob storage or GPV2 account. A premium page blob's tier determines the allowed size, IOPS, and bandwidth of - * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's - * etag. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.setTier#AccessTier} - * - *

For more information, see the - * Azure Docs

- * - * @param tier The new tier for the blob. - */ - public void setTier(AccessTier tier) { - setTierWithResponse(tier, null, null, null, Context.NONE); - } - - /** - * Sets the tier on a blob. The operation is allowed on a page blob in a premium storage account or a block blob in - * a blob storage or GPV2 account. A premium page blob's tier determines the allowed size, IOPS, and bandwidth of - * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's - * etag. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.setTierWithResponse#AccessTier-RehydratePriority-LeaseAccessConditions-Duration-Context} - * - *

For more information, see the - * Azure Docs

- * - * @param tier The new tier for the blob. - * @param priority Optional priority to set for re-hydrating blobs. - * @param leaseAccessConditions By setting lease access conditions, requests will fail if the provided lease does - * not match the active lease on the blob. - * @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 response containing status code and HTTP headers. - */ - public Response setTierWithResponse(AccessTier tier, RehydratePriority priority, - LeaseAccessConditions leaseAccessConditions, Duration timeout, Context context) { - Mono> response = blobAsyncClient.setTierWithResponse(tier, priority, leaseAccessConditions, - context); - - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.undelete} + * Creates a new {@link AppendBlobClient} associated to this blob. * - *

For more information, see the - * Azure Docs

+ * @return a {@link AppendBlobClient} associated to this blob. */ - public void undelete() { - undeleteWithResponse(null, Context.NONE); - } - - /** - * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.undeleteWithResponse#Duration-Context} - * - *

For more information, see the - * Azure Docs

- * - * @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 response containing status code and HTTP headers. - */ - public Response undeleteWithResponse(Duration timeout, Context context) { - Mono> response = blobAsyncClient.undeleteWithResponse(context); - - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Returns the sku name and account kind for the account. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.getAccountInfo} - * - *

For more information, see the - * Azure Docs

- * - * @return The sku name and account kind. - */ - public StorageAccountInfo getAccountInfo() { - return getAccountInfoWithResponse(null, Context.NONE).getValue(); - } - - /** - * Returns the sku name and account kind for the account. - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.getAccountInfoWithResponse#Duration-Context} - * - *

For more information, see the - * Azure Docs

- * - * @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 sku name and account kind. - */ - public Response getAccountInfoWithResponse(Duration timeout, Context context) { - Mono> response = blobAsyncClient.getAccountInfoWithResponse(context); - - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Generates a user delegation SAS token with the specified parameters - * - * @param userDelegationKey The {@code UserDelegationKey} user delegation key for the SAS - * @param accountName The {@code String} account name for the SAS - * @param permissions The {@code BlobSASPermission} permission for the SAS - * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS - * @return A string that represents the SAS token - */ - public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, String accountName, - BlobSASPermission permissions, OffsetDateTime expiryTime) { - return this.blobAsyncClient.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime); - } - - /** - * Generates a user delegation SAS token with the specified parameters - * - * @param userDelegationKey The {@code UserDelegationKey} user delegation key for the SAS - * @param accountName The {@code String} account name for the SAS - * @param permissions The {@code BlobSASPermission} permission for the SAS - * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS - * @param startTime An optional {@code OffsetDateTime} start time for the SAS - * @param version An optional {@code String} version for the SAS - * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS - * @param ipRange An optional {@code IPRange} ip address range for the SAS - * @return A string that represents the SAS token - */ - public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, String accountName, - BlobSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, - SASProtocol sasProtocol, IPRange ipRange) { - return this.blobAsyncClient.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime, - startTime, version, sasProtocol, ipRange); - } - - /** - * Generates a user delegation SAS token with the specified parameters - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.generateUserDelegationSAS#UserDelegationKey-String-BlobSASPermission-OffsetDateTime-OffsetDateTime-String-SASProtocol-IPRange-String-String-String-String-String} - * - *

For more information, see the - * Azure - * Docs

- * - * @param userDelegationKey The {@code UserDelegationKey} user delegation key for the SAS - * @param accountName The {@code String} account name for the SAS - * @param permissions The {@code BlobSASPermission} permission for the SAS - * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS - * @param startTime An optional {@code OffsetDateTime} start time for the SAS - * @param version An optional {@code String} version for the SAS - * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS - * @param ipRange An optional {@code IPRange} ip address range for the SAS - * @param cacheControl An optional {@code String} cache-control header for the SAS. - * @param contentDisposition An optional {@code String} content-disposition header for the SAS. - * @param contentEncoding An optional {@code String} content-encoding header for the SAS. - * @param contentLanguage An optional {@code String} content-language header for the SAS. - * @param contentType An optional {@code String} content-type header for the SAS. - * @return A string that represents the SAS token - */ - public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, String accountName, - BlobSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, - SASProtocol sasProtocol, IPRange ipRange, String cacheControl, String contentDisposition, - String contentEncoding, String contentLanguage, String contentType) { - return this.blobAsyncClient.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime, - startTime, version, sasProtocol, ipRange, cacheControl, contentDisposition, contentEncoding, - contentLanguage, contentType); - } - - /** - * Generates a SAS token with the specified parameters - * - * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS - * @param permissions The {@code BlobSASPermission} permission for the SAS - * @return A string that represents the SAS token - */ - public String generateSAS(OffsetDateTime expiryTime, BlobSASPermission permissions) { - return this.blobAsyncClient.generateSAS(permissions, expiryTime); - } - - /** - * Generates a SAS token with the specified parameters - * - * @param identifier The {@code String} name of the access policy on the container this SAS references if any - * @return A string that represents the SAS token - */ - public String generateSAS(String identifier) { - return this.blobAsyncClient.generateSAS(identifier); - } - - /** - * Generates a SAS token with the specified parameters - * - * @param identifier The {@code String} name of the access policy on the container this SAS references if any - * @param permissions The {@code BlobSASPermission} permission for the SAS - * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS - * @param startTime An optional {@code OffsetDateTime} start time for the SAS - * @param version An optional {@code String} version for the SAS - * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS - * @param ipRange An optional {@code IPRange} ip address range for the SAS - * @return A string that represents the SAS token - */ - public String generateSAS(String identifier, BlobSASPermission permissions, OffsetDateTime expiryTime, - OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange) { - return this.blobAsyncClient.generateSAS(identifier, permissions, expiryTime, startTime, version, sasProtocol, - ipRange); - } - - /** - * Generates a SAS token with the specified parameters - * - *

Code Samples

- * - * {@codesnippet com.azure.storage.blob.BlobClient.generateSAS#String-BlobSASPermission-OffsetDateTime-OffsetDateTime-String-SASProtocol-IPRange-String-String-String-String-String} - * - *

For more information, see the - * Azure Docs

- * - * @param identifier The {@code String} name of the access policy on the container this SAS references if any - * @param permissions The {@code BlobSASPermission} permission for the SAS - * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS - * @param startTime An optional {@code OffsetDateTime} start time for the SAS - * @param version An optional {@code String} version for the SAS - * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS - * @param ipRange An optional {@code IPRange} ip address range for the SAS - * @param cacheControl An optional {@code String} cache-control header for the SAS. - * @param contentDisposition An optional {@code String} content-disposition header for the SAS. - * @param contentEncoding An optional {@code String} content-encoding header for the SAS. - * @param contentLanguage An optional {@code String} content-language header for the SAS. - * @param contentType An optional {@code String} content-type header for the SAS. - * @return A string that represents the SAS token - */ - public String generateSAS(String identifier, BlobSASPermission permissions, OffsetDateTime expiryTime, - OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange, String cacheControl, - String contentDisposition, String contentEncoding, String contentLanguage, String contentType) { - return this.blobAsyncClient.generateSAS(identifier, permissions, expiryTime, startTime, version, sasProtocol, - ipRange, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); - } - - /** - * Gets the snapshotId for a blob resource - * - * @return A string that represents the snapshotId of the snapshot blob - */ - public String getSnapshotId() { - return this.blobAsyncClient.getSnapshotId(); - } - - /** - * Determines if a blob is a snapshot - * - * @return A boolean that indicates if a blob is a snapshot - */ - public boolean isSnapshot() { - return this.blobAsyncClient.isSnapshot(); + public AppendBlobClient asAppendBlobClient() { + return new SpecializedBlobClientBuilder() + .blobClient(this) + .buildAppendBlobClient(); } /** - * Get the container name. - * - *

Code Samples

+ * Creates a new {@link BlockBlobClient} associated to this blob. * - * {@codesnippet com.azure.storage.blob.BlobClient.getContainerName} - * - * @return The name of the container. + * @return a {@link BlockBlobClient} associated to this blob. */ - public final String getContainerName() { - return this.blobAsyncClient.getContainerName(); + public BlockBlobClient asBlockBlobClient() { + return new SpecializedBlobClientBuilder() + .blobClient(this) + .buildBlockBlobClient(); } /** - * Get the blob name. - * - *

Code Samples

+ * Creates a new {@link PageBlobClient} associated to this blob. * - * {@codesnippet com.azure.storage.blob.BlobClient.getBlobName} - * - * @return The name of the blob. + * @return a {@link PageBlobClient} associated to this blob. */ - public final String getBlobName() { - return this.blobAsyncClient.getBlobName(); + public PageBlobClient asPageBlobClient() { + return new SpecializedBlobClientBuilder() + .blobClient(this) + .buildPageBlobClient(); } } diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobClientBuilder.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobClientBuilder.java index a98d21b05d26..6a10aa86f995 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobClientBuilder.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobClientBuilder.java @@ -7,20 +7,18 @@ import com.azure.core.http.HttpPipeline; import com.azure.core.util.logging.ClientLogger; import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; -import com.azure.storage.blob.implementation.AzureBlobStorageImpl; -import com.azure.storage.blob.models.LeaseAccessConditions; -import com.azure.storage.blob.models.PageRange; import com.azure.storage.common.credentials.SASTokenCredential; -import java.io.InputStream; + import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; -import java.util.List; import java.util.Objects; -import reactor.core.publisher.Flux; /** - * This class provides a fluent builder API to help aid the configuration and instantiation of Storage Blob clients. + * This class provides a fluent builder API to help aid the configuration and instantiation of + * {@link BlobClient BlobClients} and {@link BlobAsyncClient BlobAsyncClients} when + * {@link #buildBlobClient() buildBlobClient} and {@link #buildBlobAsyncClient() buildBlobAsyncClient} as called + * respectively. * *

* The following information must be provided on this builder: @@ -31,23 +29,8 @@ *

  • the credential through {@code .credential()} or {@code .connectionString()} if the container is not publicly * accessible. * - * - *

    - * Once all the configurations are set on this builder use the following mapping to construct the given client: - *

      - *
    • {@link BlobClientBuilder#buildBlobClient()} - {@link BlobClient}
    • - *
    • {@link BlobClientBuilder#buildBlobAsyncClient()} - {@link BlobAsyncClient}
    • - *
    • {@link BlobClientBuilder#buildAppendBlobClient()} - {@link AppendBlobClient}
    • - *
    • {@link BlobClientBuilder#buildAppendBlobAsyncClient()} - {@link AppendBlobAsyncClient}
    • - *
    • {@link BlobClientBuilder#buildBlockBlobClient()} - {@link BlockBlobClient}
    • - *
    • {@link BlobClientBuilder#buildBlockBlobAsyncClient()} - {@link BlockBlobAsyncClient}
    • - *
    • {@link BlobClientBuilder#buildPageBlobClient()} - {@link PageBlobClient}
    • - *
    • {@link BlobClientBuilder#buildPageBlobAsyncClient()} - {@link PageBlobAsyncClient}
    • - *
    */ -@ServiceClientBuilder(serviceClients = {BlobClient.class, BlobAsyncClient.class, AppendBlobClient.class, - AppendBlobAsyncClient.class, BlockBlobClient.class, BlockBlobAsyncClient.class, PageBlobClient.class, - PageBlobAsyncClient.class}) +@ServiceClientBuilder(serviceClients = {BlobClient.class, BlobAsyncClient.class }) public final class BlobClientBuilder extends BaseBlobClientBuilder { private final ClientLogger logger = new ClientLogger(BlobClientBuilder.class); @@ -57,26 +40,12 @@ public final class BlobClientBuilder extends BaseBlobClientBuilderCode Samples

    * - * {@codesnippet com.azure.storage.blob.BlobClientBuilder.buildBlobClient} + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.Builder.buildBlobClient} * * @return a {@link BlobClient} created from the configurations in this builder. * @throws NullPointerException If {@code endpoint}, {@code containerName}, or {@code blobName} is {@code null}. @@ -100,90 +69,24 @@ public BlobClient buildBlobClient() { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlobClientBuilder.buildBlobAsyncClient} + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.Builder.buildBlobAsyncClient} * * @return a {@link BlobAsyncClient} created from the configurations in this builder. * @throws NullPointerException If {@code endpoint}, {@code containerName}, or {@code blobName} is {@code null}. */ public BlobAsyncClient buildBlobAsyncClient() { - return new BlobAsyncClient(constructImpl(), snapshot, cpk); - } - - /** - * Creates a {@link AppendBlobClient} based on options set in the Builder. AppendBlobClients are used to perform - * append blob specific operations such as {@link AppendBlobClient#appendBlock(InputStream, long) append block}, - * only use this when the blob is known to be an append blob. - * - * @return a {@link AppendBlobClient} created from the configurations in this builder. - * @throws NullPointerException If {@code endpoint}, {@code containerName}, or {@code blobName} is {@code null}. - */ - public AppendBlobClient buildAppendBlobClient() { - return new AppendBlobClient(buildAppendBlobAsyncClient()); - } - - /** - * Creates a {@link AppendBlobAsyncClient} based on options set in the Builder. AppendBlobAsyncClients are used to - * perform append blob specific operations such as {@link AppendBlobAsyncClient#appendBlock(Flux, long) append - * blob}, only use this when the blob is known to be an append blob. - * - * @return a {@link AppendBlobAsyncClient} created from the configurations in this builder. - * @throws NullPointerException If {@code endpoint}, {@code containerName}, or {@code blobName} is {@code null}. - */ - public AppendBlobAsyncClient buildAppendBlobAsyncClient() { - return new AppendBlobAsyncClient(constructImpl(), snapshot, cpk); - } - - /** - * Creates a {@link BlockBlobClient} based on options set in the Builder. BlockBlobClients are used to perform - * generic upload operations such as {@link BlockBlobClient#uploadFromFile(String) upload from file} and block blob - * specific operations such as {@link BlockBlobClient#stageBlock(String, InputStream, long) stage block} and {@link - * BlockBlobClient#commitBlockList(List)}, only use this when the blob is known to be a block blob. - * - * @return a {@link BlockBlobClient} created from the configurations in this builder. - * @throws NullPointerException If {@code endpoint}, {@code containerName}, or {@code blobName} is {@code null}. - */ - public BlockBlobClient buildBlockBlobClient() { - return new BlockBlobClient(buildBlockBlobAsyncClient()); - } + Objects.requireNonNull(containerName, "'containerName' cannot be null."); + Objects.requireNonNull(blobName, "'blobName' cannot be null."); - /** - * Creates a {@link BlockBlobAsyncClient} based on options set in the Builder. BlockBlobAsyncClients are used to - * perform generic upload operations such as {@link BlockBlobAsyncClient#uploadFromFile(String) upload from file} - * and block blob specific operations such as {@link BlockBlobAsyncClient#stageBlockWithResponse(String, Flux, long, - * LeaseAccessConditions) stage block} and {@link BlockBlobAsyncClient#commitBlockList(List) commit block list}, - * only use this when the blob is known to be a block blob. - * - * @return a {@link BlockBlobAsyncClient} created from the configurations in this builder. - * @throws NullPointerException If {@code endpoint}, {@code containerName}, or {@code blobName} is {@code null}. - */ - public BlockBlobAsyncClient buildBlockBlobAsyncClient() { - return new BlockBlobAsyncClient(constructImpl(), snapshot, cpk); - } - - /** - * Creates a {@link PageBlobClient} based on options set in the Builder. PageBlobClients are used to perform page - * blob specific operations such as {@link PageBlobClient#uploadPages(PageRange, InputStream) upload pages} and - * {@link PageBlobClient#clearPages(PageRange) clear pages}, only use this when the blob is known to be a page - * blob. - * - * @return a {@link PageBlobClient} created from the configurations in this builder. - * @throws NullPointerException If {@code endpoint}, {@code containerName}, or {@code blobName} is {@code null}. - */ - public PageBlobClient buildPageBlobClient() { - return new PageBlobClient(buildPageBlobAsyncClient()); - } + HttpPipeline pipeline = super.getPipeline(); + if (pipeline == null) { + pipeline = super.buildPipeline(); + } - /** - * Creates a {@link PageBlobAsyncClient} based on options set in the Builder. PageBlobAsyncClients are used to - * perform page blob specific operations such as {@link PageBlobAsyncClient#uploadPages(PageRange, Flux) upload - * pages} and {@link PageBlobAsyncClient#clearPages(PageRange) clear pages}, only use this when the blob is known to - * be a page blob. - * - * @return a {@link PageBlobAsyncClient} created from the configurations in this builder. - * @throws NullPointerException If {@code endpoint}, {@code containerName}, or {@code blobName} is {@code null}. - */ - public PageBlobAsyncClient buildPageBlobAsyncClient() { - return new PageBlobAsyncClient(constructImpl(), snapshot, cpk); + return new BlobAsyncClient(new AzureBlobStorageBuilder() + .url(String.format("%s/%s/%s", endpoint, containerName, blobName)) + .pipeline(pipeline) + .build(), snapshot, customerProvidedKey); } /** @@ -191,7 +94,7 @@ public PageBlobAsyncClient buildPageBlobAsyncClient() { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlobClientBuilder.endpoint#String} + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.Builder.endpoint#String} * * @param endpoint URL of the service * @return the updated BlobClientBuilder object @@ -201,7 +104,7 @@ public PageBlobAsyncClient buildPageBlobAsyncClient() { public BlobClientBuilder endpoint(String endpoint) { try { URL url = new URL(endpoint); - BlobURLParts parts = URLParser.parse(url); + BlobURLParts parts = BlobURLParts.parse(url); this.endpoint = parts.getScheme() + "://" + parts.getHost(); this.containerName = parts.getContainerName(); @@ -225,14 +128,14 @@ public BlobClientBuilder endpoint(String endpoint) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlobClientBuilder.containerName#String} + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.Builder.containerName#String} * * @param containerName the name of the container * @return the updated BlobClientBuilder object * @throws NullPointerException If {@code containerName} is {@code null} */ public BlobClientBuilder containerName(String containerName) { - this.containerName = Objects.requireNonNull(containerName); + this.containerName = Objects.requireNonNull(containerName, "'containerName' cannot be null."); return this; } @@ -244,7 +147,7 @@ public BlobClientBuilder containerName(String containerName) { * @throws NullPointerException If {@code blobName} is {@code null} */ public BlobClientBuilder blobName(String blobName) { - this.blobName = Objects.requireNonNull(blobName); + this.blobName = Objects.requireNonNull(blobName, "'blobName' cannot be null."); return this; } @@ -258,4 +161,9 @@ public BlobClientBuilder snapshot(String snapshot) { this.snapshot = snapshot; return this; } + + @Override + protected Class getClazz() { + return BlobClientBuilder.class; + } } diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobProperties.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobProperties.java index a44177df0efa..fe8963148788 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobProperties.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobProperties.java @@ -49,7 +49,7 @@ public final class BlobProperties { private final Metadata metadata; private final Integer committedBlockCount; - BlobProperties(BlobGetPropertiesHeaders generatedHeaders) { + public BlobProperties(BlobGetPropertiesHeaders generatedHeaders) { this.creationTime = generatedHeaders.getCreationTime(); this.lastModified = generatedHeaders.getLastModified(); this.eTag = generatedHeaders.getETag(); diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobSASPermission.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobSASPermission.java index a5ff84ce5548..2a39f2eea816 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobSASPermission.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobSASPermission.java @@ -9,10 +9,9 @@ /** * This is a helper class to construct a string representing the permissions granted by a ServiceSAS to a blob. Setting - * a value to true means that any SAS which uses these permissions will grant permissions for that operation. Once all - * the values are set, this should be serialized with toString and set as the permissions field on a {@link - * BlobServiceSASSignatureValues} object. It is possible to construct the permissions string without this class, but the - * order of the permissions is particular and this class guarantees correctness. + * a value to true means that any SAS which uses these permissions will grant permissions for that operation. It is + * possible to construct the permissions string without this class, but the order of the permissions is particular and + * this class guarantees correctness. */ public final class BlobSASPermission { @@ -155,7 +154,7 @@ public boolean getDeletePermission() { * @param hasDeletePermission Permission status to set * @return the updated BlobSASPermission object. */ - public BlobSASPermission getDeletePermission(boolean hasDeletePermission) { + public BlobSASPermission setDeletePermission(boolean hasDeletePermission) { this.deletePermission = hasDeletePermission; return this; } diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceAsyncClient.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceAsyncClient.java index d24eb7056926..86e0f67a9b6a 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceAsyncClient.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceAsyncClient.java @@ -3,13 +3,13 @@ package com.azure.storage.blob; +import com.azure.core.annotation.ServiceClient; import com.azure.core.credentials.TokenCredential; import com.azure.core.http.HttpPipeline; 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.http.rest.SimpleResponse; -import com.azure.core.annotation.ServiceClient; import com.azure.core.implementation.http.PagedResponseBase; import com.azure.core.implementation.util.FluxUtil; import com.azure.core.util.Context; @@ -44,7 +44,7 @@ import java.util.function.Function; import static com.azure.core.implementation.util.FluxUtil.withContext; -import static com.azure.storage.blob.PostProcessor.postProcessResponse; +import static com.azure.storage.blob.implementation.PostProcessor.postProcessResponse; /** * Client to a storage account. It may only be instantiated through a {@link BlobServiceClientBuilder}. This class does @@ -70,16 +70,16 @@ public final class BlobServiceAsyncClient { private final ClientLogger logger = new ClientLogger(BlobServiceAsyncClient.class); private final AzureBlobStorageImpl azureBlobStorage; - private final CpkInfo cpk; + private final CpkInfo customerProvidedKey; /** * Package-private constructor for use by {@link BlobServiceClientBuilder}. * * @param azureBlobStorage the API client for blob storage */ - BlobServiceAsyncClient(AzureBlobStorageImpl azureBlobStorage, CpkInfo cpk) { + BlobServiceAsyncClient(AzureBlobStorageImpl azureBlobStorage, CpkInfo customerProvidedKey) { this.azureBlobStorage = azureBlobStorage; - this.cpk = cpk; + this.customerProvidedKey = customerProvidedKey; } /** @@ -98,7 +98,7 @@ public ContainerAsyncClient getContainerAsyncClient(String containerName) { return new ContainerAsyncClient(new AzureBlobStorageBuilder() .url(Utility.appendToURLPath(getAccountUrl(), containerName).toString()) .pipeline(azureBlobStorage.getHttpPipeline()) - .build(), cpk); + .build(), customerProvidedKey); } /** diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceClient.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceClient.java index bcd6ea424631..534f217a09c7 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceClient.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceClient.java @@ -3,12 +3,12 @@ package com.azure.storage.blob; +import com.azure.core.annotation.ServiceClient; import com.azure.core.credentials.TokenCredential; import com.azure.core.http.HttpPipeline; import com.azure.core.http.rest.PagedIterable; import com.azure.core.http.rest.Response; import com.azure.core.http.rest.SimpleResponse; -import com.azure.core.annotation.ServiceClient; import com.azure.core.util.Context; import com.azure.storage.blob.models.ContainerItem; import com.azure.storage.blob.models.ListContainersOptions; diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceClientBuilder.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceClientBuilder.java index 0b4860f6c6ad..a550baf30b32 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceClientBuilder.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceClientBuilder.java @@ -60,7 +60,7 @@ public BlobServiceAsyncClient buildAsyncClient() { return new BlobServiceAsyncClient(new AzureBlobStorageBuilder() .url(super.endpoint) .pipeline(pipeline) - .build(), cpk); + .build(), customerProvidedKey); } /** @@ -76,7 +76,7 @@ public BlobServiceClientBuilder endpoint(String endpoint) { super.endpoint = url.getProtocol() + "://" + url.getAuthority(); SASTokenCredential sasTokenCredential = SASTokenCredential - .fromSASTokenString(URLParser.parse(url).getSasQueryParameters().encode()); + .fromSASTokenString(BlobURLParts.parse(url).getSasQueryParameters().encode()); if (sasTokenCredential != null) { super.credential(sasTokenCredential); } @@ -88,6 +88,11 @@ public BlobServiceClientBuilder endpoint(String endpoint) { return this; } + @Override + protected Class getClazz() { + return BlobServiceClientBuilder.class; + } + String endpoint() { return super.endpoint; } diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobURLParts.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobURLParts.java index f43a8ca393ea..ba61173f126c 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobURLParts.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobURLParts.java @@ -4,55 +4,55 @@ package com.azure.storage.blob; import com.azure.core.implementation.http.UrlBuilder; +import com.azure.core.implementation.util.ImplUtils; +import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.blob.specialized.BlobServiceSASQueryParameters; import com.azure.storage.common.Constants; import com.azure.storage.common.Utility; import java.net.MalformedURLException; import java.net.URL; +import java.util.Comparator; import java.util.HashMap; +import java.util.Locale; import java.util.Map; +import java.util.TreeMap; /** - * A BlobURLParts object represents the components that make up an Azure Storage Container/Blob URL. You may parse an - * existing URL into its parts with the {@link URLParser} class. You may construct a URL from parts by calling - * {@link #toURL()}. It is also possible to use the empty constructor to buildClient a blobURL from scratch. - * - *

    NOTE: Changing any SAS-related field requires computing a new SAS signature.

    + * This class represents the components that make up an Azure Storage Container/Blob URL. You may parse an + * existing URL into its parts with the {@link #parse(URL)} class. You may construct a URL from parts by calling {@link + * #toURL()}. */ -final class BlobURLParts { - +public final class BlobURLParts { private String scheme; - private String host; - private String containerName; - private String blobName; - private String snapshot; - private BlobServiceSASQueryParameters blobServiceSasQueryParameters; - private Map unparsedParameters; /** - * Initializes a BlobURLParts object with all fields set to null, except unparsedParameters, which is an empty map. - * This may be useful for constructing a URL to a blob storage resource from scratch when the constituent parts are - * already known. + * Initializes a BlobURLParts object which helps aid in the construction of a Blob Storage URL. */ - BlobURLParts() { + public BlobURLParts() { unparsedParameters = new HashMap<>(); } /** - * The scheme. Ex: "https://". + * Gets the URL scheme, ex. "https://". + * + * @return the URL scheme. */ public String getScheme() { return scheme; } /** - * The scheme. Ex: "https://". + * Sets the URL scheme, ex. "https://". + * + * @param scheme The URL scheme. + * @return the updated BlobURLParts object. */ public BlobURLParts setScheme(String scheme) { this.scheme = scheme; @@ -60,14 +60,19 @@ public BlobURLParts setScheme(String scheme) { } /** - * The host. Ex: "account.blob.core.windows.net". + * Gets the URL host, ex. "account.blob.core.windows.net". + * + * @return the URL host. */ public String getHost() { return host; } /** - * The host. Ex: "account.blob.core.windows.net". + * Sets the URL host, ex. "account.blob.core.windows.net". + * + * @param host The URL host. + * @return the updated BlobURLParts object. */ public BlobURLParts setHost(String host) { this.host = host; @@ -75,14 +80,19 @@ public BlobURLParts setHost(String host) { } /** - * The container name or {@code null} if a {@link BlobServiceAsyncClient} was parsed. + * Gets the container name that will be used as part of the URL path. + * + * @return the container name. */ public String getContainerName() { return containerName; } /** - * The container name or {@code null} if a {@link BlobServiceAsyncClient} was parsed. + * Sets the container name that will be used as part of the URL path. + * + * @param containerName The container nme. + * @return the updated BlobURLParts object. */ public BlobURLParts setContainerName(String containerName) { this.containerName = containerName; @@ -90,14 +100,19 @@ public BlobURLParts setContainerName(String containerName) { } /** - * The blob name or {@code null} if a {@link BlobServiceAsyncClient} or {@link ContainerAsyncClient} was parsed. + * Gets the blob name that will be used as part of the URL path. + * + * @return the blob name. */ public String getBlobName() { return blobName; } /** - * The blob name or {@code null} if a {@link BlobServiceAsyncClient} or {@link ContainerAsyncClient} was parsed. + * Sets the blob name that will be used as part of the URL path. + * + * @param blobName The blob name. + * @return the updated BlobURLParts object. */ public BlobURLParts setBlobName(String blobName) { this.blobName = blobName; @@ -105,14 +120,19 @@ public BlobURLParts setBlobName(String blobName) { } /** - * The snapshot time or {@code null} if anything except a URL to a snapshot was parsed. + * Gets the snapshot identifier that will be used as part of the query string if set. + * + * @return the snapshot identifier. */ public String getSnapshot() { return snapshot; } /** - * The snapshot time or {@code null} if anything except a URL to a snapshot was parsed. + * Sets the snapshot identifier that will be used as part of the query string if set. + * + * @param snapshot The snapshot identifier. + * @return the updated BlobURLParts object. */ public BlobURLParts setSnapshot(String snapshot) { this.snapshot = snapshot; @@ -120,16 +140,21 @@ public BlobURLParts setSnapshot(String snapshot) { } /** - * A {@link BlobServiceSASQueryParameters} representing the SAS query parameters or {@code null} if there were no - * such parameters. + * Gets the {@link BlobServiceSASQueryParameters} representing the SAS query parameters that will be used to + * generate the SAS token for this URL. + * + * @return the {@link BlobServiceSASQueryParameters} of the URL */ public BlobServiceSASQueryParameters getSasQueryParameters() { return blobServiceSasQueryParameters; } /** - * A {@link BlobServiceSASQueryParameters} representing the SAS query parameters or {@code null} if there were no - * such parameters. + * Sets the {@link BlobServiceSASQueryParameters} representing the SAS query parameters that will be used to + * generate the SAS token for this URL. + * + * @param blobServiceSasQueryParameters The SAS query parameters. + * @return the updated BlobURLParts object. */ public BlobURLParts setSasQueryParameters(BlobServiceSASQueryParameters blobServiceSasQueryParameters) { this.blobServiceSasQueryParameters = blobServiceSasQueryParameters; @@ -137,16 +162,19 @@ public BlobURLParts setSasQueryParameters(BlobServiceSASQueryParameters blobServ } /** - * The query parameter key value pairs aside from SAS parameters and snapshot time or {@code null} if there were no - * such parameters. + * Gets the query string parameters that aren't part of the SAS token that will be used by this URL. + * + * @return the non-SAS token query string values. */ public Map getUnparsedParameters() { return unparsedParameters; } /** - * The query parameter key value pairs aside from SAS parameters and snapshot time or {@code null} if there were no - * such parameters. + * Sets the query string parameters that aren't part of the SAS token that will be used by this URL. + * + * @param unparsedParameters The non-SAS token query string values. + * @return the updated BlobURLParts object. */ public BlobURLParts setUnparsedParameters(Map unparsedParameters) { this.unparsedParameters = unparsedParameters; @@ -156,7 +184,7 @@ public BlobURLParts setUnparsedParameters(Map unparsedParamete /** * Converts the blob URL parts to a {@link URL}. * - * @return A {@code java.net.URL} to the blob resource composed of all the elements in the object. + * @return A {@code URL} to the blob resource composed of all the elements in this object. * @throws MalformedURLException The fields present on the BlobURLParts object were insufficient to construct a * valid URL or were ill-formatted. */ @@ -191,4 +219,125 @@ public URL toURL() throws MalformedURLException { return url.toURL(); } + + /** + * URLParser parses a string URL initializing BlobURLParts' fields including any SAS-related and snapshot query + * parameters. Any other query parameters remain in the UnparsedParams field. This method overwrites all fields + * in the BlobURLParts object. + * + * @param url The string URL to be parsed. + * @param logger Logger associated to the calling class to log a {@link MalformedURLException}. + * @return A {@link BlobURLParts} object containing all the components of a BlobURL. + * @throws IllegalArgumentException If the {@code url} is malformed. + */ + public static BlobURLParts parse(String url, ClientLogger logger) { + try { + return parse(new URL(url)); + } catch (MalformedURLException e) { + throw logger.logExceptionAsError(new IllegalArgumentException("Please double check the URL format. URL: " + + url)); + } + } + + /** + * Parses an existing URL into a BlobURLParts. + * + *

    Query parameters will be parsed into two properties, {@link BlobServiceSASQueryParameters} which contains + * all SAS token related values and {@link #getUnparsedParameters() unparsedParameters} which is all other query + * parameters.

    + * + * @param url The {@code URL} to be parsed. + * @return A {@link BlobURLParts} object containing all the components of a BlobURL. + */ + public static BlobURLParts parse(URL url) { + + final String scheme = url.getProtocol(); + final String host = url.getHost(); + + String containerName = null; + String blobName = null; + + // find the container & blob names (if any) + String path = url.getPath(); + if (!ImplUtils.isNullOrEmpty(path)) { + // if the path starts with a slash remove it + if (path.charAt(0) == '/') { + path = path.substring(1); + } + + int containerEndIndex = path.indexOf('/'); + if (containerEndIndex == -1) { + // path contains only a container name and no blob name + containerName = path; + } else { + // path contains the container name up until the slash and blob name is everything after the slash + containerName = path.substring(0, containerEndIndex); + blobName = path.substring(containerEndIndex + 1); + } + } + Map queryParamsMap = parseQueryString(url.getQuery()); + + String snapshot = null; + String[] snapshotArray = queryParamsMap.get("snapshot"); + if (snapshotArray != null) { + snapshot = snapshotArray[0]; + queryParamsMap.remove("snapshot"); + } + + BlobServiceSASQueryParameters blobServiceSasQueryParameters = + new BlobServiceSASQueryParameters(queryParamsMap, true); + + return new BlobURLParts() + .setScheme(scheme) + .setHost(host) + .setContainerName(containerName) + .setBlobName(blobName) + .setSnapshot(snapshot) + .setSasQueryParameters(blobServiceSasQueryParameters) + .setUnparsedParameters(queryParamsMap); + } + + /** + * Parses a query string into a one to many hashmap. + * + * @param queryParams The string of query params to parse. + * @return A {@code HashMap} of the key values. + */ + private static TreeMap parseQueryString(String queryParams) { + final TreeMap retVals = new TreeMap<>(Comparator.naturalOrder()); + + if (ImplUtils.isNullOrEmpty(queryParams)) { + return retVals; + } + + // split name value pairs by splitting on the '&' character + final String[] valuePairs = queryParams.split("&"); + + // for each field value pair parse into appropriate map entries + for (String valuePair : valuePairs) { + // Getting key and value for a single query parameter + final int equalDex = valuePair.indexOf("="); + String key = Utility.urlDecode(valuePair.substring(0, equalDex)).toLowerCase(Locale.ROOT); + String value = Utility.urlDecode(valuePair.substring(equalDex + 1)); + + // add to map + String[] keyValues = retVals.get(key); + + // check if map already contains key + if (keyValues == null) { + // map does not contain this key + keyValues = new String[]{value}; + } else { + // map contains this key already so append + final String[] newValues = new String[keyValues.length + 1]; + System.arraycopy(keyValues, 0, newValues, 0, keyValues.length); + + newValues[newValues.length - 1] = value; + keyValues = newValues; + } + retVals.put(key, keyValues); + } + + return retVals; + } } diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java index 2c70bf062037..8ec6dcca6507 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java @@ -3,13 +3,13 @@ package com.azure.storage.blob; +import com.azure.core.annotation.ServiceClient; import com.azure.core.http.HttpPipeline; import com.azure.core.http.HttpResponse; 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.http.rest.SimpleResponse; -import com.azure.core.annotation.ServiceClient; import com.azure.core.implementation.http.PagedResponseBase; import com.azure.core.implementation.util.FluxUtil; import com.azure.core.util.Context; @@ -31,6 +31,8 @@ import com.azure.storage.blob.models.StorageAccountInfo; import com.azure.storage.blob.models.StorageException; import com.azure.storage.blob.models.UserDelegationKey; +import com.azure.storage.blob.specialized.BlobServiceSASQueryParameters; +import com.azure.storage.blob.specialized.BlobServiceSASSignatureValues; import com.azure.storage.common.Constants; import com.azure.storage.common.IPRange; import com.azure.storage.common.SASProtocol; @@ -50,7 +52,7 @@ import java.util.stream.Stream; import static com.azure.core.implementation.util.FluxUtil.withContext; -import static com.azure.storage.blob.PostProcessor.postProcessResponse; +import static com.azure.storage.blob.implementation.PostProcessor.postProcessResponse; /** * Client to a container. It may only be instantiated through a {@link ContainerClientBuilder} or via the method {@link @@ -82,7 +84,7 @@ public final class ContainerAsyncClient { private final ClientLogger logger = new ClientLogger(ContainerAsyncClient.class); private final AzureBlobStorageImpl azureBlobStorage; - private final CpkInfo cpk; // only used to pass down to blob clients + private final CpkInfo customerProvidedKey; // only used to pass down to blob clients /** * Package-private constructor for use by {@link ContainerClientBuilder}. @@ -91,133 +93,7 @@ public final class ContainerAsyncClient { */ ContainerAsyncClient(AzureBlobStorageImpl azureBlobStorage, CpkInfo cpk) { this.azureBlobStorage = azureBlobStorage; - this.cpk = cpk; - } - - /** - * Creates a new {@link BlockBlobAsyncClient} object by concatenating the blobName to the end of - * ContainerAsyncClient's URL. The new BlockBlobAsyncClient uses the same request policy pipeline as the - * ContainerAsyncClient. To change the pipeline, create the BlockBlobAsyncClient and then call its WithPipeline - * method passing in the desired pipeline object. Or, call this package's NewBlockBlobAsyncClient instead of calling - * this object's NewBlockBlobAsyncClient method. - * - *

    Code Samples

    - * - * {@codesnippet com.azure.storage.blob.ContainerAsyncClient.getBlobAsyncClient#String} - * - * @param blobName A {@code String} representing the name of the blob. - * @return A new {@link BlockBlobAsyncClient} object which references the blob with the specified name in this - * container. - */ - public BlockBlobAsyncClient getBlockBlobAsyncClient(String blobName) { - return getBlockBlobAsyncClient(blobName, null); - } - - /** - * Creates a new {@link BlockBlobAsyncClient} object by concatenating the blobName to the end of - * ContainerAsyncClient's URL. The new BlockBlobAsyncClient uses the same request policy pipeline as the - * ContainerAsyncClient. To change the pipeline, create the BlockBlobAsyncClient and then call its WithPipeline - * method passing in the desired pipeline object. Or, call this package's NewBlockBlobAsyncClient instead of calling - * this object's NewBlockBlobAsyncClient method. - * - *

    Code Samples

    - * - * {@codesnippet com.azure.storage.blob.ContainerAsyncClient.getBlobAsyncClient#String-String} - * - * @param blobName A {@code String} representing the name of the blob. - * @param snapshot the snapshot identifier for the blob. - * @return A new {@link BlockBlobAsyncClient} object which references the blob with the specified name in this - * container. - */ - public BlockBlobAsyncClient getBlockBlobAsyncClient(String blobName, String snapshot) { - return new BlockBlobAsyncClient(new AzureBlobStorageBuilder() - .url(Utility.appendToURLPath(getContainerUrl(), blobName).toString()) - .pipeline(azureBlobStorage.getHttpPipeline()) - .build(), snapshot, cpk); - } - - /** - * Creates creates a new PageBlobAsyncClient object by concatenating blobName to the end of ContainerAsyncClient's - * URL. The new PageBlobAsyncClient uses the same request policy pipeline as the ContainerAsyncClient. To change the - * pipeline, create the PageBlobAsyncClient and then call its WithPipeline method passing in the desired pipeline - * object. Or, call this package's NewPageBlobAsyncClient instead of calling this object's NewPageBlobAsyncClient - * method. - * - *

    Code Samples

    - * - * {@codesnippet com.azure.storage.blob.ContainerAsyncClient.getPageBlobAsyncClient#String} - * - * @param blobName A {@code String} representing the name of the blob. - * @return A new {@link PageBlobAsyncClient} object which references the blob with the specified name in this - * container. - */ - public PageBlobAsyncClient getPageBlobAsyncClient(String blobName) { - return getPageBlobAsyncClient(blobName, null); - } - - /** - * Creates creates a new PageBlobAsyncClient object by concatenating blobName to the end of ContainerAsyncClient's - * URL. The new PageBlobAsyncClient uses the same request policy pipeline as the ContainerAsyncClient. To change the - * pipeline, create the PageBlobAsyncClient and then call its WithPipeline method passing in the desired pipeline - * object. Or, call this package's NewPageBlobAsyncClient instead of calling this object's NewPageBlobAsyncClient - * method. - * - *

    Code Samples

    - * - * {@codesnippet com.azure.storage.blob.ContainerAsyncClient.getPageBlobAsyncClient#String-String} - * - * @param blobName A {@code String} representing the name of the blob. - * @param snapshot the snapshot identifier for the blob. - * @return A new {@link PageBlobAsyncClient} object which references the blob with the specified name in this - * container. - */ - public PageBlobAsyncClient getPageBlobAsyncClient(String blobName, String snapshot) { - return new PageBlobAsyncClient(new AzureBlobStorageBuilder() - .url(Utility.appendToURLPath(getContainerUrl(), blobName).toString()) - .pipeline(azureBlobStorage.getHttpPipeline()) - .build(), snapshot, cpk); - } - - /** - * Creates creates a new AppendBlobAsyncClient object by concatenating blobName to the end of ContainerAsyncClient's - * URL. The new AppendBlobAsyncClient uses the same request policy pipeline as the ContainerAsyncClient. To change - * the pipeline, create the AppendBlobAsyncClient and then call its WithPipeline method passing in the desired - * pipeline object. Or, call this package's NewAppendBlobAsyncClient instead of calling this object's - * NewAppendBlobAsyncClient method. - * - *

    Code Samples

    - * - * {@codesnippet com.azure.storage.blob.ContainerAsyncClient.getAppendBlobAsyncClient#String} - * - * @param blobName A {@code String} representing the name of the blob. - * @return A new {@link AppendBlobAsyncClient} object which references the blob with the specified name in this - * container. - */ - public AppendBlobAsyncClient getAppendBlobAsyncClient(String blobName) { - return getAppendBlobAsyncClient(blobName, null); - } - - /** - * Creates creates a new AppendBlobAsyncClient object by concatenating blobName to the end of ContainerAsyncClient's - * URL. The new AppendBlobAsyncClient uses the same request policy pipeline as the ContainerAsyncClient. To change - * the pipeline, create the AppendBlobAsyncClient and then call its WithPipeline method passing in the desired - * pipeline object. Or, call this package's NewAppendBlobAsyncClient instead of calling this object's - * NewAppendBlobAsyncClient method. - * - *

    Code Samples

    - * - * {@codesnippet com.azure.storage.blob.ContainerAsyncClient.getAppendBlobAsyncClient#String-String} - * - * @param blobName A {@code String} representing the name of the blob. - * @param snapshot the snapshot identifier for the blob. - * @return A new {@link AppendBlobAsyncClient} object which references the blob with the specified name in this - * container. - */ - public AppendBlobAsyncClient getAppendBlobAsyncClient(String blobName, String snapshot) { - return new AppendBlobAsyncClient(new AzureBlobStorageBuilder() - .url(Utility.appendToURLPath(getContainerUrl(), blobName).toString()) - .pipeline(azureBlobStorage.getHttpPipeline()) - .build(), snapshot, cpk); + this.customerProvidedKey = cpk; } /** @@ -255,19 +131,7 @@ public BlobAsyncClient getBlobAsyncClient(String blobName, String snapshot) { return new BlobAsyncClient(new AzureBlobStorageBuilder() .url(Utility.appendToURLPath(getContainerUrl(), blobName).toString()) .pipeline(azureBlobStorage.getHttpPipeline()) - .build(), snapshot, cpk); - } - - /** - * Initializes a {@link BlobServiceAsyncClient} object pointing to the storage account this container is in. - * - * @return A {@link BlobServiceAsyncClient} object pointing to the specified storage account - */ - public BlobServiceAsyncClient getBlobServiceAsyncClient() { - return new BlobServiceAsyncClient(new AzureBlobStorageBuilder() - .url(Utility.stripLastPathSegment(getContainerUrl()).toString()) - .pipeline(azureBlobStorage.getHttpPipeline()) - .build(), cpk); + .build(), snapshot, customerProvidedKey); } /** @@ -285,6 +149,19 @@ public URL getContainerUrl() { } } + /** + * Get the container name. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.ContainerAsyncClient.getContainerName} + * + * @return The name of container. + */ + public String getContainerName() { + return BlobURLParts.parse(this.azureBlobStorage.getUrl(), logger).getContainerName(); + } + /** * Gets the {@link HttpPipeline} powering this client. * @@ -294,6 +171,16 @@ public HttpPipeline getHttpPipeline() { return azureBlobStorage.getHttpPipeline(); } + /** + * Gets the {@link CpkInfo} associated with this client that will be passed to + * {@link BlobAsyncClient BlobAsyncClients} when {@link #getBlobAsyncClient(String) getBlobAsyncClient} is called. + * + * @return the customer provided key used for encryption. + */ + public CpkInfo getCustomerProvidedKey() { + return customerProvidedKey; + } + /** * Gets if the container this client represents exists in the cloud. * @@ -1081,19 +968,6 @@ public String generateSAS(String identifier, ContainerSASPermission permissions, return blobServiceSasQueryParameters.encode(); } - /** - * Get the container name. - * - *

    Code Samples

    - * - * {@codesnippet com.azure.storage.blob.ContainerAsyncClient.getContainerName} - * - * @return The name of container. - */ - public String getContainerName() { - return URLParser.parse(this.azureBlobStorage.getUrl(), logger).getContainerName(); - } - /** * Sets blobServiceSASSignatureValues parameters dependent on the current blob type */ diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/ContainerClient.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/ContainerClient.java index 3aa4944e66d7..b9625e4643f4 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/ContainerClient.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/ContainerClient.java @@ -3,14 +3,15 @@ package com.azure.storage.blob; +import com.azure.core.annotation.ServiceClient; import com.azure.core.http.HttpPipeline; import com.azure.core.http.rest.PagedIterable; import com.azure.core.http.rest.Response; -import com.azure.core.annotation.ServiceClient; import com.azure.core.util.Context; import com.azure.storage.blob.models.BlobItem; import com.azure.storage.blob.models.ContainerAccessConditions; import com.azure.storage.blob.models.ContainerAccessPolicies; +import com.azure.storage.blob.models.CpkInfo; import com.azure.storage.blob.models.LeaseAccessConditions; import com.azure.storage.blob.models.ListBlobsOptions; import com.azure.storage.blob.models.Metadata; @@ -61,117 +62,6 @@ public final class ContainerClient { this.containerAsyncClient = containerAsyncClient; } - /** - * Creates a new {@link BlockBlobClient} object by concatenating the blobName to the end of ContainerAsyncClient's - * URL. The new BlockBlobClient uses the same request policy pipeline as the ContainerAsyncClient. To change the - * pipeline, create the BlockBlobClient and then call its WithPipeline method passing in the desired pipeline - * object. Or, call this package's NewBlockBlobAsyncClient instead of calling this object's NewBlockBlobAsyncClient - * method. - * - *

    Code Samples

    - * - * {@codesnippet com.azure.storage.blob.ContainerClient.getBlockBlobClient#String} - * - * @param blobName A {@code String} representing the name of the blob. - * @return A new {@link BlockBlobClient} object which references the blob with the specified name in this container. - */ - public BlockBlobClient getBlockBlobClient(String blobName) { - return new BlockBlobClient(containerAsyncClient.getBlockBlobAsyncClient(blobName)); - } - - /** - * Creates a new {@link BlockBlobClient} object by concatenating the blobName to the end of ContainerAsyncClient's - * URL. The new BlockBlobClient uses the same request policy pipeline as the ContainerAsyncClient. To change the - * pipeline, create the BlockBlobClient and then call its WithPipeline method passing in the desired pipeline - * object. Or, call this package's NewBlockBlobAsyncClient instead of calling this object's NewBlockBlobAsyncClient - * method. - * - *

    Code Samples

    - * - * {@codesnippet com.azure.storage.blob.ContainerClient.getBlockBlobClient#String-String} - * - * @param blobName A {@code String} representing the name of the blob. - * @param snapshot the snapshot identifier for the blob. - * @return A new {@link BlockBlobClient} object which references the blob with the specified name in this container. - */ - public BlockBlobClient getBlockBlobClient(String blobName, String snapshot) { - return new BlockBlobClient(containerAsyncClient.getBlockBlobAsyncClient(blobName, snapshot)); - } - - /** - * Creates creates a new PageBlobClient object by concatenating blobName to the end of ContainerAsyncClient's URL. - * The new PageBlobClient uses the same request policy pipeline as the ContainerAsyncClient. To change the pipeline, - * create the PageBlobClient and then call its WithPipeline method passing in the desired pipeline object. Or, call - * this package's NewPageBlobAsyncClient instead of calling this object's NewPageBlobAsyncClient method. - * - *

    Code Samples

    - * - * {@codesnippet com.azure.storage.blob.ContainerClient.getPageBlobClient#String} - * - * @param blobName A {@code String} representing the name of the blob. - * @return A new {@link PageBlobClient} object which references the blob with the specified name in this container. - */ - public PageBlobClient getPageBlobClient(String blobName) { - return new PageBlobClient(containerAsyncClient.getPageBlobAsyncClient(blobName)); - } - - /** - * Creates creates a new PageBlobClient object by concatenating blobName to the end of ContainerAsyncClient's URL. - * The new PageBlobClient uses the same request policy pipeline as the ContainerAsyncClient. To change the pipeline, - * create the PageBlobClient and then call its WithPipeline method passing in the desired pipeline object. Or, call - * this package's NewPageBlobAsyncClient instead of calling this object's NewPageBlobAsyncClient method. - * - *

    Code Samples

    - * - * {@codesnippet com.azure.storage.blob.ContainerClient.getPageBlobClient#String-String} - * - * @param blobName A {@code String} representing the name of the blob. - * @param snapshot the snapshot identifier for the blob. - * @return A new {@link PageBlobClient} object which references the blob with the specified name in this container. - */ - public PageBlobClient getPageBlobClient(String blobName, String snapshot) { - return new PageBlobClient(containerAsyncClient.getPageBlobAsyncClient(blobName, snapshot)); - } - - /** - * Creates creates a new AppendBlobClient object by concatenating blobName to the end of ContainerAsyncClient's URL. - * The new AppendBlobClient uses the same request policy pipeline as the ContainerAsyncClient. To change the - * pipeline, create the AppendBlobClient and then call its WithPipeline method passing in the desired pipeline - * object. Or, call this package's NewAppendBlobAsyncClient instead of calling this object's - * NewAppendBlobAsyncClient method. - * - *

    Code Samples

    - * - * {@codesnippet com.azure.storage.blob.ContainerClient.getAppendBlobClient#String} - * - * @param blobName A {@code String} representing the name of the blob. - * @return A new {@link AppendBlobClient} object which references the blob with the specified name in this - * container. - */ - public AppendBlobClient getAppendBlobClient(String blobName) { - return new AppendBlobClient(containerAsyncClient.getAppendBlobAsyncClient(blobName)); - } - - /** - * Creates creates a new AppendBlobClient object by concatenating blobName to the end of ContainerAsyncClient's URL. - * The new AppendBlobClient uses the same request policy pipeline as the ContainerAsyncClient. To change the - * pipeline, create the AppendBlobClient and then call its WithPipeline method passing in the desired pipeline - * object. Or, call this package's NewAppendBlobAsyncClient instead of calling this object's - * NewAppendBlobAsyncClient method. - * - *

    Code Samples

    - * - * {@codesnippet com.azure.storage.blob.ContainerClient.getAppendBlobClient#String-String} - * - * @param blobName A {@code String} representing the name of the blob. - * @param snapshot the snapshot identifier for the blob. - * @return A new {@link AppendBlobClient} object which references the blob with the specified name in this - * container. - */ - public AppendBlobClient getAppendBlobClient(String blobName, String snapshot) { - return new AppendBlobClient(containerAsyncClient.getAppendBlobAsyncClient(blobName, snapshot)); - } - /** * Initializes a new BlobClient object by concatenating blobName to the end of ContainerAsyncClient's URL. The new * BlobClient uses the same request policy pipeline as the ContainerAsyncClient. To change the pipeline, create the @@ -207,15 +97,6 @@ public BlobClient getBlobClient(String blobName, String snapshot) { return new BlobClient(containerAsyncClient.getBlobAsyncClient(blobName, snapshot)); } - /** - * Initializes a {@link BlobServiceClient} object pointing to the storage account this container is in. - * - * @return A {@link BlobServiceClient} object pointing to the specified storage account - */ - public BlobServiceClient getBlobServiceClient() { - return new BlobServiceClient(containerAsyncClient.getBlobServiceAsyncClient()); - } - /** * Gets the URL of the container represented by this client. * @@ -234,6 +115,16 @@ public HttpPipeline getHttpPipeline() { return containerAsyncClient.getHttpPipeline(); } + /** + * Gets the {@link CpkInfo} associated with this client that will be passed to {@link BlobClient BlobClients} when + * {@link #getBlobClient(String) getBlobClient} is called. + * + * @return the customer provided key used for encryption. + */ + public CpkInfo getCustomerProvidedKey() { + return containerAsyncClient.getCustomerProvidedKey(); + } + /** * Gets if the container this client represents exists in the cloud. * diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/ContainerClientBuilder.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/ContainerClientBuilder.java index 0ecab1d2d279..c122228bbdfd 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/ContainerClientBuilder.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/ContainerClientBuilder.java @@ -73,7 +73,7 @@ public ContainerAsyncClient buildAsyncClient() { return new ContainerAsyncClient(new AzureBlobStorageBuilder() .url(String.format("%s/%s", endpoint, containerName)) .pipeline(pipeline) - .build(), cpk); + .build(), customerProvidedKey); } /** @@ -91,7 +91,7 @@ public ContainerAsyncClient buildAsyncClient() { public ContainerClientBuilder endpoint(String endpoint) { try { URL url = new URL(endpoint); - BlobURLParts parts = URLParser.parse(url); + BlobURLParts parts = BlobURLParts.parse(url); this.endpoint = parts.getScheme() + "://" + parts.getHost(); this.containerName = parts.getContainerName(); @@ -124,6 +124,11 @@ public ContainerClientBuilder containerName(String containerName) { return this; } + @Override + protected Class getClazz() { + return ContainerClientBuilder.class; + } + String endpoint() { return this.endpoint; } diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/ContainerSASPermission.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/ContainerSASPermission.java index 83d90b1408e2..bdb78314eb68 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/ContainerSASPermission.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/ContainerSASPermission.java @@ -11,9 +11,8 @@ /** * This is a helper class to construct a string representing the permissions granted by a ServiceSAS to a container. * Setting a value to true means that any SAS which uses these permissions will grant permissions for that operation. - * Once all the values are set, this should be serialized with toString and set as the permissions field on a {@link - * BlobServiceSASSignatureValues} object. It is possible to construct the permissions string without this class, but the - * order of the permissions is particular and this class guarantees correctness. + * It is possible to construct the permissions string without this class, but the order of the permissions is + * particular and this class guarantees correctness. */ public final class ContainerSASPermission { private boolean read; @@ -29,7 +28,7 @@ public final class ContainerSASPermission { private boolean list; /** - * Initializes an {@code ContainerSASPermssion} object with all fields set to false. + * Initializes an {@code ContainerSASPermission} object with all fields set to false. */ public ContainerSASPermission() { } diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/URLParser.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/URLParser.java deleted file mode 100644 index 5ca8f2b8673e..000000000000 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/URLParser.java +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.storage.blob; - -import com.azure.core.implementation.util.ImplUtils; -import com.azure.core.util.logging.ClientLogger; -import com.azure.storage.common.Utility; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Comparator; -import java.util.Locale; -import java.util.Map; -import java.util.TreeMap; - -/** - * A class used to conveniently parse URLs into {@link BlobURLParts} to modify the components of the URL. - */ -final class URLParser { - - /** - * URLParser parses a string URL initializing BlobURLParts' fields including any SAS-related and snapshot query - * parameters. Any other query parameters remain in the UnparsedParams field. This method overwrites all fields - * in the BlobURLParts object. - * - * @param url The string URL to be parsed. - * @return A {@link BlobURLParts} object containing all the components of a BlobURL. - */ - public static BlobURLParts parse(String url, ClientLogger logger) { - try { - return parse(new URL(url)); - } catch (MalformedURLException e) { - throw logger.logExceptionAsError(new IllegalArgumentException("Please double check the URL format. URL: " - + url)); - } - } - - /** - * URLParser parses a URL initializing BlobURLParts' fields including any SAS-related and snapshot query parameters. - * Any other query parameters remain in the UnparsedParams field. This method overwrites all fields in the - * BlobURLParts object. - * - * @param url The {@code URL} to be parsed. - * @return A {@link BlobURLParts} object containing all the components of a BlobURL. - */ - public static BlobURLParts parse(URL url) { - - final String scheme = url.getProtocol(); - final String host = url.getHost(); - - String containerName = null; - String blobName = null; - - // find the container & blob names (if any) - String path = url.getPath(); - if (!ImplUtils.isNullOrEmpty(path)) { - // if the path starts with a slash remove it - if (path.charAt(0) == '/') { - path = path.substring(1); - } - - int containerEndIndex = path.indexOf('/'); - if (containerEndIndex == -1) { - // path contains only a container name and no blob name - containerName = path; - } else { - // path contains the container name up until the slash and blob name is everything after the slash - containerName = path.substring(0, containerEndIndex); - blobName = path.substring(containerEndIndex + 1); - } - } - Map queryParamsMap = parseQueryString(url.getQuery()); - - String snapshot = null; - String[] snapshotArray = queryParamsMap.get("snapshot"); - if (snapshotArray != null) { - snapshot = snapshotArray[0]; - queryParamsMap.remove("snapshot"); - } - - BlobServiceSASQueryParameters blobServiceSasQueryParameters = - new BlobServiceSASQueryParameters(queryParamsMap, true); - - return new BlobURLParts() - .setScheme(scheme) - .setHost(host) - .setContainerName(containerName) - .setBlobName(blobName) - .setSnapshot(snapshot) - .setSasQueryParameters(blobServiceSasQueryParameters) - .setUnparsedParameters(queryParamsMap); - } - - /** - * Parses a query string into a one to many hashmap. - * - * @param queryParams The string of query params to parse. - * @return A {@code HashMap} of the key values. - */ - private static TreeMap parseQueryString(String queryParams) { - - final TreeMap retVals = new TreeMap<>(Comparator.naturalOrder()); - - if (ImplUtils.isNullOrEmpty(queryParams)) { - return retVals; - } - - // split name value pairs by splitting on the 'c&' character - final String[] valuePairs = queryParams.split("&"); - - // for each field value pair parse into appropriate map entries - for (String valuePair : valuePairs) { - // Getting key and value for a single query parameter - final int equalDex = valuePair.indexOf("="); - String key = Utility.urlDecode(valuePair.substring(0, equalDex)).toLowerCase(Locale.ROOT); - String value = Utility.urlDecode(valuePair.substring(equalDex + 1)); - - // add to map - String[] keyValues = retVals.get(key); - - // check if map already contains key - if (keyValues == null) { - // map does not contain this key - keyValues = new String[]{value}; - } else { - // map contains this key already so append - final String[] newValues = new String[keyValues.length + 1]; - System.arraycopy(keyValues, 0, newValues, 0, keyValues.length); - - newValues[newValues.length - 1] = value; - keyValues = newValues; - } - retVals.put(key, keyValues); - } - - return retVals; - } -} diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/PostProcessor.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/PostProcessor.java similarity index 50% rename from sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/PostProcessor.java rename to sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/PostProcessor.java index b573adcdf6b6..61156c36056c 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/PostProcessor.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/PostProcessor.java @@ -1,15 +1,27 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.implementation; import com.azure.storage.blob.models.StorageErrorException; import com.azure.storage.blob.models.StorageException; import com.azure.storage.common.Utility; import reactor.core.publisher.Mono; -final class PostProcessor { - static Mono postProcessResponse(Mono response) { +/** + * This class is a helper class that offers functionality to apply processing to responses returned from the service. + */ +public final class PostProcessor { + + /** + * Applies cleaning to eTag returned from the service if the request was successful, otherwise maps the returned + * {@link StorageErrorException} to a {@link StorageException} which promotes information from the returned error. + * + * @param response Response from the service + * @param Generic value contained in the response + * @return The cleansed success response or the mapped exception + */ + public static Mono postProcessResponse(Mono response) { return Utility.postProcessResponse(response, (errorResponse) -> errorResponse.onErrorResume(StorageErrorException.class, resume -> resume.getResponse() diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/CustomerProvidedKey.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/CustomerProvidedKey.java index cc3484fe9c99..d29b0bbb65ca 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/CustomerProvidedKey.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/CustomerProvidedKey.java @@ -3,11 +3,14 @@ package com.azure.storage.blob.models; +import com.azure.core.util.logging.ClientLogger; + import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Base64; public class CustomerProvidedKey { + private final ClientLogger logger = new ClientLogger(CustomerProvidedKey.class); /** * Base64 encoded string of the encryption key. @@ -30,13 +33,18 @@ public class CustomerProvidedKey { * Creates a new wrapper for a client provided key. * * @param key The encryption key encoded as a base64 string. - * @throws NoSuchAlgorithmException Throws if MessageDigest "SHA-256" cannot be found. + * @throws RuntimeException If "SHA-256" cannot be found. */ - public CustomerProvidedKey(String key) throws NoSuchAlgorithmException { + public CustomerProvidedKey(String key) { this.key = key; - MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); + MessageDigest sha256; + try { + sha256 = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + throw logger.logExceptionAsError(new RuntimeException(e)); + } byte[] keyhash = sha256.digest(Base64.getDecoder().decode(key)); this.keySHA256 = Base64.getEncoder().encodeToString(keyhash); } @@ -46,13 +54,18 @@ public CustomerProvidedKey(String key) throws NoSuchAlgorithmException { * * @param key The encryption key bytes. * - * @throws NoSuchAlgorithmException Throws if MessageDigest "SHA-256" cannot be found. + * @throws RuntimeException If "SHA-256" cannot be found. */ - public CustomerProvidedKey(byte[] key) throws NoSuchAlgorithmException { + public CustomerProvidedKey(byte[] key) { this.key = Base64.getEncoder().encodeToString(key); - MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); + MessageDigest sha256; + try { + sha256 = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + throw logger.logExceptionAsError(new RuntimeException(e)); + } byte[] keyhash = sha256.digest(key); this.keySHA256 = Base64.getEncoder().encodeToString(keyhash); } diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/ReliableDownloadOptions.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/ReliableDownloadOptions.java index 0120f0e3c35e..20171492b04b 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/ReliableDownloadOptions.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/ReliableDownloadOptions.java @@ -4,7 +4,7 @@ package com.azure.storage.blob.models; import com.azure.core.util.logging.ClientLogger; -import com.azure.storage.blob.DownloadAsyncResponse; +import com.azure.storage.blob.specialized.DownloadAsyncResponse; import java.util.Locale; diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncClient.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/AppendBlobAsyncClient.java similarity index 85% rename from sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncClient.java rename to sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/AppendBlobAsyncClient.java index dfa5ca9bb966..cced720eb6b1 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncClient.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/AppendBlobAsyncClient.java @@ -1,13 +1,17 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; +import com.azure.core.annotation.ServiceClient; import com.azure.core.http.rest.Response; import com.azure.core.http.rest.SimpleResponse; -import com.azure.core.annotation.ServiceClient; import com.azure.core.implementation.util.FluxUtil; import com.azure.core.util.Context; +import com.azure.storage.blob.BlobAsyncClient; +import com.azure.storage.blob.BlobClientBuilder; +import com.azure.storage.blob.BlobServiceAsyncClient; +import com.azure.storage.blob.ContainerAsyncClient; import com.azure.storage.blob.implementation.AzureBlobStorageImpl; import com.azure.storage.blob.models.AppendBlobAccessConditions; import com.azure.storage.blob.models.AppendBlobItem; @@ -25,14 +29,13 @@ import java.nio.ByteBuffer; import static com.azure.core.implementation.util.FluxUtil.withContext; -import static com.azure.storage.blob.PostProcessor.postProcessResponse; +import static com.azure.storage.blob.implementation.PostProcessor.postProcessResponse; /** * Client to an append blob. It may only be instantiated through a - * {@link BlobClientBuilder#buildAppendBlobAsyncClient()}, via the method - * {@link BlobAsyncClient#asAppendBlobAsyncClient()}, or via the method - * {@link ContainerAsyncClient#getAppendBlobAsyncClient(String)}. 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. + * {@link SpecializedBlobClientBuilder#buildAppendBlobAsyncClient()} or via the method + * {@link BlobAsyncClient#asAppendBlobAsyncClient()}. 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 ContainerAsyncClient}, @@ -48,8 +51,8 @@ * operation, until {@code .subscribe()} is called on the reactive response. You can simply convert one of these * responses to a {@link java.util.concurrent.CompletableFuture} object through {@link Mono#toFuture()}. */ -@ServiceClient(builder = BlobClientBuilder.class, isAsync = true) -public final class AppendBlobAsyncClient extends BlobAsyncClient { +@ServiceClient(builder = SpecializedBlobClientBuilder.class, isAsync = true) +public final class AppendBlobAsyncClient extends BlobAsyncClientBase { /** * Indicates the maximum number of bytes that can be sent in a call to appendBlock. */ @@ -74,7 +77,7 @@ public final class AppendBlobAsyncClient extends BlobAsyncClient { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.AppendBlobAsyncClient.create} + * {@codesnippet com.azure.storage.blob.specialized.AppendBlobAsyncClient.create} * * @return A {@link Mono} containing the information of the created appended blob. */ @@ -87,7 +90,7 @@ public Mono create() { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.AppendBlobAsyncClient.createWithResponse#BlobHTTPHeaders-Metadata-BlobAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.AppendBlobAsyncClient.createWithResponse#BlobHTTPHeaders-Metadata-BlobAccessConditions} * * @param headers {@link BlobHTTPHeaders} * @param metadata {@link Metadata} @@ -106,8 +109,8 @@ Mono> createWithResponse(BlobHTTPHeaders headers, Metad accessConditions = (accessConditions == null) ? new BlobAccessConditions() : accessConditions; return postProcessResponse(this.azureBlobStorage.appendBlobs().createWithRestResponseAsync(null, - null, 0, null, metadata, null, headers, accessConditions.getLeaseAccessConditions(), cpk, - accessConditions.getModifiedAccessConditions(), context)) + null, 0, null, metadata, null, headers, accessConditions.getLeaseAccessConditions(), + getCustomerProvidedKey(), accessConditions.getModifiedAccessConditions(), context)) .map(rb -> new SimpleResponse<>(rb, new AppendBlobItem(rb.getDeserializedHeaders()))); } @@ -119,7 +122,7 @@ Mono> createWithResponse(BlobHTTPHeaders headers, Metad * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.AppendBlobAsyncClient.appendBlock#Flux-long} + * {@codesnippet com.azure.storage.blob.specialized.AppendBlobAsyncClient.appendBlock#Flux-long} * * @param data The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled * (the default). In other words, the Flux must produce the same data each time it is subscribed to. @@ -139,7 +142,7 @@ public Mono appendBlock(Flux data, long length) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.AppendBlobAsyncClient.appendBlockWithResponse#Flux-long-AppendBlobAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.AppendBlobAsyncClient.appendBlockWithResponse#Flux-long-AppendBlobAccessConditions} * * @param data The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled * (the default). In other words, the Flux must produce the same data each time it is subscribed to. @@ -162,7 +165,7 @@ Mono> appendBlockWithResponse(Flux data, lo return postProcessResponse(this.azureBlobStorage.appendBlobs().appendBlockWithRestResponseAsync( null, null, data, length, null, null, null, null, appendBlobAccessConditions.getLeaseAccessConditions(), - appendBlobAccessConditions.getAppendPositionAccessConditions(), cpk, + appendBlobAccessConditions.getAppendPositionAccessConditions(), getCustomerProvidedKey(), appendBlobAccessConditions.getModifiedAccessConditions(), context)) .map(rb -> new SimpleResponse<>(rb, new AppendBlobItem(rb.getDeserializedHeaders()))); } @@ -172,7 +175,7 @@ Mono> appendBlockWithResponse(Flux data, lo * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.AppendBlobAsyncClient.appendBlockFromUrl#URL-BlobRange} + * {@codesnippet com.azure.storage.blob.specialized.AppendBlobAsyncClient.appendBlockFromUrl#URL-BlobRange} * * @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 @@ -190,7 +193,7 @@ public Mono appendBlockFromUrl(URL sourceURL, BlobRange sourceRa * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.AppendBlobAsyncClient.appendBlockFromUrlWithResponse#URL-BlobRange-byte-AppendBlobAccessConditions-SourceModifiedAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.AppendBlobAsyncClient.appendBlockFromUrlWithResponse#URL-BlobRange-byte-AppendBlobAccessConditions-SourceModifiedAccessConditions} * * @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 @@ -219,8 +222,8 @@ Mono> appendBlockFromUrlWithResponse(URL sourceURL, Blo ? new AppendBlobAccessConditions() : destAccessConditions; return postProcessResponse( - this.azureBlobStorage.appendBlobs().appendBlockFromUrlWithRestResponseAsync(null, null, - sourceURL, 0, sourceRange.toString(), sourceContentMD5, null, null, null, null, cpk, + this.azureBlobStorage.appendBlobs().appendBlockFromUrlWithRestResponseAsync(null, null, sourceURL, 0, + sourceRange.toString(), sourceContentMD5, null, null, null, null, getCustomerProvidedKey(), destAccessConditions.getLeaseAccessConditions(), destAccessConditions.getAppendPositionAccessConditions(), destAccessConditions.getModifiedAccessConditions(), sourceAccessConditions, context)) diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/AppendBlobClient.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/AppendBlobClient.java similarity index 87% rename from sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/AppendBlobClient.java rename to sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/AppendBlobClient.java index d8ff9f9d804d..949a5f85e2a6 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/AppendBlobClient.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/AppendBlobClient.java @@ -1,12 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; +import com.azure.core.annotation.ServiceClient; import com.azure.core.exception.UnexpectedLengthException; import com.azure.core.http.rest.Response; -import com.azure.core.annotation.ServiceClient; import com.azure.core.util.Context; +import com.azure.storage.blob.BlobClient; +import com.azure.storage.blob.BlobClientBuilder; +import com.azure.storage.blob.BlobServiceClient; +import com.azure.storage.blob.ContainerClient; import com.azure.storage.blob.models.AppendBlobAccessConditions; import com.azure.storage.blob.models.AppendBlobItem; import com.azure.storage.blob.models.BlobAccessConditions; @@ -27,10 +31,9 @@ import java.util.Objects; /** - * Client to an append blob. It may only be instantiated through a {@link BlobClientBuilder}, via the method {@link - * BlobClient#asAppendBlobClient()}, or via the method {@link ContainerClient#getAppendBlobClient(String)}. 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. + * Client to an append blob. It may only be instantiated through a {@link SpecializedBlobClientBuilder} or via the + * method {@link BlobClient#asAppendBlobClient()}. 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 ContainerClient}, and @@ -40,8 +43,8 @@ * Please refer to the Azure * Docs for more information. */ -@ServiceClient(builder = BlobClientBuilder.class) -public final class AppendBlobClient extends BlobClient { +@ServiceClient(builder = SpecializedBlobClientBuilder.class) +public final class AppendBlobClient extends BlobClientBase { private final AppendBlobAsyncClient appendBlobAsyncClient; /** @@ -93,7 +96,7 @@ public BlobOutputStream getBlobOutputStream(AppendBlobAccessConditions accessCon * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.AppendBlobClient.create} + * {@codesnippet com.azure.storage.blob.specialized.AppendBlobClient.create} * * @return The information of the created appended blob. */ @@ -106,7 +109,7 @@ public AppendBlobItem create() { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.AppendBlobClient.createWithResponse#BlobHTTPHeaders-Metadata-BlobAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.AppendBlobClient.createWithResponse#BlobHTTPHeaders-Metadata-BlobAccessConditions-Duration-Context} * * @param headers {@link BlobHTTPHeaders} * @param metadata {@link Metadata} @@ -129,7 +132,7 @@ public Response createWithResponse(BlobHTTPHeaders headers, Meta * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.AppendBlobClient.appendBlock#InputStream-long} + * {@codesnippet com.azure.storage.blob.specialized.AppendBlobClient.appendBlock#InputStream-long} * * @param data The data to write to the blob. * @param length The exact length of the data. It is important that this value match precisely the length of the @@ -148,7 +151,7 @@ public AppendBlobItem appendBlock(InputStream data, long length) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.AppendBlobClient.appendBlockWithResponse#InputStream-long-AppendBlobAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.AppendBlobClient.appendBlockWithResponse#InputStream-long-AppendBlobAccessConditions-Duration-Context} * * @param data The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled * (the default). In other words, the Flux must produce the same data each time it is subscribed to. @@ -175,7 +178,7 @@ public Response appendBlockWithResponse(InputStream data, long l * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.AppendBlobClient.appendBlockFromUrl#URL-BlobRange} + * {@codesnippet com.azure.storage.blob.specialized.AppendBlobClient.appendBlockFromUrl#URL-BlobRange} * * @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 @@ -193,7 +196,7 @@ public AppendBlobItem appendBlockFromUrl(URL sourceURL, BlobRange sourceRange) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.AppendBlobClient.appendBlockFromUrlWithResponse#URL-BlobRange-byte-AppendBlobAccessConditions-SourceModifiedAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.AppendBlobClient.appendBlockFromUrlWithResponse#URL-BlobRange-byte-AppendBlobAccessConditions-SourceModifiedAccessConditions-Duration-Context} * * @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 diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobAsyncClientBase.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobAsyncClientBase.java new file mode 100644 index 000000000000..f54299a38b22 --- /dev/null +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobAsyncClientBase.java @@ -0,0 +1,1164 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.specialized; + +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.implementation.http.UrlBuilder; +import com.azure.core.implementation.util.FluxUtil; +import com.azure.core.util.Context; +import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.blob.BlobProperties; +import com.azure.storage.blob.BlobSASPermission; +import com.azure.storage.blob.BlobURLParts; +import com.azure.storage.blob.HTTPGetterInfo; +import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; +import com.azure.storage.blob.implementation.AzureBlobStorageImpl; +import com.azure.storage.blob.models.AccessTier; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.BlobStartCopyFromURLHeaders; +import com.azure.storage.blob.models.CpkInfo; +import com.azure.storage.blob.models.DeleteSnapshotsOptionType; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.RehydratePriority; +import com.azure.storage.blob.models.ReliableDownloadOptions; +import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import com.azure.storage.blob.models.StorageAccountInfo; +import com.azure.storage.blob.models.StorageException; +import com.azure.storage.blob.models.UserDelegationKey; +import com.azure.storage.common.Constants; +import com.azure.storage.common.IPRange; +import com.azure.storage.common.SASProtocol; +import com.azure.storage.common.Utility; +import com.azure.storage.common.credentials.SharedKeyCredential; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.channels.AsynchronousFileChannel; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.List; + +import static com.azure.core.implementation.util.FluxUtil.withContext; +import static com.azure.storage.blob.implementation.PostProcessor.postProcessResponse; + +/** + * This class provides a client that contains all operations that apply to any blob type. + * + *

    + * This client offers the ability to download blobs. Note that uploading data is specific to each type of blob. Please + * refer to the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient} for upload options. + */ +public class BlobAsyncClientBase { + private static final int BLOB_DEFAULT_DOWNLOAD_BLOCK_SIZE = 4 * Constants.MB; + private static final int BLOB_MAX_DOWNLOAD_BLOCK_SIZE = 100 * Constants.MB; + + private final ClientLogger logger = new ClientLogger(BlobAsyncClientBase.class); + + protected final AzureBlobStorageImpl azureBlobStorage; + private final String snapshot; + private final CpkInfo customerProvidedKey; + + /** + * Package-private constructor for use by {@link SpecializedBlobClientBuilder}. + * + * @param azureBlobStorage the API client for blob storage + * @param snapshot Optional. The snapshot identifier for the snapshot blob. + * @param customerProvidedKey Optional. Customer provided key used during encryption of the blob's data on the + * server. + */ + protected BlobAsyncClientBase(AzureBlobStorageImpl azureBlobStorage, String snapshot, CpkInfo customerProvidedKey) { + this.azureBlobStorage = azureBlobStorage; + this.snapshot = snapshot; + this.customerProvidedKey = customerProvidedKey; + } + + /** + * Creates a new {@link BlobAsyncClientBase} linked to the {@code snapshot} of this blob resource. + * + * @param snapshot the identifier for a specific snapshot of this blob + * @return a {@link BlobAsyncClientBase} used to interact with the specific snapshot. + */ + public BlobAsyncClientBase getSnapshotClient(String snapshot) { + return new BlobAsyncClientBase(new AzureBlobStorageBuilder() + .url(getBlobUrl().toString()) + .pipeline(azureBlobStorage.getHttpPipeline()) + .build(), snapshot, customerProvidedKey); + } + + /** + * Gets the URL of the blob represented by this client. + * + * @return the URL. + * @throws RuntimeException If the blob is using a malformed URL. + */ + public URL getBlobUrl() { + try { + UrlBuilder urlBuilder = UrlBuilder.parse(azureBlobStorage.getUrl()); + if (snapshot != null) { + urlBuilder.setQuery("snapshot=" + snapshot); + } + return urlBuilder.toURL(); + } catch (MalformedURLException e) { + throw logger.logExceptionAsError(new RuntimeException( + String.format("Invalid URL on %s: %s" + getClass().getSimpleName(), azureBlobStorage.getUrl()), e)); + } + } + + /** + * Get the container name. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.getContainerName} + * + * @return The name of the container. + */ + public final String getContainerName() { + return BlobURLParts.parse(this.azureBlobStorage.getUrl(), logger).getContainerName(); + } + + /** + * Get the blob name. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.getBlobName} + * + * @return The name of the blob. + */ + public final String getBlobName() { + return BlobURLParts.parse(this.azureBlobStorage.getUrl(), logger).getBlobName(); + } + + /** + * Gets the {@link HttpPipeline} powering this client. + * + * @return The pipeline. + */ + public HttpPipeline getHttpPipeline() { + return azureBlobStorage.getHttpPipeline(); + } + + /** + * Gets the {@link CpkInfo} used to encrypt this blob's content on the server. + * + * @return the customer provided key used for encryption. + */ + public CpkInfo getCustomerProvidedKey() { + return customerProvidedKey; + } + + /** + * Gets the snapshotId for a blob resource + * + * @return A string that represents the snapshotId of the snapshot blob + */ + public String getSnapshotId() { + return this.snapshot; + } + + /** + * Determines if a blob is a snapshot + * + * @return A boolean that indicates if a blob is a snapshot + */ + public boolean isSnapshot() { + return this.snapshot != null; + } + + /** + * Determines if the blob this client represents exists in the cloud. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.exists} + * + * @return true if the blob exists, false if it doesn't + */ + public Mono exists() { + return existsWithResponse().flatMap(FluxUtil::toMono); + } + + /** + * Determines if the blob this client represents exists in the cloud. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.existsWithResponse} + * + * @return true if the blob exists, false if it doesn't + */ + public Mono> existsWithResponse() { + return withContext(this::existsWithResponse); + } + + Mono> existsWithResponse(Context context) { + return this.getPropertiesWithResponse(null, context) + .map(cp -> (Response) new SimpleResponse<>(cp, true)) + .onErrorResume(t -> t instanceof StorageException && ((StorageException) t).getStatusCode() == 404, t -> { + HttpResponse response = ((StorageException) t).getResponse(); + return Mono.just(new SimpleResponse<>(response.getRequest(), response.getStatusCode(), + response.getHeaders(), false)); + }); + } + + /** + * Copies the data at the source URL to a blob. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.startCopyFromURL#URL} + * + *

    For more information, see the + * Azure Docs

    + * + * @param sourceURL The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * @return A reactive response containing the copy ID for the long running operation. + */ + public Mono startCopyFromURL(URL sourceURL) { + return startCopyFromURLWithResponse(sourceURL, null, null, null, null, null).flatMap(FluxUtil::toMono); + } + + /** + * Copies the data at the source URL to a blob. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.startCopyFromURLWithResponse#URL-Metadata-AccessTier-RehydratePriority-ModifiedAccessConditions-BlobAccessConditions} + * + *

    For more information, see the + * Azure Docs

    + * + * @param sourceURL The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * @param metadata {@link Metadata} + * @param tier {@link AccessTier} for the destination blob. + * @param priority {@link RehydratePriority} for rehydrating the blob. + * @param sourceModifiedAccessConditions {@link ModifiedAccessConditions} against the source. Standard HTTP Access + * conditions related to the modification of data. ETag and LastModifiedTime are used to construct conditions + * related to when the blob was changed relative to the given request. The request will fail if the specified + * condition is not satisfied. + * @param destAccessConditions {@link BlobAccessConditions} against the destination. + * @return A reactive response containing the copy ID for the long running operation. + */ + public Mono> startCopyFromURLWithResponse(URL sourceURL, Metadata metadata, AccessTier tier, + RehydratePriority priority, ModifiedAccessConditions sourceModifiedAccessConditions, + BlobAccessConditions destAccessConditions) { + return withContext(context -> startCopyFromURLWithResponse(sourceURL, metadata, tier, priority, + sourceModifiedAccessConditions, destAccessConditions, context)); + } + + Mono> startCopyFromURLWithResponse(URL sourceURL, Metadata metadata, AccessTier tier, + RehydratePriority priority, ModifiedAccessConditions sourceModifiedAccessConditions, + BlobAccessConditions destAccessConditions, Context context) { + metadata = metadata == null ? new Metadata() : metadata; + sourceModifiedAccessConditions = sourceModifiedAccessConditions == null + ? new ModifiedAccessConditions() : sourceModifiedAccessConditions; + destAccessConditions = destAccessConditions == null ? new BlobAccessConditions() : destAccessConditions; + + // We want to hide the SourceAccessConditions type from the user for consistency's sake, so we convert here. + SourceModifiedAccessConditions sourceConditions = new SourceModifiedAccessConditions() + .setSourceIfModifiedSince(sourceModifiedAccessConditions.getIfModifiedSince()) + .setSourceIfUnmodifiedSince(sourceModifiedAccessConditions.getIfUnmodifiedSince()) + .setSourceIfMatch(sourceModifiedAccessConditions.getIfMatch()) + .setSourceIfNoneMatch(sourceModifiedAccessConditions.getIfNoneMatch()); + + return postProcessResponse(this.azureBlobStorage.blobs().startCopyFromURLWithRestResponseAsync( + null, null, sourceURL, null, metadata, tier, priority, null, sourceConditions, + destAccessConditions.getModifiedAccessConditions(), destAccessConditions.getLeaseAccessConditions(), + context)) + .map(rb -> new SimpleResponse<>(rb, rb.getDeserializedHeaders().getCopyId())); + } + + /** + * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.abortCopyFromURL#String} + * + *

    For more information, see the + * Azure Docs

    + * + * @param copyId The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link + * BlobStartCopyFromURLHeaders} object. + * @return A reactive response signalling completion. + */ + public Mono abortCopyFromURL(String copyId) { + return abortCopyFromURLWithResponse(copyId, null).flatMap(FluxUtil::toMono); + } + + /** + * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.abortCopyFromURLWithResponse#String-LeaseAccessConditions} + * + *

    For more information, see the + * Azure Docs

    + * + * @param copyId The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link + * BlobStartCopyFromURLHeaders} object. + * @param leaseAccessConditions By setting lease access conditions, requests will fail if the provided lease does + * not match the active lease on the blob. + * @return A reactive response signalling completion. + */ + public Mono> abortCopyFromURLWithResponse(String copyId, + LeaseAccessConditions leaseAccessConditions) { + return withContext(context -> abortCopyFromURLWithResponse(copyId, leaseAccessConditions, context)); + } + + Mono> abortCopyFromURLWithResponse(String copyId, LeaseAccessConditions leaseAccessConditions, + Context context) { + return postProcessResponse(this.azureBlobStorage.blobs().abortCopyFromURLWithRestResponseAsync( + null, null, copyId, null, null, leaseAccessConditions, context)) + .map(response -> new SimpleResponse<>(response, null)); + } + + /** + * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.copyFromURL#URL} + * + *

    For more information, see the + * Azure Docs

    + * + * @param copySource The source URL to copy from. + * @return A reactive response containing the copy ID for the long running operation. + */ + public Mono copyFromURL(URL copySource) { + return copyFromURLWithResponse(copySource, null, null, null, null).flatMap(FluxUtil::toMono); + } + + /** + * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.copyFromURLWithResponse#URL-Metadata-AccessTier-ModifiedAccessConditions-BlobAccessConditions} + * + *

    For more information, see the + * Azure Docs

    + * + * @param copySource The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * @param metadata {@link Metadata} + * @param tier {@link AccessTier} for the destination blob. + * @param sourceModifiedAccessConditions {@link ModifiedAccessConditions} against the source. Standard HTTP Access + * conditions related to the modification of data. ETag and LastModifiedTime are used to construct conditions + * related to when the blob was changed relative to the given request. The request will fail if the specified + * condition is not satisfied. + * @param destAccessConditions {@link BlobAccessConditions} against the destination. + * @return A reactive response containing the copy ID for the long running operation. + */ + public Mono> copyFromURLWithResponse(URL copySource, Metadata metadata, AccessTier tier, + ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions) { + return withContext(context -> copyFromURLWithResponse(copySource, metadata, tier, + sourceModifiedAccessConditions, destAccessConditions, context)); + } + + Mono> copyFromURLWithResponse(URL copySource, Metadata metadata, AccessTier tier, + ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions, + Context context) { + metadata = metadata == null ? new Metadata() : metadata; + sourceModifiedAccessConditions = sourceModifiedAccessConditions == null + ? new ModifiedAccessConditions() : sourceModifiedAccessConditions; + destAccessConditions = destAccessConditions == null ? new BlobAccessConditions() : destAccessConditions; + + // We want to hide the SourceAccessConditions type from the user for consistency's sake, so we convert here. + SourceModifiedAccessConditions sourceConditions = new SourceModifiedAccessConditions() + .setSourceIfModifiedSince(sourceModifiedAccessConditions.getIfModifiedSince()) + .setSourceIfUnmodifiedSince(sourceModifiedAccessConditions.getIfUnmodifiedSince()) + .setSourceIfMatch(sourceModifiedAccessConditions.getIfMatch()) + .setSourceIfNoneMatch(sourceModifiedAccessConditions.getIfNoneMatch()); + + return postProcessResponse(this.azureBlobStorage.blobs().copyFromURLWithRestResponseAsync( + null, null, copySource, null, metadata, tier, null, sourceConditions, + destAccessConditions.getModifiedAccessConditions(), destAccessConditions.getLeaseAccessConditions(), + context)) + .map(rb -> new SimpleResponse<>(rb, rb.getDeserializedHeaders().getCopyId())); + } + + /** + * Reads the entire blob. Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or + * {@link AppendBlobClient}. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.download} + * + *

    For more information, see the + * Azure Docs

    + * + * @return A reactive response containing the blob data. + */ + public Mono> download() { + return downloadWithResponse(null, null, null, false).flatMap(FluxUtil::toMono); + } + + /** + * Reads a range of bytes from a blob. Uploading data must be done from the {@link BlockBlobClient}, {@link + * PageBlobClient}, or {@link AppendBlobClient}. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadWithResponse#BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean} + * + *

    For more information, see the + * Azure Docs

    + * + * @param range {@link BlobRange} + * @param options {@link ReliableDownloadOptions} + * @param accessConditions {@link BlobAccessConditions} + * @param rangeGetContentMD5 Whether the contentMD5 for the specified blob range should be returned. + * @return A reactive response containing the blob data. + */ + public Mono>> downloadWithResponse(BlobRange range, ReliableDownloadOptions options, + BlobAccessConditions accessConditions, boolean rangeGetContentMD5) { + return withContext(context -> downloadWithResponse(range, options, accessConditions, rangeGetContentMD5, + context)); + } + + Mono>> downloadWithResponse(BlobRange range, ReliableDownloadOptions options, + BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Context context) { + return download(range, accessConditions, rangeGetContentMD5, context) + .map(response -> new SimpleResponse<>( + response.getRawResponse(), + response.body(options).switchIfEmpty(Flux.just(ByteBuffer.wrap(new byte[0]))))); + } + + /** + * Reads a range of bytes from a blob. The response also includes the blob's properties and metadata. For more + * information, see the Azure Docs. + *

    + * Note that the response body has reliable download functionality built in, meaning that a failed download stream + * will be automatically retried. This behavior may be configured with {@link ReliableDownloadOptions}. + * + * @param range {@link BlobRange} + * @param accessConditions {@link BlobAccessConditions} + * @param rangeGetContentMD5 Whether the contentMD5 for the specified blob range should be returned. + * @return Emits the successful response. + */ + Mono download(BlobRange range, BlobAccessConditions accessConditions, + boolean rangeGetContentMD5) { + return withContext(context -> download(range, accessConditions, rangeGetContentMD5, context)); + } + + Mono download(BlobRange range, BlobAccessConditions accessConditions, + boolean rangeGetContentMD5, Context context) { + range = range == null ? new BlobRange(0) : range; + Boolean getMD5 = rangeGetContentMD5 ? rangeGetContentMD5 : null; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + HTTPGetterInfo info = new HTTPGetterInfo() + .setOffset(range.getOffset()) + .setCount(range.getCount()) + .setETag(accessConditions.getModifiedAccessConditions().getIfMatch()); + + // TODO: range is BlobRange but expected as String + // TODO: figure out correct response + return postProcessResponse(this.azureBlobStorage.blobs().downloadWithRestResponseAsync( + null, null, snapshot, null, range.toHeaderValue(), getMD5, null, null, + accessConditions.getLeaseAccessConditions(), customerProvidedKey, + accessConditions.getModifiedAccessConditions(), context)) + // Convert the autorest response to a DownloadAsyncResponse, which enable reliable download. + .map(response -> { + // If there wasn't an etag originally specified, lock on the one returned. + info.setETag(response.getDeserializedHeaders().getETag()); + return new DownloadAsyncResponse(response, info, + // In the event of a stream failure, make a new request to pick up where we left off. + newInfo -> + this.download(new BlobRange(newInfo.getOffset(), newInfo.getCount()), + new BlobAccessConditions().setModifiedAccessConditions( + new ModifiedAccessConditions().setIfMatch(info.getETag())), false, context)); + }); + } + + + /** + * Downloads the entire blob into a file specified by the path. + * + *

    The file will be created and must not exist, if the file already exists a {@link FileAlreadyExistsException} + * will be thrown.

    + * + *

    Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link + * AppendBlobClient}.

    + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadToFile#String} + * + *

    For more information, see the + * Azure Docs

    + * + * @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written. + * @return An empty response + */ + public Mono downloadToFile(String filePath) { + return downloadToFile(filePath, null, BLOB_DEFAULT_DOWNLOAD_BLOCK_SIZE, null, null, false); + } + + /** + * Downloads the entire blob into a file specified by the path. + * + *

    The file will be created and must not exist, if the file already exists a {@link FileAlreadyExistsException} + * will be thrown.

    + * + *

    Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link + * AppendBlobClient}.

    + * + *

    This method makes an extra HTTP call to get the length of the blob in the beginning. To avoid this extra + * call, provide the {@link BlobRange} parameter.

    + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadToFile#String-BlobRange-Integer-ReliableDownloadOptions-BlobAccessConditions-boolean} + * + *

    For more information, see the + * Azure Docs

    + * + * @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written. + * @param range {@link BlobRange} + * @param blockSize the size of a chunk to download at a time, in bytes + * @param options {@link ReliableDownloadOptions} + * @param accessConditions {@link BlobAccessConditions} + * @param rangeGetContentMD5 Whether the contentMD5 for the specified blob range should be returned. + * @return An empty response + * @throws IllegalArgumentException If {@code blockSize} is less than 0 or greater than 100MB. + * @throws UncheckedIOException If an I/O error occurs. + */ + public Mono downloadToFile(String filePath, BlobRange range, Integer blockSize, + ReliableDownloadOptions options, BlobAccessConditions accessConditions, boolean rangeGetContentMD5) { + return withContext(context -> downloadToFile(filePath, range, blockSize, options, accessConditions, + rangeGetContentMD5, context)); + } + + Mono downloadToFile(String filePath, BlobRange range, Integer blockSize, ReliableDownloadOptions options, + BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Context context) { + if (blockSize != null) { + Utility.assertInBounds("blockSize", blockSize, 0, BLOB_MAX_DOWNLOAD_BLOCK_SIZE); + } + + return Mono.using(() -> downloadToFileResourceSupplier(filePath), + channel -> Mono.justOrEmpty(range) + .switchIfEmpty(getFullBlobRange(accessConditions)) + .flatMapMany(rg -> Flux.fromIterable(sliceBlobRange(rg, blockSize))) + .flatMap(chunk -> this.download(chunk, accessConditions, rangeGetContentMD5, context) + .subscribeOn(Schedulers.elastic()) + .flatMap(dar -> FluxUtil.writeFile(dar.body(options), channel, + chunk.getOffset() - (range == null ? 0 : range.getOffset())))) + .then(), this::downloadToFileCleanup); + } + + private AsynchronousFileChannel downloadToFileResourceSupplier(String filePath) { + try { + return AsynchronousFileChannel.open(Paths.get(filePath), StandardOpenOption.READ, StandardOpenOption.WRITE, + StandardOpenOption.CREATE_NEW); + } catch (IOException e) { + throw logger.logExceptionAsError(new UncheckedIOException(e)); + } + } + + private void downloadToFileCleanup(AsynchronousFileChannel channel) { + try { + channel.close(); + } catch (IOException e) { + throw logger.logExceptionAsError(new UncheckedIOException(e)); + } + } + + private Mono getFullBlobRange(BlobAccessConditions accessConditions) { + return getPropertiesWithResponse(accessConditions).map(rb -> new BlobRange(0, rb.getValue().getBlobSize())); + } + + private List sliceBlobRange(BlobRange blobRange, Integer blockSize) { + if (blockSize == null) { + blockSize = BLOB_DEFAULT_DOWNLOAD_BLOCK_SIZE; + } + long offset = blobRange.getOffset(); + long length = blobRange.getCount(); + List chunks = new ArrayList<>(); + for (long pos = offset; pos < offset + length; pos += blockSize) { + long count = blockSize; + if (pos + count > offset + length) { + count = offset + length - pos; + } + chunks.add(new BlobRange(pos, count)); + } + return chunks; + } + + /** + * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.delete} + * + *

    For more information, see the + * Azure Docs

    + * + * @return A reactive response signalling completion. + */ + public Mono delete() { + return deleteWithResponse(null, null).flatMap(FluxUtil::toMono); + } + + /** + * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.deleteWithResponse#DeleteSnapshotsOptionType-BlobAccessConditions} + * + *

    For more information, see the + * Azure Docs

    + * + * @param deleteBlobSnapshotOptions Specifies the behavior for deleting the snapshots on this blob. {@code Include} + * will delete the base blob and all snapshots. {@code Only} will delete only the snapshots. If a snapshot is being + * deleted, you must pass null. + * @param accessConditions {@link BlobAccessConditions} + * @return A reactive response signalling completion. + */ + public Mono> deleteWithResponse(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, + BlobAccessConditions accessConditions) { + return withContext(context -> deleteWithResponse(deleteBlobSnapshotOptions, accessConditions, context)); + } + + Mono> deleteWithResponse(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, + BlobAccessConditions accessConditions, Context context) { + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blobs().deleteWithRestResponseAsync( + null, null, snapshot, null, deleteBlobSnapshotOptions, + null, accessConditions.getLeaseAccessConditions(), accessConditions.getModifiedAccessConditions(), + context)) + .map(response -> new SimpleResponse<>(response, null)); + } + + /** + * Returns the blob's metadata and properties. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.getProperties} + * + *

    For more information, see the + * Azure Docs

    + * + * @return A reactive response containing the blob properties and metadata. + */ + public Mono getProperties() { + return getPropertiesWithResponse(null).flatMap(FluxUtil::toMono); + } + + /** + * Returns the blob's metadata and properties. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.getPropertiesWithResponse#BlobAccessConditions} + * + *

    For more information, see the + * Azure Docs

    + * + * @param accessConditions {@link BlobAccessConditions} + * @return A reactive response containing the blob properties and metadata. + */ + public Mono> getPropertiesWithResponse(BlobAccessConditions accessConditions) { + return withContext(context -> getPropertiesWithResponse(accessConditions, context)); + } + + Mono> getPropertiesWithResponse(BlobAccessConditions accessConditions, Context context) { + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blobs().getPropertiesWithRestResponseAsync( + null, null, snapshot, null, null, accessConditions.getLeaseAccessConditions(), customerProvidedKey, + accessConditions.getModifiedAccessConditions(), context)) + .map(rb -> new SimpleResponse<>(rb, new BlobProperties(rb.getDeserializedHeaders()))); + } + + /** + * Changes a blob's HTTP header properties. if only one HTTP header is updated, the others will all be erased. In + * order to preserve existing values, they must be passed alongside the header being changed. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.setHTTPHeaders#BlobHTTPHeaders} + * + *

    For more information, see the + * Azure Docs

    + * + * @param headers {@link BlobHTTPHeaders} + * @return A reactive response signalling completion. + */ + public Mono setHTTPHeaders(BlobHTTPHeaders headers) { + return setHTTPHeadersWithResponse(headers, null).flatMap(FluxUtil::toMono); + } + + /** + * Changes a blob's HTTP header properties. if only one HTTP header is updated, the others will all be erased. In + * order to preserve existing values, they must be passed alongside the header being changed. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.setHTTPHeadersWithResponse#BlobHTTPHeaders-BlobAccessConditions} + * + *

    For more information, see the + * Azure Docs

    + * + * @param headers {@link BlobHTTPHeaders} + * @param accessConditions {@link BlobAccessConditions} + * @return A reactive response signalling completion. + */ + public Mono> setHTTPHeadersWithResponse(BlobHTTPHeaders headers, + BlobAccessConditions accessConditions) { + return withContext(context -> setHTTPHeadersWithResponse(headers, accessConditions, context)); + } + + Mono> setHTTPHeadersWithResponse(BlobHTTPHeaders headers, BlobAccessConditions accessConditions, + Context context) { + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blobs().setHTTPHeadersWithRestResponseAsync( + null, null, null, null, headers, + accessConditions.getLeaseAccessConditions(), accessConditions.getModifiedAccessConditions(), context)) + .map(response -> new SimpleResponse<>(response, null)); + } + + /** + * Changes a blob's metadata. The specified metadata in this method will replace existing metadata. If old values + * must be preserved, they must be downloaded and included in the call to this method. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.setMetadata#Metadata} + * + *

    For more information, see the + * Azure Docs

    + * + * @param metadata {@link Metadata} + * @return A reactive response signalling completion. + */ + public Mono setMetadata(Metadata metadata) { + return setMetadataWithResponse(metadata, null).flatMap(FluxUtil::toMono); + } + + /** + * Changes a blob's metadata. The specified metadata in this method will replace existing metadata. If old values + * must be preserved, they must be downloaded and included in the call to this method. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.setMetadataWithResponse#Metadata-BlobAccessConditions} + * + *

    For more information, see the + * Azure Docs

    + * + * @param metadata {@link Metadata} + * @param accessConditions {@link BlobAccessConditions} + * @return A reactive response signalling completion. + */ + public Mono> setMetadataWithResponse(Metadata metadata, BlobAccessConditions accessConditions) { + return withContext(context -> setMetadataWithResponse(metadata, accessConditions, context)); + } + + Mono> setMetadataWithResponse(Metadata metadata, BlobAccessConditions accessConditions, + Context context) { + metadata = metadata == null ? new Metadata() : metadata; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blobs().setMetadataWithRestResponseAsync( + null, null, null, metadata, null, accessConditions.getLeaseAccessConditions(), customerProvidedKey, + accessConditions.getModifiedAccessConditions(), context)) + .map(response -> new SimpleResponse<>(response, null)); + } + + /** + * Creates a read-only snapshot of the blob. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.createSnapshot} + * + *

    For more information, see the + * Azure Docs

    + * + * @return A response containing a {@link BlobAsyncClientBase} which is used to interact with the created snapshot, + * use {@link #getSnapshotId()} to get the identifier for the snapshot. + */ + public Mono createSnapshot() { + return createSnapshotWithResponse(null, null).flatMap(FluxUtil::toMono); + } + + /** + * Creates a read-only snapshot of the blob. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.createSnapshotWithResponse#Metadata-BlobAccessConditions} + * + *

    For more information, see the + * Azure Docs

    + * + * @param metadata {@link Metadata} + * @param accessConditions {@link BlobAccessConditions} + * @return A response containing a {@link BlobAsyncClientBase} which is used to interact with the created snapshot, + * use {@link #getSnapshotId()} to get the identifier for the snapshot. + */ + public Mono> createSnapshotWithResponse(Metadata metadata, + BlobAccessConditions accessConditions) { + return withContext(context -> createSnapshotWithResponse(metadata, accessConditions, context)); + } + + Mono> createSnapshotWithResponse(Metadata metadata, + BlobAccessConditions accessConditions, Context context) { + metadata = metadata == null ? new Metadata() : metadata; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blobs().createSnapshotWithRestResponseAsync( + null, null, null, metadata, null, customerProvidedKey, accessConditions.getModifiedAccessConditions(), + accessConditions.getLeaseAccessConditions(), context)) + .map(rb -> new SimpleResponse<>(rb, this.getSnapshotClient(rb.getDeserializedHeaders().getSnapshot()))); + } + + /** + * Sets the tier on a blob. The operation is allowed on a page blob in a premium storage account or a block blob in + * a blob storage or GPV2 account. A premium page blob's tier determines the allowed size, IOPS, and bandwidth of + * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's + * etag. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.setTier#AccessTier} + * + *

    For more information, see the + * Azure Docs

    + * + * @param tier The new tier for the blob. + * @return A reactive response signalling completion. + */ + public Mono setTier(AccessTier tier) { + return setTierWithResponse(tier, null, null).flatMap(FluxUtil::toMono); + } + + /** + * Sets the tier on a blob. The operation is allowed on a page blob in a premium storage account or a block blob in + * a blob storage or GPV2 account. A premium page blob's tier determines the allowed size, IOPS, and bandwidth of + * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's + * etag. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.setTierWithResponse#AccessTier-RehydratePriority-LeaseAccessConditions} + * + *

    For more information, see the + * Azure Docs

    + * + * @param tier The new tier for the blob. + * @param priority Optional priority to set for re-hydrating blobs. + * @param leaseAccessConditions By setting lease access conditions, requests will fail if the provided lease does + * not match the active lease on the blob. + * @return A reactive response signalling completion. + */ + public Mono> setTierWithResponse(AccessTier tier, RehydratePriority priority, + LeaseAccessConditions leaseAccessConditions) { + return withContext(context -> setTierWithResponse(tier, priority, leaseAccessConditions, context)); + } + + Mono> setTierWithResponse(AccessTier tier, RehydratePriority priority, + LeaseAccessConditions leaseAccessConditions, Context context) { + Utility.assertNotNull("tier", tier); + + return postProcessResponse(this.azureBlobStorage.blobs().setTierWithRestResponseAsync( + null, null, tier, null, priority, null, leaseAccessConditions, context)) + .map(response -> new SimpleResponse<>(response, null)); + } + + /** + * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.undelete} + * + *

    For more information, see the + * Azure Docs

    + * + * @return A reactive response signalling completion. + */ + public Mono undelete() { + return undeleteWithResponse().flatMap(FluxUtil::toMono); + } + + /** + * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.undeleteWithResponse} + * + *

    For more information, see the + * Azure Docs

    + * + * @return A reactive response signalling completion. + */ + public Mono> undeleteWithResponse() { + return withContext(this::undeleteWithResponse); + } + + Mono> undeleteWithResponse(Context context) { + return postProcessResponse(this.azureBlobStorage.blobs().undeleteWithRestResponseAsync(null, + null, context)) + .map(response -> new SimpleResponse<>(response, null)); + } + + /** + * Returns the sku name and account kind for the account. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.getAccountInfo} + * + *

    For more information, see the + * Azure Docs

    + * + * @return a reactor response containing the sku name and account kind. + */ + public Mono getAccountInfo() { + return getAccountInfoWithResponse().flatMap(FluxUtil::toMono); + } + + /** + * Returns the sku name and account kind for the account. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.getAccountInfoWithResponse} + * + *

    For more information, see the + * Azure Docs

    + * + * @return a reactor response containing the sku name and account kind. + */ + public Mono> getAccountInfoWithResponse() { + return withContext(this::getAccountInfoWithResponse); + } + + Mono> getAccountInfoWithResponse(Context context) { + return postProcessResponse( + this.azureBlobStorage.blobs().getAccountInfoWithRestResponseAsync(null, null, context)) + .map(rb -> new SimpleResponse<>(rb, new StorageAccountInfo(rb.getDeserializedHeaders()))); + } + + /** + * Generates a user delegation SAS with the specified parameters + * + * @param userDelegationKey The {@code UserDelegationKey} user delegation key for the SAS + * @param accountName The {@code String} account name for the SAS + * @param permissions The {@code ContainerSASPermissions} permission for the SAS + * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS + * @return A string that represents the SAS token + */ + public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, String accountName, + BlobSASPermission permissions, OffsetDateTime expiryTime) { + return this.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime, null /* + startTime */, null /* version */, null /*sasProtocol */, null /* ipRange */, null /* cacheControl */, null + /*contentDisposition */, null /* contentEncoding */, null /* contentLanguage */, null /* contentType */); + } + + /** + * Generates a user delegation SAS token with the specified parameters + * + * @param userDelegationKey The {@code UserDelegationKey} user delegation key for the SAS + * @param accountName The {@code String} account name for the SAS + * @param permissions The {@code ContainerSASPermissions} permission for the SAS + * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS + * @param startTime An optional {@code OffsetDateTime} start time for the SAS + * @param version An optional {@code String} version for the SAS + * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS + * @param ipRange An optional {@code IPRange} ip address range for the SAS + * @return A string that represents the SAS token + */ + public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, String accountName, + BlobSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, + SASProtocol sasProtocol, IPRange ipRange) { + return this.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime, startTime, + version, sasProtocol, ipRange, null /* cacheControl */, null /* contentDisposition */, null /* + contentEncoding */, null /* contentLanguage */, null /* contentType */); + } + + /** + * Generates a user delegation SAS token with the specified parameters + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.generateUserDelegationSAS#UserDelegationKey-String-BlobSASPermission-OffsetDateTime-OffsetDateTime-String-SASProtocol-IPRange-String-String-String-String-String} + * + *

    For more information, see the + * Azure + * Docs

    + * + * @param userDelegationKey The {@code UserDelegationKey} user delegation key for the SAS + * @param accountName The {@code String} account name for the SAS + * @param permissions The {@code BlobSASPermission} permission for the SAS + * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS + * @param startTime An optional {@code OffsetDateTime} start time for the SAS + * @param version An optional {@code String} version for the SAS + * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS + * @param ipRange An optional {@code IPRange} ip address range for the SAS + * @param cacheControl An optional {@code String} cache-control header for the SAS. + * @param contentDisposition An optional {@code String} content-disposition header for the SAS. + * @param contentEncoding An optional {@code String} content-encoding header for the SAS. + * @param contentLanguage An optional {@code String} content-language header for the SAS. + * @param contentType An optional {@code String} content-type header for the SAS. + * @return A string that represents the SAS token + */ + public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, String accountName, + BlobSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, + SASProtocol sasProtocol, IPRange ipRange, String cacheControl, String contentDisposition, + String contentEncoding, String contentLanguage, String contentType) { + + BlobServiceSASSignatureValues blobServiceSASSignatureValues = new BlobServiceSASSignatureValues(version, + sasProtocol, startTime, expiryTime, permissions == null ? null : permissions.toString(), ipRange, + null /* identifier*/, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); + + BlobServiceSASSignatureValues values = configureServiceSASSignatureValues(blobServiceSASSignatureValues, + accountName); + + BlobServiceSASQueryParameters blobServiceSasQueryParameters = + values.generateSASQueryParameters(userDelegationKey); + + return blobServiceSasQueryParameters.encode(); + } + + /** + * Generates a SAS token with the specified parameters + * + * @param permissions The {@code BlobSASPermission} permission for the SAS + * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS + * @return A string that represents the SAS token + */ + public String generateSAS(BlobSASPermission permissions, OffsetDateTime expiryTime) { + return this.generateSAS(null, permissions, expiryTime, null /* startTime */, /* identifier */ null /* + version */, null /* sasProtocol */, null /* ipRange */, null /* cacheControl */, null /* contentLanguage*/, + null /* contentEncoding */, null /* contentLanguage */, null /* contentType */); + } + + /** + * Generates a SAS token with the specified parameters + * + * @param identifier The {@code String} name of the access policy on the container this SAS references if any + * @return A string that represents the SAS token + */ + public String generateSAS(String identifier) { + return this.generateSAS(identifier, null /* permissions */, null /* expiryTime */, null /* startTime */, + null /* version */, null /* sasProtocol */, null /* ipRange */, null /* cacheControl */, null /* + contentLanguage*/, null /* contentEncoding */, null /* contentLanguage */, null /* contentType */); + } + + /** + * Generates a SAS token with the specified parameters + * + * @param identifier The {@code String} name of the access policy on the container this SAS references if any + * @param permissions The {@code BlobSASPermission} permission for the SAS + * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS + * @param startTime An optional {@code OffsetDateTime} start time for the SAS + * @param version An optional {@code String} version for the SAS + * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS + * @param ipRange An optional {@code IPRange} ip address range for the SAS + * @return A string that represents the SAS token + */ + public String generateSAS(String identifier, BlobSASPermission permissions, OffsetDateTime expiryTime, + OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange) { + return this.generateSAS(identifier, permissions, expiryTime, startTime, version, sasProtocol, ipRange, null + /* cacheControl */, null /* contentLanguage*/, null /* contentEncoding */, null /* contentLanguage */, + null /* contentType */); + } + + /** + * Generates a SAS token with the specified parameters + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.generateSAS#String-BlobSASPermission-OffsetDateTime-OffsetDateTime-String-SASProtocol-IPRange-String-String-String-String-String} + * + *

    For more information, see the + * Azure Docs

    + * + * @param identifier The {@code String} name of the access policy on the container this SAS references if any + * @param permissions The {@code BlobSASPermission} permission for the SAS + * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS + * @param startTime An optional {@code OffsetDateTime} start time for the SAS + * @param version An optional {@code String} version for the SAS + * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS + * @param ipRange An optional {@code IPRange} ip address range for the SAS + * @param cacheControl An optional {@code String} cache-control header for the SAS. + * @param contentDisposition An optional {@code String} content-disposition header for the SAS. + * @param contentEncoding An optional {@code String} content-encoding header for the SAS. + * @param contentLanguage An optional {@code String} content-language header for the SAS. + * @param contentType An optional {@code String} content-type header for the SAS. + * @return A string that represents the SAS token + */ + public String generateSAS(String identifier, BlobSASPermission permissions, OffsetDateTime expiryTime, + OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange, String cacheControl, + String contentDisposition, String contentEncoding, String contentLanguage, String contentType) { + + BlobServiceSASSignatureValues blobServiceSASSignatureValues = new BlobServiceSASSignatureValues(version, + sasProtocol, startTime, expiryTime, permissions == null ? null : permissions.toString(), ipRange, + identifier, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); + + SharedKeyCredential sharedKeyCredential = + Utility.getSharedKeyCredential(this.azureBlobStorage.getHttpPipeline()); + + Utility.assertNotNull("sharedKeyCredential", sharedKeyCredential); + + BlobServiceSASSignatureValues values = configureServiceSASSignatureValues(blobServiceSASSignatureValues, + sharedKeyCredential.getAccountName()); + + BlobServiceSASQueryParameters blobServiceSasQueryParameters = + values.generateSASQueryParameters(sharedKeyCredential); + + return blobServiceSasQueryParameters.encode(); + } + + /** + * Sets blobServiceSASSignatureValues parameters dependent on the current blob type + */ + private BlobServiceSASSignatureValues configureServiceSASSignatureValues( + BlobServiceSASSignatureValues blobServiceSASSignatureValues, String accountName) { + + // Set canonical name + blobServiceSASSignatureValues.setCanonicalName(this.azureBlobStorage.getUrl(), accountName); + + // Set snapshotId + blobServiceSASSignatureValues.setSnapshotId(getSnapshotId()); + + // Set resource + if (isSnapshot()) { + blobServiceSASSignatureValues.setResource(Constants.UrlConstants.SAS_BLOB_SNAPSHOT_CONSTANT); + } else { + blobServiceSASSignatureValues.setResource(Constants.UrlConstants.SAS_BLOB_CONSTANT); + } + + return blobServiceSASSignatureValues; + } +} diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobClientBase.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobClientBase.java new file mode 100644 index 000000000000..5d4b2b871ef5 --- /dev/null +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobClientBase.java @@ -0,0 +1,921 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.specialized; + +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.implementation.util.FluxUtil; +import com.azure.core.util.Context; +import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.blob.BlobClient; +import com.azure.storage.blob.BlobProperties; +import com.azure.storage.blob.BlobSASPermission; +import com.azure.storage.blob.models.AccessTier; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.BlobStartCopyFromURLHeaders; +import com.azure.storage.blob.models.CpkInfo; +import com.azure.storage.blob.models.DeleteSnapshotsOptionType; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.RehydratePriority; +import com.azure.storage.blob.models.ReliableDownloadOptions; +import com.azure.storage.blob.models.StorageAccountInfo; +import com.azure.storage.blob.models.StorageException; +import com.azure.storage.blob.models.UserDelegationKey; +import com.azure.storage.common.IPRange; +import com.azure.storage.common.SASProtocol; +import com.azure.storage.common.Utility; +import reactor.core.publisher.Mono; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.net.URL; +import java.nio.file.FileAlreadyExistsException; +import java.time.Duration; +import java.time.OffsetDateTime; + +/** + * This class provides a client that contains all operations that apply to any blob type. + * + *

    + * This client offers the ability to download blobs. Note that uploading data is specific to each type of blob. Please + * refer to the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient} for upload options. + */ +public class BlobClientBase { + private final ClientLogger logger = new ClientLogger(BlobClientBase.class); + + private final BlobAsyncClientBase client; + + /** + * Constructor used by {@link SpecializedBlobClientBuilder}. + * + * @param client the async blob client + */ + protected BlobClientBase(BlobAsyncClientBase client) { + this.client = client; + } + + /** + * Creates a new {@link BlobClientBase} linked to the {@code snapshot} of this blob resource. + * + * @param snapshot the identifier for a specific snapshot of this blob + * @return a {@link BlobClientBase} used to interact with the specific snapshot. + */ + public BlobClientBase getSnapshotClient(String snapshot) { + return new BlobClientBase(client.getSnapshotClient(snapshot)); + } + + /** + * Gets the URL of the blob represented by this client. + * + * @return the URL. + */ + public URL getBlobUrl() { + return client.getBlobUrl(); + } + + /** + * Get the container name. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.getContainerName} + * + * @return The name of the container. + */ + public final String getContainerName() { + return client.getContainerName(); + } + + /** + * Get the blob name. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.getBlobName} + * + * @return The name of the blob. + */ + public final String getBlobName() { + return client.getBlobName(); + } + + /** + * Gets the {@link HttpPipeline} powering this client. + * + * @return The pipeline. + */ + public HttpPipeline getHttpPipeline() { + return client.getHttpPipeline(); + } + + /** + * Gets the {@link CpkInfo} used to encrypt this blob's content on the server. + * + * @return the customer provided key used for encryption. + */ + public CpkInfo getCustomerProvidedKey() { + return client.getCustomerProvidedKey(); + } + + /** + * Gets the snapshotId for a blob resource + * + * @return A string that represents the snapshotId of the snapshot blob + */ + public String getSnapshotId() { + return this.client.getSnapshotId(); + } + + /** + * Determines if a blob is a snapshot + * + * @return A boolean that indicates if a blob is a snapshot + */ + public boolean isSnapshot() { + return this.client.isSnapshot(); + } + + /** + * Opens a blob input stream to download the blob. + *

    + * + * @return An InputStream object that represents the stream to use for reading from the blob. + * @throws StorageException If a storage service error occurred. + */ + public final BlobInputStream openInputStream() { + return openInputStream(new BlobRange(0), null); + } + + /** + * Opens a blob input stream to download the specified range of the blob. + *

    + * + * @param range {@link BlobRange} + * @param accessConditions An {@link BlobAccessConditions} object that represents the access conditions for the + * blob. + * @return An InputStream object that represents the stream to use for reading from the blob. + * @throws StorageException If a storage service error occurred. + */ + public final BlobInputStream openInputStream(BlobRange range, BlobAccessConditions accessConditions) { + return new BlobInputStream(client, range.getOffset(), range.getCount(), accessConditions); + } + + /** + * Gets if the container this client represents exists in the cloud. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.exists} + * + * @return true if the container exists, false if it doesn't + */ + public Boolean exists() { + return existsWithResponse(null, Context.NONE).getValue(); + } + + /** + * Gets if the container this client represents exists in the cloud. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.existsWithResponse#Duration-Context} + * + * @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 true if the container exists, false if it doesn't + */ + public Response existsWithResponse(Duration timeout, Context context) { + Mono> response = client.existsWithResponse(context); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Copies the data at the source URL to a blob. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.startCopyFromURL#URL} + * + *

    For more information, see the + * Azure Docs

    + * + * @param sourceURL The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * @return The copy ID for the long running operation. + */ + public String startCopyFromURL(URL sourceURL) { + return startCopyFromURLWithResponse(sourceURL, null, null, null, null, null, null, Context.NONE).getValue(); + } + + /** + * Copies the data at the source URL to a blob. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.startCopyFromURLWithResponse#URL-Metadata-AccessTier-RehydratePriority-ModifiedAccessConditions-BlobAccessConditions-Duration-Context} + * + *

    For more information, see the + * Azure Docs

    + * + * @param sourceURL The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * @param metadata {@link Metadata} + * @param tier {@link AccessTier} for the destination blob. + * @param priority {@link RehydratePriority} for rehydrating the blob. + * @param sourceModifiedAccessConditions {@link ModifiedAccessConditions} against the source. Standard HTTP Access + * conditions related to the modification of data. ETag and LastModifiedTime are used to construct conditions + * related to when the blob was changed relative to the given request. The request will fail if the specified + * condition is not satisfied. + * @param destAccessConditions {@link BlobAccessConditions} against the destination. + * @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 copy ID for the long running operation. + */ + public Response startCopyFromURLWithResponse(URL sourceURL, Metadata metadata, AccessTier tier, + RehydratePriority priority, ModifiedAccessConditions sourceModifiedAccessConditions, + BlobAccessConditions destAccessConditions, Duration timeout, Context context) { + Mono> response = client + .startCopyFromURLWithResponse(sourceURL, metadata, tier, priority, sourceModifiedAccessConditions, + destAccessConditions, context); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.abortCopyFromURL#String} + * + *

    For more information, see the + * Azure Docs

    + * + * @param copyId The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link + * BlobStartCopyFromURLHeaders} object. + */ + public void abortCopyFromURL(String copyId) { + abortCopyFromURLWithResponse(copyId, null, null, Context.NONE); + } + + /** + * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.abortCopyFromURLWithResponse#String-LeaseAccessConditions-Duration-Context} + * + *

    For more information, see the + * Azure Docs

    + * + * @param copyId The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link + * BlobStartCopyFromURLHeaders} object. + * @param leaseAccessConditions By setting lease access conditions, requests will fail if the provided lease does + * not match the active lease on the blob. + * @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 response containing status code and HTTP headers. + */ + public Response abortCopyFromURLWithResponse(String copyId, LeaseAccessConditions leaseAccessConditions, + Duration timeout, Context context) { + Mono> response = client.abortCopyFromURLWithResponse(copyId, leaseAccessConditions, + context); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.copyFromURL#URL} + * + *

    For more information, see the + * Azure Docs

    + * + * @param copySource The source URL to copy from. + * @return The copy ID for the long running operation. + */ + public String copyFromURL(URL copySource) { + return copyFromURLWithResponse(copySource, null, null, null, null, null, Context.NONE).getValue(); + } + + /** + * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.copyFromURLWithResponse#URL-Metadata-AccessTier-ModifiedAccessConditions-BlobAccessConditions-Duration-Context} + * + *

    For more information, see the + * Azure Docs

    + * + * @param copySource The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * @param metadata {@link Metadata} + * @param tier {@link AccessTier} for the destination blob. + * @param sourceModifiedAccessConditions {@link ModifiedAccessConditions} against the source. Standard HTTP Access + * conditions related to the modification of data. ETag and LastModifiedTime are used to construct conditions + * related to when the blob was changed relative to the given request. The request will fail if the specified + * condition is not satisfied. + * @param destAccessConditions {@link BlobAccessConditions} against the destination. + * @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 copy ID for the long running operation. + */ + public Response copyFromURLWithResponse(URL copySource, Metadata metadata, AccessTier tier, + ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions, + Duration timeout, Context context) { + Mono> response = client + .copyFromURLWithResponse(copySource, metadata, tier, sourceModifiedAccessConditions, destAccessConditions, + context); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Downloads the entire blob into an output stream. Uploading data must be done from the {@link BlockBlobClient}, + * {@link PageBlobClient}, or {@link AppendBlobClient}. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.download#OutputStream} + * + *

    For more information, see the + * Azure Docs

    + * + * @param stream A non-null {@link OutputStream} instance where the downloaded data will be written. + * @throws UncheckedIOException If an I/O error occurs. + */ + public void download(OutputStream stream) { + downloadWithResponse(stream, null, null, null, false, null, Context.NONE); + } + + /** + * Downloads a range of bytes from a blob into an output stream. Uploading data must be done from the {@link + * BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient}. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.downloadWithResponse#OutputStream-BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration-Context} + * + *

    For more information, see the + * Azure Docs

    + * + * @param stream A non-null {@link OutputStream} instance where the downloaded data will be written. + * @param range {@link BlobRange} + * @param options {@link ReliableDownloadOptions} + * @param accessConditions {@link BlobAccessConditions} + * @param rangeGetContentMD5 Whether the contentMD5 for the specified blob range should be returned. + * @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 response containing status code and HTTP headers. + * @throws UncheckedIOException If an I/O error occurs. + */ + public Response downloadWithResponse(OutputStream stream, BlobRange range, ReliableDownloadOptions options, + BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Duration timeout, Context context) { + Utility.assertNotNull("stream", stream); + Mono> download = client + .downloadWithResponse(range, options, accessConditions, rangeGetContentMD5, context) + .flatMapMany(res -> res.getValue() + .doOnNext(bf -> { + try { + stream.write(FluxUtil.byteBufferToArray(bf)); + } catch (IOException e) { + throw logger.logExceptionAsError(new UncheckedIOException(e)); + } + }).map(bf -> res)) + .last() + .map(response -> new SimpleResponse<>(response, null)); + + return Utility.blockWithOptionalTimeout(download, timeout); + } + + /** + * Downloads the entire blob into a file specified by the path. + * + *

    The file will be created and must not exist, if the file already exists a {@link FileAlreadyExistsException} + * will be thrown.

    + * + *

    Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link + * AppendBlobClient}.

    + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.downloadToFile#String} + * + *

    For more information, see the + * Azure Docs

    + * + * @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written. + * @throws UncheckedIOException If an I/O error occurs + */ + public void downloadToFile(String filePath) { + downloadToFile(filePath, null, null, null, null, false, null, Context.NONE); + } + + /** + * Downloads the entire blob into a file specified by the path. + * + *

    The file will be created and must not exist, if the file already exists a {@link FileAlreadyExistsException} + * will be thrown.

    + * + *

    Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link + * AppendBlobClient}.

    + * + *

    This method makes an extra HTTP call to get the length of the blob in the beginning. To avoid this extra + * call, provide the {@link BlobRange} parameter.

    + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.downloadToFile#String-BlobRange-Integer-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration-Context} + * + *

    For more information, see the + * Azure Docs

    + * + * @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written. + * @param range {@link BlobRange} + * @param blockSize the size of a chunk to download at a time, in bytes + * @param options {@link ReliableDownloadOptions} + * @param accessConditions {@link BlobAccessConditions} + * @param rangeGetContentMD5 Whether the contentMD5 for the specified blob range should be returned. + * @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. + * @throws UncheckedIOException If an I/O error occurs + */ + public void downloadToFile(String filePath, BlobRange range, Integer blockSize, ReliableDownloadOptions options, + BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Duration timeout, Context context) { + Mono download = client.downloadToFile(filePath, range, blockSize, options, accessConditions, + rangeGetContentMD5, context); + + Utility.blockWithOptionalTimeout(download, timeout); + } + + /** + * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.delete} + * + *

    For more information, see the + * Azure Docs

    + */ + public void delete() { + deleteWithResponse(null, null, null, Context.NONE); + } + + /** + * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.deleteWithResponse#DeleteSnapshotsOptionType-BlobAccessConditions-Duration-Context} + * + *

    For more information, see the + * Azure Docs

    + * + * @param deleteBlobSnapshotOptions Specifies the behavior for deleting the snapshots on this blob. {@code Include} + * will delete the base blob and all snapshots. {@code Only} will delete only the snapshots. If a snapshot is being + * deleted, you must pass null. + * @param accessConditions {@link BlobAccessConditions} + * @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 response containing status code and HTTP headers. + */ + public Response deleteWithResponse(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, + BlobAccessConditions accessConditions, Duration timeout, Context context) { + Mono> response = client + .deleteWithResponse(deleteBlobSnapshotOptions, accessConditions, context); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns the blob's metadata and properties. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.getProperties} + * + *

    For more information, see the + * Azure Docs

    + * + * @return The blob properties and metadata. + */ + public BlobProperties getProperties() { + return getPropertiesWithResponse(null, null, Context.NONE).getValue(); + } + + /** + * Returns the blob's metadata and properties. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.getPropertiesWithResponse#BlobAccessConditions-Duration-Context} + * + *

    For more information, see the + * Azure Docs

    + * + * @param accessConditions {@link BlobAccessConditions} + * @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 blob properties and metadata. + */ + public Response getPropertiesWithResponse(BlobAccessConditions accessConditions, Duration timeout, + Context context) { + Mono> response = client.getPropertiesWithResponse(accessConditions, context); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Changes a blob's HTTP header properties. if only one HTTP header is updated, the others will all be erased. In + * order to preserve existing values, they must be passed alongside the header being changed. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.setHTTPHeaders#BlobHTTPHeaders} + * + *

    For more information, see the + * Azure Docs

    + * + * @param headers {@link BlobHTTPHeaders} + */ + public void setHTTPHeaders(BlobHTTPHeaders headers) { + setHTTPHeadersWithResponse(headers, null, null, Context.NONE); + } + + /** + * Changes a blob's HTTP header properties. if only one HTTP header is updated, the others will all be erased. In + * order to preserve existing values, they must be passed alongside the header being changed. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.setHTTPHeadersWithResponse#BlobHTTPHeaders-BlobAccessConditions-Duration-Context} + * + *

    For more information, see the + * Azure Docs

    + * + * @param headers {@link BlobHTTPHeaders} + * @param accessConditions {@link BlobAccessConditions} + * @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 response containing status code and HTTP headers. + */ + public Response setHTTPHeadersWithResponse(BlobHTTPHeaders headers, BlobAccessConditions accessConditions, + Duration timeout, Context context) { + Mono> response = client + .setHTTPHeadersWithResponse(headers, accessConditions, context); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Changes a blob's metadata. The specified metadata in this method will replace existing metadata. If old values + * must be preserved, they must be downloaded and included in the call to this method. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.setMetadata#Metadata} + * + *

    For more information, see the + * Azure Docs

    + * + * @param metadata {@link Metadata} + */ + public void setMetadata(Metadata metadata) { + setMetadataWithResponse(metadata, null, null, Context.NONE); + } + + /** + * Changes a blob's metadata. The specified metadata in this method will replace existing metadata. If old values + * must be preserved, they must be downloaded and included in the call to this method. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.setMetadataWithResponse#Metadata-BlobAccessConditions-Duration-Context} + * + *

    For more information, see the + * Azure Docs

    + * + * @param metadata {@link Metadata} + * @param accessConditions {@link BlobAccessConditions} + * @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 response containing status code and HTTP headers. + */ + public Response setMetadataWithResponse(Metadata metadata, BlobAccessConditions accessConditions, + Duration timeout, Context context) { + Mono> response = client.setMetadataWithResponse(metadata, accessConditions, context); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Creates a read-only snapshot of the blob. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.createSnapshot} + * + *

    For more information, see the + * Azure Docs

    + * + * @return A response containing a {@link BlobClient} which is used to interact with the created snapshot, use + * {@link BlobClient#getSnapshotId()} to get the identifier for the snapshot. + */ + public BlobClientBase createSnapshot() { + return createSnapshotWithResponse(null, null, null, Context.NONE).getValue(); + } + + + /** + * Creates a read-only snapshot of the blob. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.createSnapshotWithResponse#Metadata-BlobAccessConditions-Duration-Context} + * + *

    For more information, see the + * Azure Docs

    + * + * @param metadata {@link Metadata} + * @param accessConditions {@link BlobAccessConditions} + * @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 response containing a {@link BlobClient} which is used to interact with the created snapshot, use + * {@link BlobClient#getSnapshotId()} to get the identifier for the snapshot. + */ + public Response createSnapshotWithResponse(Metadata metadata, BlobAccessConditions accessConditions, + Duration timeout, Context context) { + Mono> response = client + .createSnapshotWithResponse(metadata, accessConditions, context) + .map(rb -> new SimpleResponse<>(rb, new BlobClientBase(rb.getValue()))); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Sets the tier on a blob. The operation is allowed on a page blob in a premium storage account or a block blob in + * a blob storage or GPV2 account. A premium page blob's tier determines the allowed size, IOPS, and bandwidth of + * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's + * etag. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.setTier#AccessTier} + * + *

    For more information, see the + * Azure Docs

    + * + * @param tier The new tier for the blob. + */ + public void setTier(AccessTier tier) { + setTierWithResponse(tier, null, null, null, Context.NONE); + } + + /** + * Sets the tier on a blob. The operation is allowed on a page blob in a premium storage account or a block blob in + * a blob storage or GPV2 account. A premium page blob's tier determines the allowed size, IOPS, and bandwidth of + * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's + * etag. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.setTierWithResponse#AccessTier-RehydratePriority-LeaseAccessConditions-Duration-Context} + * + *

    For more information, see the + * Azure Docs

    + * + * @param tier The new tier for the blob. + * @param priority Optional priority to set for re-hydrating blobs. + * @param leaseAccessConditions By setting lease access conditions, requests will fail if the provided lease does + * not match the active lease on the blob. + * @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 response containing status code and HTTP headers. + */ + public Response setTierWithResponse(AccessTier tier, RehydratePriority priority, + LeaseAccessConditions leaseAccessConditions, Duration timeout, Context context) { + Mono> response = client.setTierWithResponse(tier, priority, leaseAccessConditions, + context); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.undelete} + * + *

    For more information, see the + * Azure Docs

    + */ + public void undelete() { + undeleteWithResponse(null, Context.NONE); + } + + /** + * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.undeleteWithResponse#Duration-Context} + * + *

    For more information, see the + * Azure Docs

    + * + * @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 response containing status code and HTTP headers. + */ + public Response undeleteWithResponse(Duration timeout, Context context) { + Mono> response = client.undeleteWithResponse(context); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns the sku name and account kind for the account. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.getAccountInfo} + * + *

    For more information, see the + * Azure Docs

    + * + * @return The sku name and account kind. + */ + public StorageAccountInfo getAccountInfo() { + return getAccountInfoWithResponse(null, Context.NONE).getValue(); + } + + /** + * Returns the sku name and account kind for the account. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.getAccountInfoWithResponse#Duration-Context} + * + *

    For more information, see the + * Azure Docs

    + * + * @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 sku name and account kind. + */ + public Response getAccountInfoWithResponse(Duration timeout, Context context) { + Mono> response = client.getAccountInfoWithResponse(context); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Generates a user delegation SAS token with the specified parameters + * + * @param userDelegationKey The {@code UserDelegationKey} user delegation key for the SAS + * @param accountName The {@code String} account name for the SAS + * @param permissions The {@code BlobSASPermission} permission for the SAS + * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS + * @return A string that represents the SAS token + */ + public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, String accountName, + BlobSASPermission permissions, OffsetDateTime expiryTime) { + return this.client.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime); + } + + /** + * Generates a user delegation SAS token with the specified parameters + * + * @param userDelegationKey The {@code UserDelegationKey} user delegation key for the SAS + * @param accountName The {@code String} account name for the SAS + * @param permissions The {@code BlobSASPermission} permission for the SAS + * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS + * @param startTime An optional {@code OffsetDateTime} start time for the SAS + * @param version An optional {@code String} version for the SAS + * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS + * @param ipRange An optional {@code IPRange} ip address range for the SAS + * @return A string that represents the SAS token + */ + public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, String accountName, + BlobSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, + SASProtocol sasProtocol, IPRange ipRange) { + return this.client.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime, + startTime, version, sasProtocol, ipRange); + } + + /** + * Generates a user delegation SAS token with the specified parameters + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.generateUserDelegationSAS#UserDelegationKey-String-BlobSASPermission-OffsetDateTime-OffsetDateTime-String-SASProtocol-IPRange-String-String-String-String-String} + * + *

    For more information, see the + * Azure + * Docs

    + * + * @param userDelegationKey The {@code UserDelegationKey} user delegation key for the SAS + * @param accountName The {@code String} account name for the SAS + * @param permissions The {@code BlobSASPermission} permission for the SAS + * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS + * @param startTime An optional {@code OffsetDateTime} start time for the SAS + * @param version An optional {@code String} version for the SAS + * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS + * @param ipRange An optional {@code IPRange} ip address range for the SAS + * @param cacheControl An optional {@code String} cache-control header for the SAS. + * @param contentDisposition An optional {@code String} content-disposition header for the SAS. + * @param contentEncoding An optional {@code String} content-encoding header for the SAS. + * @param contentLanguage An optional {@code String} content-language header for the SAS. + * @param contentType An optional {@code String} content-type header for the SAS. + * @return A string that represents the SAS token + */ + public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, String accountName, + BlobSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, + SASProtocol sasProtocol, IPRange ipRange, String cacheControl, String contentDisposition, + String contentEncoding, String contentLanguage, String contentType) { + return this.client.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime, + startTime, version, sasProtocol, ipRange, cacheControl, contentDisposition, contentEncoding, + contentLanguage, contentType); + } + + /** + * Generates a SAS token with the specified parameters + * + * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS + * @param permissions The {@code BlobSASPermission} permission for the SAS + * @return A string that represents the SAS token + */ + public String generateSAS(OffsetDateTime expiryTime, BlobSASPermission permissions) { + return this.client.generateSAS(permissions, expiryTime); + } + + /** + * Generates a SAS token with the specified parameters + * + * @param identifier The {@code String} name of the access policy on the container this SAS references if any + * @return A string that represents the SAS token + */ + public String generateSAS(String identifier) { + return this.client.generateSAS(identifier); + } + + /** + * Generates a SAS token with the specified parameters + * + * @param identifier The {@code String} name of the access policy on the container this SAS references if any + * @param permissions The {@code BlobSASPermission} permission for the SAS + * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS + * @param startTime An optional {@code OffsetDateTime} start time for the SAS + * @param version An optional {@code String} version for the SAS + * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS + * @param ipRange An optional {@code IPRange} ip address range for the SAS + * @return A string that represents the SAS token + */ + public String generateSAS(String identifier, BlobSASPermission permissions, OffsetDateTime expiryTime, + OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange) { + return this.client.generateSAS(identifier, permissions, expiryTime, startTime, version, sasProtocol, + ipRange); + } + + /** + * Generates a SAS token with the specified parameters + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.generateSAS#String-BlobSASPermission-OffsetDateTime-OffsetDateTime-String-SASProtocol-IPRange-String-String-String-String-String} + * + *

    For more information, see the + * Azure Docs

    + * + * @param identifier The {@code String} name of the access policy on the container this SAS references if any + * @param permissions The {@code BlobSASPermission} permission for the SAS + * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS + * @param startTime An optional {@code OffsetDateTime} start time for the SAS + * @param version An optional {@code String} version for the SAS + * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS + * @param ipRange An optional {@code IPRange} ip address range for the SAS + * @param cacheControl An optional {@code String} cache-control header for the SAS. + * @param contentDisposition An optional {@code String} content-disposition header for the SAS. + * @param contentEncoding An optional {@code String} content-encoding header for the SAS. + * @param contentLanguage An optional {@code String} content-language header for the SAS. + * @param contentType An optional {@code String} content-type header for the SAS. + * @return A string that represents the SAS token + */ + public String generateSAS(String identifier, BlobSASPermission permissions, OffsetDateTime expiryTime, + OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange, String cacheControl, + String contentDisposition, String contentEncoding, String contentLanguage, String contentType) { + return this.client.generateSAS(identifier, permissions, expiryTime, startTime, version, sasProtocol, + ipRange, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); + } +} diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobInputStream.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobInputStream.java similarity index 95% rename from sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobInputStream.java rename to sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobInputStream.java index 17407285b957..da54a241f9e3 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobInputStream.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobInputStream.java @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; import com.azure.core.implementation.util.FluxUtil; import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.blob.BlobProperties; import com.azure.storage.blob.models.BlobAccessConditions; import com.azure.storage.blob.models.BlobRange; import com.azure.storage.blob.models.StorageException; @@ -23,7 +24,7 @@ public final class BlobInputStream extends InputStream { /** * Holds the reference to the blob this stream is associated with. */ - private final BlobAsyncClient blobClient; + private final BlobAsyncClientBase blobClient; /** * A flag to determine if the stream is faulted, if so the last error will be thrown on next operation. @@ -88,12 +89,13 @@ public final class BlobInputStream extends InputStream { /** * Initializes a new instance of the BlobInputStream class. * - * @param blobClient A {@link BlobClient} object which represents the blob that this stream is associated with. + * @param blobClient A {@link BlobAsyncClientBase} object which represents the blob that this stream is associated + * with. * @param accessCondition An {@link BlobAccessConditions} object which represents the access conditions for the * blob. * @throws StorageException An exception representing any error which occurred during the operation. */ - BlobInputStream(final BlobAsyncClient blobClient, final BlobAccessConditions accessCondition) + BlobInputStream(final BlobAsyncClientBase blobClient, final BlobAccessConditions accessCondition) throws StorageException { this(blobClient, 0, null, accessCondition); } @@ -102,14 +104,15 @@ public final class BlobInputStream extends InputStream { * Initializes a new instance of the BlobInputStream class. Note that if {@code blobRangeOffset} is not {@code 0} or * {@code blobRangeLength} is not {@code null}, there will be no content MD5 verification. * - * @param blobClient A {@link BlobClient} object which represents the blob that this stream is associated with. + * @param blobClient A {@link BlobAsyncClientBase} object which represents the blob that this stream is associated + * with. * @param blobRangeOffset The offset of blob data to begin stream. * @param blobRangeLength How much data the stream should return after blobRangeOffset. * @param accessCondition An {@link BlobAccessConditions} object which represents the access conditions for the * blob. * @throws StorageException An exception representing any error which occurred during the operation. */ - BlobInputStream(final BlobAsyncClient blobClient, long blobRangeOffset, Long blobRangeLength, + BlobInputStream(final BlobAsyncClientBase blobClient, long blobRangeOffset, Long blobRangeLength, final BlobAccessConditions accessCondition) throws StorageException { @@ -139,10 +142,9 @@ public final class BlobInputStream extends InputStream { * * @return An int which represents an estimate of the number of bytes that can be read (or skipped * over) from this input stream without blocking, or 0 when it reaches the end of the input stream. - * @throws IOException If an I/O error occurs. */ @Override - public synchronized int available() throws IOException { + public synchronized int available() { return this.bufferSize - (int) (this.currentAbsoluteReadPosition - this.bufferStartOffset); } @@ -160,11 +162,9 @@ private synchronized void checkStreamState() throws IOException { /** * Closes this input stream and releases any system resources associated with the stream. - * - * @throws IOException If an I/O error occurs. */ @Override - public synchronized void close() throws IOException { + public synchronized void close() { this.currentBuffer = null; this.streamFaulted = true; this.lastError = new IOException(SR.STREAM_CLOSED); @@ -347,7 +347,7 @@ private synchronized int readInternal(final byte[] b, final int off, int len) th len = Math.min(len, this.readSize); final int numberOfBytesRead; - if (currentBuffer.remaining() == 0) { + if (currentBuffer == null || currentBuffer.remaining() == 0) { numberOfBytesRead = -1; } else { numberOfBytesRead = Math.min(len, this.currentBuffer.remaining()); @@ -405,7 +405,7 @@ public synchronized void reset() throws IOException { * @param n A long which represents the number of bytes to skip. */ @Override - public synchronized long skip(final long n) throws IOException { + public synchronized long skip(final long n) { if (n == 0) { return 0; } diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobOutputStream.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobOutputStream.java similarity index 95% rename from sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobOutputStream.java rename to sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobOutputStream.java index aa65162d6fbc..96aea3ba7000 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobOutputStream.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobOutputStream.java @@ -1,6 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; import com.azure.storage.blob.models.AppendBlobAccessConditions; import com.azure.storage.blob.models.AppendPositionAccessConditions; @@ -118,11 +118,9 @@ public void flush() throws IOException { *

    * * @param data A byte array which represents the data to write. - * @throws IOException If an I/O error occurs. In particular, an IOException may be thrown if the output stream has - * been closed. */ @Override - public void write(@NonNull final byte[] data) throws IOException { + public void write(@NonNull final byte[] data) { this.write(data, 0, data.length); } @@ -133,11 +131,11 @@ public void write(@NonNull final byte[] data) throws IOException { * @param data A byte array which represents the data to write. * @param offset An int which represents the start offset in the data. * @param length An int which represents the number of bytes to write. - * @throws IOException If an I/O error occurs. In particular, an IOException may be thrown if the output stream has - * been closed. + * @throws IndexOutOfBoundsException If {@code offset} or {@code length} are less than {@code 0} or {@code offset} + * plus {@code length} is greater than the {@code data} length. */ @Override - public void write(@NonNull final byte[] data, final int offset, final int length) throws IOException { + public void write(@NonNull final byte[] data, final int offset, final int length) { if (offset < 0 || length < 0 || length > data.length - offset) { throw new IndexOutOfBoundsException(); } @@ -153,11 +151,9 @@ public void write(@NonNull final byte[] data, final int offset, final int length * true is acceptable for you. * * @param byteVal An int which represents the bye value to write. - * @throws IOException If an I/O error occurs. In particular, an IOException may be thrown if the output stream has - * been closed. */ @Override - public void write(final int byteVal) throws IOException { + public void write(final int byteVal) { this.write(new byte[]{(byte) (byteVal & 0xFF)}); } @@ -282,7 +278,7 @@ private String getCurrentBlockId() { } private Mono writeBlock(Flux blockData, String blockId, long writeLength) { - LeaseAccessConditions leaseAccessConditions = (accessConditions == null) + LeaseAccessConditions leaseAccessConditions = (accessConditions == null) ? null : accessConditions.getLeaseAccessConditions(); return client.stageBlockWithResponse(blockId, blockData, writeLength, leaseAccessConditions) diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceSASQueryParameters.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobServiceSASQueryParameters.java similarity index 99% rename from sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceSASQueryParameters.java rename to sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobServiceSASQueryParameters.java index 9443376cf6f6..2c1738d1b87d 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceSASQueryParameters.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobServiceSASQueryParameters.java @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; import com.azure.storage.blob.models.UserDelegationKey; +import com.azure.storage.blob.BlobClientBuilder; import com.azure.storage.common.BaseSASQueryParameters; import com.azure.storage.common.Constants; import com.azure.storage.common.IPRange; diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceSASSignatureValues.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobServiceSASSignatureValues.java similarity index 98% rename from sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceSASSignatureValues.java rename to sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobServiceSASSignatureValues.java index 9d7eee455780..894227c90336 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceSASSignatureValues.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobServiceSASSignatureValues.java @@ -1,9 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.blob.BlobSASPermission; +import com.azure.storage.blob.ContainerSASPermission; import com.azure.storage.blob.models.UserDelegationKey; import com.azure.storage.common.Constants; import com.azure.storage.common.IPRange; @@ -33,7 +35,7 @@ * for additional samples.

    */ -final class BlobServiceSASSignatureValues { +public final class BlobServiceSASSignatureValues { private final ClientLogger logger = new ClientLogger(BlobServiceSASSignatureValues.class); private String version = Constants.HeaderConstants.TARGET_STORAGE_VERSION; @@ -69,7 +71,7 @@ final class BlobServiceSASSignatureValues { /** * Creates an object with empty values for all fields. */ - BlobServiceSASSignatureValues() { + public BlobServiceSASSignatureValues() { } /** @@ -92,7 +94,7 @@ final class BlobServiceSASSignatureValues { this.identifier = identifier; } - BlobServiceSASSignatureValues(String version, SASProtocol sasProtocol, OffsetDateTime startTime, + public BlobServiceSASSignatureValues(String version, SASProtocol sasProtocol, OffsetDateTime startTime, OffsetDateTime expiryTime, String permission, IPRange ipRange, String identifier, String cacheControl, String contentDisposition, String contentEncoding, String contentLanguage, String contentType) { if (version != null) { diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncClient.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlockBlobAsyncClient.java similarity index 90% rename from sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncClient.java rename to sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlockBlobAsyncClient.java index 83f597fbc9fb..cd6f83dc1cf9 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncClient.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlockBlobAsyncClient.java @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; import com.azure.core.annotation.ServiceClient; import com.azure.core.http.rest.Response; @@ -9,6 +9,7 @@ import com.azure.core.implementation.util.FluxUtil; import com.azure.core.util.Context; import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.blob.BlobAsyncClient; import com.azure.storage.blob.implementation.AzureBlobStorageImpl; import com.azure.storage.blob.models.AccessTier; import com.azure.storage.blob.models.BlobAccessConditions; @@ -45,18 +46,13 @@ import java.util.stream.Collectors; import static com.azure.core.implementation.util.FluxUtil.withContext; -import static com.azure.storage.blob.PostProcessor.postProcessResponse; +import static com.azure.storage.blob.implementation.PostProcessor.postProcessResponse; import static java.nio.charset.StandardCharsets.UTF_8; /** - * Client to a block blob. It may only be instantiated through a {@link BlobClientBuilder}, via the method {@link - * BlobAsyncClient#asBlockBlobAsyncClient()}, or via the method - * {@link ContainerAsyncClient#getBlockBlobAsyncClient(String)}. 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 ContainerAsyncClient}, - * and operations on the service are available on {@link BlobServiceAsyncClient}. + * Client to a block blob. It may only be instantiated through a {@link SpecializedBlobClientBuilder} or via the method + * {@link BlobAsyncClient#asBlockBlobAsyncClient()}. 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. * *

    * Please refer to the Azure @@ -68,8 +64,8 @@ * operation, until {@code .subscribe()} is called on the reactive response. You can simply convert one of these * responses to a {@link java.util.concurrent.CompletableFuture} object through {@link Mono#toFuture()}. */ -@ServiceClient(builder = BlobClientBuilder.class, isAsync = true) -public final class BlockBlobAsyncClient extends BlobAsyncClient { +@ServiceClient(builder = SpecializedBlobClientBuilder.class, isAsync = true) +public final class BlockBlobAsyncClient extends BlobAsyncClientBase { private final ClientLogger logger = new ClientLogger(BlockBlobAsyncClient.class); static final int BLOB_DEFAULT_UPLOAD_BLOCK_SIZE = 4 * Constants.MB; @@ -91,7 +87,7 @@ public final class BlockBlobAsyncClient extends BlobAsyncClient { public static final int MAX_BLOCKS = 50000; /** - * Package-private constructor for use by {@link BlobClientBuilder}. + * Package-private constructor for use by {@link SpecializedBlobClientBuilder}. * * @param azureBlobStorage the API client for blob storage */ @@ -112,7 +108,7 @@ public final class BlockBlobAsyncClient extends BlobAsyncClient { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobAsyncClient.upload#Flux-long} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobAsyncClient.upload#Flux-long} * * @param data The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled * (the default). In other words, the Flux must produce the same data each time it is subscribed to. @@ -138,7 +134,7 @@ public Mono upload(Flux data, long length) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobAsyncClient.uploadWithResponse#Flux-long-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobAsyncClient.uploadWithResponse#Flux-long-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions} * * @param data The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled * (the default). In other words, the Flux must produce the same data each time it is subscribed to. @@ -162,8 +158,8 @@ Mono> uploadWithResponse(Flux data, long len accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; return postProcessResponse(this.azureBlobStorage.blockBlobs().uploadWithRestResponseAsync(null, - null, data, length, null, metadata, tier, null, headers, accessConditions.getLeaseAccessConditions(), cpk, - accessConditions.getModifiedAccessConditions(), context)) + null, data, length, null, metadata, tier, null, headers, accessConditions.getLeaseAccessConditions(), + getCustomerProvidedKey(), accessConditions.getModifiedAccessConditions(), context)) .map(rb -> new SimpleResponse<>(rb, new BlockBlobItem(rb.getDeserializedHeaders()))); } @@ -191,7 +187,7 @@ Mono> uploadWithResponse(Flux data, long len * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobAsyncClient.upload#Flux-int-int} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobAsyncClient.upload#Flux-int-int} * * @param data The data to write to the blob. Unlike other upload methods, this method does not require that the * {@code Flux} be replayable. In other words, it does not have to support multiple subscribers and is not expected @@ -215,8 +211,9 @@ public Mono upload(Flux data, int blockSize, int numB * the existing blob is overwritten with the new content. To perform a partial update of a block blob's, use {@link * BlockBlobAsyncClient#stageBlock(String, Flux, long) stageBlock} and * {@link BlockBlobAsyncClient#commitBlockList(List)}, which this method uses internally. For more information, - * see the
    Azure Docs for Put Block and - * the Azure Docs for Put Block List. + * see the Azure + * Docs for Put Block and the Azure + * Docs for Put Block List. *

    * The data passed need not support multiple subscriptions/be replayable as is required in other upload methods when * retries are enabled, and the length of the data need not be known in advance. Therefore, this method should @@ -232,7 +229,7 @@ public Mono upload(Flux data, int blockSize, int numB * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobAsyncClient.uploadWithResponse#Flux-int-int-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobAsyncClient.uploadWithResponse#Flux-int-int-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions} * * @param data The data to write to the blob. Unlike other upload methods, this method does not require that the * {@code Flux} be replayable. In other words, it does not have to support multiple subscribers and is not expected @@ -320,7 +317,7 @@ as we can guarantee we only need at most two buffers for any call to write (two * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobAsyncClient.uploadFromFile#String} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobAsyncClient.uploadFromFile#String} * * @param filePath Path to the upload file * @return An empty response @@ -335,7 +332,7 @@ public Mono uploadFromFile(String filePath) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobAsyncClient.uploadFromFile#String-Integer-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobAsyncClient.uploadFromFile#String-Integer-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions} * * @param filePath Path to the upload file * @param blockSize Size of the blocks to upload @@ -349,14 +346,19 @@ public Mono uploadFromFile(String filePath) { */ public Mono uploadFromFile(String filePath, Integer blockSize, BlobHTTPHeaders headers, Metadata metadata, AccessTier tier, BlobAccessConditions accessConditions) { - if (blockSize < 0 || blockSize > BLOB_MAX_UPLOAD_BLOCK_SIZE) { + int sliceBlockSize; + if (blockSize == null) { + sliceBlockSize = BLOB_DEFAULT_UPLOAD_BLOCK_SIZE; + } else if (blockSize < 0 || blockSize > BLOB_MAX_UPLOAD_BLOCK_SIZE) { throw logger.logExceptionAsError(new IllegalArgumentException("Block size should not exceed 100MB")); + } else { + sliceBlockSize = blockSize; } return Mono.using(() -> uploadFileResourceSupplier(filePath), channel -> { final SortedMap blockIds = new TreeMap<>(); - return Flux.fromIterable(sliceFile(filePath, blockSize)) + return Flux.fromIterable(sliceFile(filePath, sliceBlockSize)) .doOnNext(chunk -> blockIds.put(chunk.getOffset(), getBlockID())) .flatMap(chunk -> { String blockId = blockIds.get(chunk.getOffset()); @@ -420,11 +422,6 @@ private List sliceFile(String path, Integer blockSize) { * Azure Docs. *

    * 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

    - * - * {@codesnippet com.azure.storage.blob.BlockBlobAsyncClient.stageBlock#String-Flux-long} * * @param base64BlockID A Base64 encoded {@code String} that specifies the ID for this block. Note that all block * ids for a given blob must be the same length. @@ -433,6 +430,11 @@ private List sliceFile(String path, Integer blockSize) { * @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 A reactive response signalling completion. + * @code Flux} must produce the same data each time it is subscribed to. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobAsyncClient.stageBlock#String-Flux-long} */ public Mono stageBlock(String base64BlockID, Flux data, long length) { return stageBlockWithResponse(base64BlockID, data, length, null).flatMap(FluxUtil::toMono); @@ -448,7 +450,7 @@ public Mono stageBlock(String base64BlockID, Flux data, long l * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobAsyncClient.stageBlockWithResponse#String-Flux-long-LeaseAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobAsyncClient.stageBlockWithResponse#String-Flux-long-LeaseAccessConditions} * * @param base64BlockID A Base64 encoded {@code String} that specifies the ID for this block. Note that all block * ids for a given blob must be the same length. @@ -468,8 +470,9 @@ public Mono> stageBlockWithResponse(String base64BlockID, Flux> stageBlockWithResponse(String base64BlockID, Flux data, long length, LeaseAccessConditions leaseAccessConditions, Context context) { - return postProcessResponse(this.azureBlobStorage.blockBlobs().stageBlockWithRestResponseAsync(null, - null, base64BlockID, length, data, null, null, null, null, leaseAccessConditions, cpk, context)) + return postProcessResponse(this.azureBlobStorage.blockBlobs().stageBlockWithRestResponseAsync(null, null, + base64BlockID, length, data, null, null, null, null, leaseAccessConditions, getCustomerProvidedKey(), + context)) .map(response -> new SimpleResponse<>(response, null)); } @@ -480,7 +483,7 @@ Mono> stageBlockWithResponse(String base64BlockID, FluxCode Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobAsyncClient.stageBlockFromURL#String-URL-BlobRange} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobAsyncClient.stageBlockFromURL#String-URL-BlobRange} * * @param base64BlockID A Base64 encoded {@code String} that specifies the ID for this block. Note that all block * ids for a given blob must be the same length. @@ -503,7 +506,7 @@ public Mono stageBlockFromURL(String base64BlockID, URL sourceURL, BlobRan * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobAsyncClient.stageBlockFromURLWithResponse#String-URL-BlobRange-byte-LeaseAccessConditions-SourceModifiedAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobAsyncClient.stageBlockFromURLWithResponse#String-URL-BlobRange-byte-LeaseAccessConditions-SourceModifiedAccessConditions} * * @param base64BlockID A Base64 encoded {@code String} that specifies the ID for this block. Note that all block * ids for a given blob must be the same length. @@ -534,7 +537,7 @@ Mono> stageBlockFromURLWithResponse(String base64BlockID, URL sou return postProcessResponse( this.azureBlobStorage.blockBlobs().stageBlockFromURLWithRestResponseAsync(null, null, base64BlockID, 0, sourceURL, sourceRange.toHeaderValue(), sourceContentMD5, null, null, - null, cpk, leaseAccessConditions, sourceModifiedAccessConditions, context)) + null, getCustomerProvidedKey(), leaseAccessConditions, sourceModifiedAccessConditions, context)) .map(response -> new SimpleResponse<>(response, null)); } @@ -545,7 +548,7 @@ Mono> stageBlockFromURLWithResponse(String base64BlockID, URL sou * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobAsyncClient.listBlocks#BlockListType} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobAsyncClient.listBlocks#BlockListType} * * @param listType Specifies which type of blocks to return. * @return A reactive response containing the list of blocks. @@ -561,7 +564,7 @@ public Mono listBlocks(BlockListType listType) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobAsyncClient.listBlocksWithResponse#BlockListType-LeaseAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobAsyncClient.listBlocksWithResponse#BlockListType-LeaseAccessConditions} * * @param listType Specifies which type of blocks to return. * @param leaseAccessConditions By setting lease access conditions, requests will fail if the provided lease does @@ -578,7 +581,7 @@ Mono> listBlocksWithResponse(BlockListType listType, LeaseAccessConditions leaseAccessConditions, Context context) { return postProcessResponse(this.azureBlobStorage.blockBlobs().getBlockListWithRestResponseAsync(null, - null, listType, snapshot, null, null, leaseAccessConditions, context)) + null, listType, getSnapshotId(), null, null, leaseAccessConditions, context)) .map(response -> new SimpleResponse<>(response, response.getValue())); } @@ -592,7 +595,7 @@ Mono> listBlocksWithResponse(BlockListType listType, * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobAsyncClient.commitBlockList#List} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobAsyncClient.commitBlockList#List} * * @param base64BlockIDs A list of base64 encode {@code String}s that specifies the block IDs to be committed. * @return A reactive response containing the information of the block blob. @@ -611,7 +614,7 @@ public Mono commitBlockList(List base64BlockIDs) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobAsyncClient.commitBlockListWithResponse#List-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobAsyncClient.commitBlockListWithResponse#List-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions} * * @param base64BlockIDs A list of base64 encode {@code String}s that specifies the block IDs to be committed. * @param headers {@link BlobHTTPHeaders} @@ -634,8 +637,8 @@ Mono> commitBlockListWithResponse(List base64Blo return postProcessResponse(this.azureBlobStorage.blockBlobs().commitBlockListWithRestResponseAsync( null, null, new BlockLookupList().setLatest(base64BlockIDs), null, null, null, metadata, tier, null, - headers, accessConditions.getLeaseAccessConditions(), cpk, accessConditions.getModifiedAccessConditions(), - context)) + headers, accessConditions.getLeaseAccessConditions(), getCustomerProvidedKey(), + accessConditions.getModifiedAccessConditions(), context)) .map(rb -> new SimpleResponse<>(rb, new BlockBlobItem(rb.getDeserializedHeaders()))); } } diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlockBlobClient.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlockBlobClient.java similarity index 88% rename from sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlockBlobClient.java rename to sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlockBlobClient.java index fccaadd7b5d6..c9638f539109 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlockBlobClient.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlockBlobClient.java @@ -1,12 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; +import com.azure.core.annotation.ServiceClient; import com.azure.core.exception.UnexpectedLengthException; import com.azure.core.http.rest.Response; -import com.azure.core.annotation.ServiceClient; import com.azure.core.util.Context; +import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.blob.BlobClient; import com.azure.storage.blob.models.AccessTier; import com.azure.storage.blob.models.BlobAccessConditions; import com.azure.storage.blob.models.BlobHTTPHeaders; @@ -33,21 +35,18 @@ import java.util.Objects; /** - * Client to a block blob. It may only be instantiated through a {@link BlobClientBuilder}, via the method {@link - * BlobClient#asBlockBlobClient()}, or via the method {@link ContainerClient#getBlockBlobClient(String)}. 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 ContainerClient}, and - * operations on the service are available on {@link BlobServiceClient}. + * Client to a block blob. It may only be instantiated through a {@link SpecializedBlobClientBuilder} or via the method + * {@link BlobClient#asBlockBlobClient()}. 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. * *

    * Please refer to the Azure * Docs for more information. */ -@ServiceClient(builder = BlobClientBuilder.class) -public final class BlockBlobClient extends BlobClient { +@ServiceClient(builder = SpecializedBlobClientBuilder.class) +public final class BlockBlobClient extends BlobClientBase { + private final ClientLogger logger = new ClientLogger(BlockBlobClient.class); + private final BlockBlobAsyncClient blockBlobAsyncClient; /** @@ -66,7 +65,7 @@ public final class BlockBlobClient extends BlobClient { public static final int MAX_BLOCKS = BlockBlobAsyncClient.MAX_BLOCKS; /** - * Package-private constructor for use by {@link BlobClientBuilder}. + * Package-private constructor for use by {@link SpecializedBlobClientBuilder}. * * @param blockBlobAsyncClient the async block blob client */ @@ -108,7 +107,7 @@ public BlobOutputStream getBlobOutputStream(BlobAccessConditions accessCondition * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobClient.upload#InputStream-long} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobClient.upload#InputStream-long} * * @param data The data to write to the blob. * @param length The exact length of the data. It is important that this value match precisely the length of the @@ -129,7 +128,7 @@ public BlockBlobItem upload(InputStream data, long length) throws IOException { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobClient.uploadWithResponse#InputStream-long-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobClient.uploadWithResponse#InputStream-long-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration-Context} * * @param data The data to write to the blob. * @param length The exact length of the data. It is important that this value match precisely the length of the @@ -143,11 +142,11 @@ public BlockBlobItem upload(InputStream data, long length) throws IOException { * @return The information of the uploaded block blob. * @throws UnexpectedLengthException when the length of data does not match the input {@code length}. * @throws NullPointerException if the input data is null. - * @throws IOException If an I/O error occurs + * @throws UncheckedIOException If an I/O error occurs */ public Response uploadWithResponse(InputStream data, long length, BlobHTTPHeaders headers, Metadata metadata, AccessTier tier, BlobAccessConditions accessConditions, Duration timeout, - Context context) throws IOException { + Context context) { Objects.requireNonNull(data); Flux fbb = Utility.convertStreamToByteBuffer(data, length, BlockBlobAsyncClient.BLOB_DEFAULT_UPLOAD_BLOCK_SIZE); @@ -158,7 +157,7 @@ public Response uploadWithResponse(InputStream data, long length, try { return Utility.blockWithOptionalTimeout(upload, timeout); } catch (UncheckedIOException e) { - throw e.getCause(); + throw logger.logExceptionAsError(e); } } @@ -167,7 +166,7 @@ public Response uploadWithResponse(InputStream data, long length, * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobClient.uploadFromFile#String} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobClient.uploadFromFile#String} * * @param filePath Path of the file to upload * @throws IOException If an I/O error occurs @@ -181,7 +180,7 @@ public void uploadFromFile(String filePath) throws IOException { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobClient.uploadFromFile#String-Integer-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobClient.uploadFromFile#String-Integer-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration} * * @param filePath Path of the file to upload * @param blockSize Size of the blocks to upload @@ -190,17 +189,17 @@ public void uploadFromFile(String filePath) throws IOException { * @param tier {@link AccessTier} for the uploaded blob * @param accessConditions {@link BlobAccessConditions} * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. - * @throws IOException If an I/O error occurs + * @throws UncheckedIOException If an I/O error occurs */ public void uploadFromFile(String filePath, Integer blockSize, BlobHTTPHeaders headers, Metadata metadata, - AccessTier tier, BlobAccessConditions accessConditions, Duration timeout) throws IOException { + AccessTier tier, BlobAccessConditions accessConditions, Duration timeout) { Mono upload = this.blockBlobAsyncClient.uploadFromFile( filePath, blockSize, headers, metadata, tier, accessConditions); try { Utility.blockWithOptionalTimeout(upload, timeout); } catch (UncheckedIOException e) { - throw e.getCause(); + throw logger.logExceptionAsError(e); } } @@ -211,7 +210,7 @@ public void uploadFromFile(String filePath, Integer blockSize, BlobHTTPHeaders h * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobClient.stageBlock#String-InputStream-long} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobClient.stageBlock#String-InputStream-long} * * @param base64BlockID A Base64 encoded {@code String} that specifies the ID for this block. Note that all block * ids for a given blob must be the same length. @@ -230,7 +229,7 @@ public void stageBlock(String base64BlockID, InputStream data, long length) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobClient.stageBlockWithResponse#String-InputStream-long-LeaseAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobClient.stageBlockWithResponse#String-InputStream-long-LeaseAccessConditions-Duration-Context} * * @param base64BlockID A Base64 encoded {@code String} that specifies the ID for this block. Note that all block * ids for a given blob must be the same length. @@ -263,7 +262,7 @@ public Response stageBlockWithResponse(String base64BlockID, InputStream d * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobClient.stageBlockFromURL#String-URL-BlobRange} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobClient.stageBlockFromURL#String-URL-BlobRange} * * @param base64BlockID A Base64 encoded {@code String} that specifies the ID for this block. Note that all block * ids for a given blob must be the same length. @@ -284,7 +283,7 @@ public void stageBlockFromURL(String base64BlockID, URL sourceURL, BlobRange sou * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobClient.stageBlockFromURLWithResponse#String-URL-BlobRange-byte-LeaseAccessConditions-SourceModifiedAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobClient.stageBlockFromURLWithResponse#String-URL-BlobRange-byte-LeaseAccessConditions-SourceModifiedAccessConditions-Duration-Context} * * @param base64BlockID A Base64 encoded {@code String} that specifies the ID for this block. Note that all block * ids for a given blob must be the same length. @@ -317,7 +316,7 @@ public Response stageBlockFromURLWithResponse(String base64BlockID, URL so * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobClient.listBlocks#BlockListType} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobClient.listBlocks#BlockListType} * * @param listType Specifies which type of blocks to return. * @return The list of blocks. @@ -333,7 +332,7 @@ public BlockList listBlocks(BlockListType listType) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobClient.listBlocksWithResponse#BlockListType-LeaseAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobClient.listBlocksWithResponse#BlockListType-LeaseAccessConditions-Duration-Context} * * @param listType Specifies which type of blocks to return. * @param leaseAccessConditions By setting lease access conditions, requests will fail if the provided lease does @@ -360,7 +359,7 @@ public Response listBlocksWithResponse(BlockListType listType, * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobClient.commitBlockList#List} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobClient.commitBlockList#List} * * @param base64BlockIDs A list of base64 encode {@code String}s that specifies the block IDs to be committed. * @return The information of the block blob. @@ -379,7 +378,7 @@ public BlockBlobItem commitBlockList(List base64BlockIDs) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.BlockBlobClient.commitBlockListWithResponse#List-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.BlockBlobClient.commitBlockListWithResponse#List-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration-Context} * * @param base64BlockIDs A list of base64 encode {@code String}s that specifies the block IDs to be committed. * @param headers {@link BlobHTTPHeaders} diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/DownloadAsyncResponse.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/DownloadAsyncResponse.java similarity index 97% rename from sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/DownloadAsyncResponse.java rename to sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/DownloadAsyncResponse.java index 472ae3124b42..c729ffba4f87 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/DownloadAsyncResponse.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/DownloadAsyncResponse.java @@ -1,13 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; import com.azure.core.http.rest.ResponseBase; +import com.azure.storage.blob.HTTPGetterInfo; import com.azure.storage.blob.models.BlobAccessConditions; import com.azure.storage.blob.models.BlobDownloadHeaders; import com.azure.storage.blob.models.BlobRange; import com.azure.storage.blob.models.ReliableDownloadOptions; +import com.azure.storage.blob.BlobAsyncClient; import com.azure.storage.common.Utility; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/LeaseClientBuilder.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/LeaseClientBuilder.java index ff5a3a3e63ab..e9a25e835ef4 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/LeaseClientBuilder.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/LeaseClientBuilder.java @@ -72,7 +72,7 @@ public LeaseAsyncClient buildAsyncClient() { * @return the updated LeaseClientBuilder object * @throws NullPointerException If {@code blobClient} is {@code null}. */ - public LeaseClientBuilder blobClient(BlobClient blobClient) { + public LeaseClientBuilder blobClient(BlobClientBase blobClient) { Objects.requireNonNull(blobClient); this.pipeline = blobClient.getHttpPipeline(); this.url = blobClient.getBlobUrl(); @@ -88,7 +88,7 @@ public LeaseClientBuilder blobClient(BlobClient blobClient) { * @return the updated LeaseClientBuilder object * @throws NullPointerException If {@code blobAsyncClient} is {@code null}. */ - public LeaseClientBuilder blobAsyncClient(BlobAsyncClient blobAsyncClient) { + public LeaseClientBuilder blobAsyncClient(BlobAsyncClientBase blobAsyncClient) { Objects.requireNonNull(blobAsyncClient); this.pipeline = blobAsyncClient.getHttpPipeline(); this.url = blobAsyncClient.getBlobUrl(); diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/PageBlobAsyncClient.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/PageBlobAsyncClient.java similarity index 90% rename from sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/PageBlobAsyncClient.java rename to sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/PageBlobAsyncClient.java index 31e4b034d0d9..168ca1968aa5 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/PageBlobAsyncClient.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/PageBlobAsyncClient.java @@ -1,15 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; +import com.azure.core.annotation.ServiceClient; import com.azure.core.http.rest.Response; import com.azure.core.http.rest.SimpleResponse; -import com.azure.core.annotation.ServiceClient; import com.azure.core.implementation.http.UrlBuilder; import com.azure.core.implementation.util.FluxUtil; import com.azure.core.util.Context; import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.blob.BlobAsyncClient; import com.azure.storage.blob.implementation.AzureBlobStorageImpl; import com.azure.storage.blob.models.BlobAccessConditions; import com.azure.storage.blob.models.BlobHTTPHeaders; @@ -33,17 +34,12 @@ import java.nio.ByteBuffer; import static com.azure.core.implementation.util.FluxUtil.withContext; -import static com.azure.storage.blob.PostProcessor.postProcessResponse; +import static com.azure.storage.blob.implementation.PostProcessor.postProcessResponse; /** - * Client to a page blob. It may only be instantiated through a {@link BlobClientBuilder}, via the method {@link - * BlobAsyncClient#asPageBlobAsyncClient()}, or via the method - * {@link ContainerAsyncClient#getPageBlobAsyncClient(String)}. 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 ContainerAsyncClient}, - * and operations on the service are available on {@link BlobServiceAsyncClient}. + * Client to a page blob. It may only be instantiated through a {@link SpecializedBlobClientBuilder} or via the method + * {@link BlobAsyncClient#asPageBlobAsyncClient()}. 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. * *

    * Please refer to the Azure @@ -55,8 +51,8 @@ * operation, until {@code .subscribe()} is called on the reactive response. You can simply convert one of these * responses to a {@link java.util.concurrent.CompletableFuture} object through {@link Mono#toFuture()}. */ -@ServiceClient(builder = BlobClientBuilder.class, isAsync = true) -public final class PageBlobAsyncClient extends BlobAsyncClient { +@ServiceClient(builder = SpecializedBlobClientBuilder.class, isAsync = true) +public final class PageBlobAsyncClient extends BlobAsyncClientBase { /** * Indicates the number of bytes in a page. */ @@ -70,7 +66,7 @@ public final class PageBlobAsyncClient extends BlobAsyncClient { private final ClientLogger logger = new ClientLogger(PageBlobAsyncClient.class); /** - * Package-private constructor for use by {@link BlobClientBuilder}. + * Package-private constructor for use by {@link SpecializedBlobClientBuilder}. * * @param azureBlobStorage the API client for blob storage */ @@ -102,7 +98,7 @@ public Mono create(long size) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.createWithResponse#long-Long-BlobHTTPHeaders-Metadata-BlobAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.createWithResponse#long-Long-BlobHTTPHeaders-Metadata-BlobAccessConditions} * * @param size Specifies the maximum size for the page blob, up to 8 TB. The page blob size must be aligned to a * 512-byte boundary. @@ -141,7 +137,7 @@ Mono> createWithResponse(long size, Long sequenceNumber, return postProcessResponse(this.azureBlobStorage.pageBlobs().createWithRestResponseAsync(null, null, 0, size, null, metadata, sequenceNumber, null, headers, accessConditions.getLeaseAccessConditions(), - cpk, accessConditions.getModifiedAccessConditions(), context)) + getCustomerProvidedKey(), accessConditions.getModifiedAccessConditions(), context)) .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.getDeserializedHeaders()))); } @@ -155,7 +151,7 @@ Mono> createWithResponse(long size, Long sequenceNumber, * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.uploadPages#PageRange-Flux} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.uploadPages#PageRange-Flux} * * @param pageRange A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start * offset must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges @@ -178,7 +174,7 @@ public Mono uploadPages(PageRange pageRange, Flux body * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.uploadPagesWithResponse#PageRange-Flux-PageBlobAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.uploadPagesWithResponse#PageRange-Flux-PageBlobAccessConditions} * * @param pageRange A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start * offset must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges @@ -209,7 +205,7 @@ Mono> uploadPagesWithResponse(PageRange pageRange, Flux new SimpleResponse<>(rb, new PageBlobItem(rb.getDeserializedHeaders()))); @@ -222,7 +218,7 @@ Mono> uploadPagesWithResponse(PageRange pageRange, FluxCode Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.uploadPagesFromURL#PageRange-URL-Long} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.uploadPagesFromURL#PageRange-URL-Long} * * @param range A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start * offset must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges @@ -247,7 +243,7 @@ public Mono uploadPagesFromURL(PageRange range, URL sourceURL, Lon * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.uploadPagesFromURLWithResponse#PageRange-URL-Long-byte-PageBlobAccessConditions-SourceModifiedAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.uploadPagesFromURLWithResponse#PageRange-URL-Long-byte-PageBlobAccessConditions-SourceModifiedAccessConditions} * * @param range The destination {@link PageRange} range. Given that pages must be aligned with 512-byte boundaries, * the start offset must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte @@ -292,8 +288,8 @@ Mono> uploadPagesFromURLWithResponse(PageRange range, URL destAccessConditions = destAccessConditions == null ? new PageBlobAccessConditions() : destAccessConditions; - return postProcessResponse(this.azureBlobStorage.pageBlobs().uploadPagesFromURLWithRestResponseAsync( - null, null, sourceURL, sourceRangeString, 0, rangeString, sourceContentMD5, null, null, null, cpk, + return postProcessResponse(this.azureBlobStorage.pageBlobs().uploadPagesFromURLWithRestResponseAsync(null, null, + sourceURL, sourceRangeString, 0, rangeString, sourceContentMD5, null, null, null, getCustomerProvidedKey(), destAccessConditions.getLeaseAccessConditions(), destAccessConditions.getSequenceNumberAccessConditions(), destAccessConditions.getModifiedAccessConditions(), sourceAccessConditions, context)) .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.getDeserializedHeaders()))); @@ -305,7 +301,7 @@ Mono> uploadPagesFromURLWithResponse(PageRange range, URL * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.clearPages#PageRange} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.clearPages#PageRange} * * @param pageRange A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start * offset must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges @@ -322,7 +318,7 @@ public Mono clearPages(PageRange pageRange) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.clearPagesWithResponse#PageRange-PageBlobAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.clearPagesWithResponse#PageRange-PageBlobAccessConditions} * * @param pageRange A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start * offset must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges @@ -350,7 +346,7 @@ Mono> clearPagesWithResponse(PageRange pageRange, return postProcessResponse(this.azureBlobStorage.pageBlobs().clearPagesWithRestResponseAsync(null, null, 0, null, pageRangeStr, null, - pageBlobAccessConditions.getLeaseAccessConditions(), cpk, + pageBlobAccessConditions.getLeaseAccessConditions(), getCustomerProvidedKey(), pageBlobAccessConditions.getSequenceNumberAccessConditions(), pageBlobAccessConditions.getModifiedAccessConditions(), context)) .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.getDeserializedHeaders()))); @@ -362,7 +358,7 @@ Mono> clearPagesWithResponse(PageRange pageRange, * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.getPageRanges#BlobRange} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.getPageRanges#BlobRange} * * @param blobRange {@link BlobRange} * @return A reactive response containing the information of the cleared pages. @@ -377,7 +373,7 @@ public Mono getPageRanges(BlobRange blobRange) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.getPageRangesWithResponse#BlobRange-BlobAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.getPageRangesWithResponse#BlobRange-BlobAccessConditions} * * @param blobRange {@link BlobRange} * @param accessConditions {@link BlobAccessConditions} @@ -394,7 +390,7 @@ Mono> getPageRangesWithResponse(BlobRange blobRange, BlobAcce accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; return postProcessResponse(this.azureBlobStorage.pageBlobs().getPageRangesWithRestResponseAsync( - null, null, snapshot, null, blobRange.toHeaderValue(), + null, null, getSnapshotId(), null, blobRange.toHeaderValue(), null, accessConditions.getLeaseAccessConditions(), accessConditions.getModifiedAccessConditions(), context)).map(response -> new SimpleResponse<>(response, response.getValue())); } @@ -406,7 +402,7 @@ Mono> getPageRangesWithResponse(BlobRange blobRange, BlobAcce * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.getPageRangesDiff#BlobRange-String} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.getPageRangesDiff#BlobRange-String} * * @param blobRange {@link BlobRange} * @param prevSnapshot Specifies that the response will contain only pages that were changed between target blob and @@ -425,7 +421,7 @@ public Mono getPageRangesDiff(BlobRange blobRange, String prevSnapshot * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.getPageRangesDiffWithResponse#BlobRange-String-BlobAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.getPageRangesDiffWithResponse#BlobRange-String-BlobAccessConditions} * * @param blobRange {@link BlobRange} * @param prevSnapshot Specifies that the response will contain only pages that were changed between target blob and @@ -451,7 +447,7 @@ Mono> getPageRangesDiffWithResponse(BlobRange blobRange, Stri } return postProcessResponse(this.azureBlobStorage.pageBlobs().getPageRangesDiffWithRestResponseAsync( - null, null, snapshot, null, prevSnapshot, + null, null, getSnapshotId(), null, prevSnapshot, blobRange.toHeaderValue(), null, accessConditions.getLeaseAccessConditions(), accessConditions.getModifiedAccessConditions(), context)) .map(response -> new SimpleResponse<>(response, response.getValue())); @@ -463,7 +459,7 @@ Mono> getPageRangesDiffWithResponse(BlobRange blobRange, Stri * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.resize#long} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.resize#long} * * @param size Resizes a page blob to the specified size. If the specified value is less than the current size of * the blob, then all pages above the specified value are cleared. @@ -479,7 +475,7 @@ public Mono resize(long size) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.resizeWithResponse#long-BlobAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.resizeWithResponse#long-BlobAccessConditions} * * @param size Resizes a page blob to the specified size. If the specified value is less than the current size of * the blob, then all pages above the specified value are cleared. @@ -501,7 +497,7 @@ Mono> resizeWithResponse(long size, BlobAccessConditions accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; return postProcessResponse(this.azureBlobStorage.pageBlobs().resizeWithRestResponseAsync(null, - null, size, null, null, accessConditions.getLeaseAccessConditions(), cpk, + null, size, null, null, accessConditions.getLeaseAccessConditions(), getCustomerProvidedKey(), accessConditions.getModifiedAccessConditions(), context)) .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.getDeserializedHeaders()))); } @@ -512,7 +508,7 @@ Mono> resizeWithResponse(long size, BlobAccessConditions * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.updateSequenceNumber#SequenceNumberActionType-Long} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.updateSequenceNumber#SequenceNumberActionType-Long} * * @param action Indicates how the service should modify the blob's sequence number. * @param sequenceNumber The blob's sequence number. The sequence number is a user-controlled property that you can @@ -529,7 +525,7 @@ public Mono updateSequenceNumber(SequenceNumberActionType action, * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.updateSequenceNumberWithResponse#SequenceNumberActionType-Long-BlobAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.updateSequenceNumberWithResponse#SequenceNumberActionType-Long-BlobAccessConditions} * * @param action Indicates how the service should modify the blob's sequence number. * @param sequenceNumber The blob's sequence number. The sequence number is a user-controlled property that you can @@ -572,7 +568,7 @@ Mono> updateSequenceNumberWithResponse(SequenceNumberActi * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.copyIncremental#URL-String} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.copyIncremental#URL-String} * * @param source The source page blob. * @param snapshot The snapshot on the copy source. @@ -592,7 +588,7 @@ public Mono copyIncremental(URL source, String snapshot) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobAsyncClient.copyIncrementalWithResponse#URL-String-ModifiedAccessConditions} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobAsyncClient.copyIncrementalWithResponse#URL-String-ModifiedAccessConditions} * * @param source The source page blob. * @param snapshot The snapshot on the copy source. @@ -600,7 +596,7 @@ public Mono copyIncremental(URL source, String snapshot) { * LastModifiedTime are used to construct conditions related to when the blob was changed relative to the given * request. The request will fail if the specified condition is not satisfied. * @return A reactive response emitting the copy status. - * @throws Error If {@code source} and {@code snapshot} form a malformed URL. + * @throws IllegalStateException If {@code source} and {@code snapshot} form a malformed URL. */ public Mono> copyIncrementalWithResponse(URL source, String snapshot, ModifiedAccessConditions modifiedAccessConditions) { @@ -615,7 +611,7 @@ Mono> copyIncrementalWithResponse(URL source, String sn source = builder.toURL(); } catch (MalformedURLException e) { // We are parsing a valid url and adding a query parameter. If this fails, we can't recover. - throw new Error(e); + throw logger.logExceptionAsError(new IllegalStateException(e)); } return postProcessResponse(this.azureBlobStorage.pageBlobs().copyIncrementalWithRestResponseAsync( null, null, source, null, null, modifiedAccessConditions, context)) diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/PageBlobClient.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/PageBlobClient.java similarity index 90% rename from sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/PageBlobClient.java rename to sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/PageBlobClient.java index 8da5ba178a27..379602ae305d 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/PageBlobClient.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/PageBlobClient.java @@ -1,12 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; +import com.azure.core.annotation.ServiceClient; import com.azure.core.exception.UnexpectedLengthException; import com.azure.core.http.rest.Response; -import com.azure.core.annotation.ServiceClient; import com.azure.core.util.Context; +import com.azure.storage.blob.BlobClient; import com.azure.storage.blob.models.BlobAccessConditions; import com.azure.storage.blob.models.BlobHTTPHeaders; import com.azure.storage.blob.models.BlobRange; @@ -32,21 +33,16 @@ import java.util.Objects; /** - * Client to a page blob. It may only be instantiated through a {@link BlobClientBuilder}, via the method {@link - * BlobClient#asPageBlobClient()}, or via the method {@link ContainerClient#getPageBlobClient(String)}. 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 ContainerClient}, and - * operations on the service are available on {@link BlobServiceClient}. + * Client to a page blob. It may only be instantiated through a {@link SpecializedBlobClientBuilder} or via the method + * {@link BlobClient#asPageBlobClient()}. 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. * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.createWithResponse#long-Long-BlobHTTPHeaders-Metadata-BlobAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.createWithResponse#long-Long-BlobHTTPHeaders-Metadata-BlobAccessConditions-Duration-Context} * * @param size Specifies the maximum size for the page blob, up to 8 TB. The page blob size must be aligned to a * 512-byte boundary. @@ -152,7 +148,7 @@ public Response createWithResponse(long size, Long sequenceNumber, * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.uploadPages#PageRange-InputStream} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.uploadPages#PageRange-InputStream} * * @param pageRange A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start * offset must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges @@ -174,7 +170,7 @@ public PageBlobItem uploadPages(PageRange pageRange, InputStream body) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.uploadPagesWithResponse#PageRange-InputStream-PageBlobAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.uploadPagesWithResponse#PageRange-InputStream-PageBlobAccessConditions-Duration-Context} * * @param pageRange A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start * offset must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges @@ -206,7 +202,7 @@ public Response uploadPagesWithResponse(PageRange pageRange, Input * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.uploadPagesFromURL#PageRange-URL-Long} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.uploadPagesFromURL#PageRange-URL-Long} * * @param range A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start * offset must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges @@ -231,7 +227,7 @@ public PageBlobItem uploadPagesFromURL(PageRange range, URL sourceURL, Long sour * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.uploadPagesFromURLWithResponse#PageRange-URL-Long-byte-PageBlobAccessConditions-SourceModifiedAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.uploadPagesFromURLWithResponse#PageRange-URL-Long-byte-PageBlobAccessConditions-SourceModifiedAccessConditions-Duration-Context} * * @param range The destination {@link PageRange} range. Given that pages must be aligned with 512-byte boundaries, * the start offset must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte @@ -264,7 +260,7 @@ public Response uploadPagesFromURLWithResponse(PageRange range, UR * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.clearPages#PageRange} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.clearPages#PageRange} * * @param pageRange A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start * offset must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges @@ -281,7 +277,7 @@ public PageBlobItem clearPages(PageRange pageRange) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.clearPagesWithResponse#PageRange-PageBlobAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.clearPagesWithResponse#PageRange-PageBlobAccessConditions-Duration-Context} * * @param pageRange A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start * offset must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges @@ -305,7 +301,7 @@ public Response clearPagesWithResponse(PageRange pageRange, * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.getPageRanges#BlobRange} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.getPageRanges#BlobRange} * * @param blobRange {@link BlobRange} * @return The information of the cleared pages. @@ -320,7 +316,7 @@ public PageList getPageRanges(BlobRange blobRange) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.getPageRangesWithResponse#BlobRange-BlobAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.getPageRangesWithResponse#BlobRange-BlobAccessConditions-Duration-Context} * * @param blobRange {@link BlobRange} * @param accessConditions {@link BlobAccessConditions} @@ -341,7 +337,7 @@ public Response getPageRangesWithResponse(BlobRange blobRange, BlobAcc * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.getPageRangesDiff#BlobRange-String} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.getPageRangesDiff#BlobRange-String} * * @param blobRange {@link BlobRange} * @param prevSnapshot Specifies that the response will contain only pages that were changed between target blob and @@ -360,7 +356,7 @@ public PageList getPageRangesDiff(BlobRange blobRange, String prevSnapshot) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.getPageRangesDiffWithResponse#BlobRange-String-BlobAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.getPageRangesDiffWithResponse#BlobRange-String-BlobAccessConditions-Duration-Context} * * @param blobRange {@link BlobRange} * @param prevSnapshot Specifies that the response will contain only pages that were changed between target blob and @@ -383,7 +379,7 @@ public Response getPageRangesDiffWithResponse(BlobRange blobRange, Str * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.resize#long} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.resize#long} * * @param size Resizes a page blob to the specified size. If the specified value is less than the current size of * the blob, then all pages above the specified value are cleared. @@ -399,7 +395,7 @@ public PageBlobItem resize(long size) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.resizeWithResponse#long-BlobAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.resizeWithResponse#long-BlobAccessConditions-Duration-Context} * * @param size Resizes a page blob to the specified size. If the specified value is less than the current size of * the blob, then all pages above the specified value are cleared. @@ -420,7 +416,7 @@ public Response resizeWithResponse(long size, BlobAccessConditions * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.updateSequenceNumber#SequenceNumberActionType-Long} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.updateSequenceNumber#SequenceNumberActionType-Long} * * @param action Indicates how the service should modify the blob's sequence number. * @param sequenceNumber The blob's sequence number. The sequence number is a user-controlled property that you can @@ -438,7 +434,7 @@ public PageBlobItem updateSequenceNumber(SequenceNumberActionType action, * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.updateSequenceNumberWithResponse#SequenceNumberActionType-Long-BlobAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.updateSequenceNumberWithResponse#SequenceNumberActionType-Long-BlobAccessConditions-Duration-Context} * * @param action Indicates how the service should modify the blob's sequence number. * @param sequenceNumber The blob's sequence number. The sequence number is a user-controlled property that you can @@ -465,7 +461,7 @@ public Response updateSequenceNumberWithResponse(SequenceNumberAct * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.copyIncremental#URL-String} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.copyIncremental#URL-String} * * @param source The source page blob. * @param snapshot The snapshot on the copy source. @@ -485,7 +481,7 @@ public CopyStatusType copyIncremental(URL source, String snapshot) { * *

    Code Samples

    * - * {@codesnippet com.azure.storage.blob.PageBlobClient.copyIncrementalWithResponse#URL-String-ModifiedAccessConditions-Duration-Context} + * {@codesnippet com.azure.storage.blob.specialized.PageBlobClient.copyIncrementalWithResponse#URL-String-ModifiedAccessConditions-Duration-Context} * * @param source The source page blob. * @param snapshot The snapshot on the copy source. diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/SpecializedBlobClientBuilder.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/SpecializedBlobClientBuilder.java new file mode 100644 index 000000000000..18bb1755c37b --- /dev/null +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/SpecializedBlobClientBuilder.java @@ -0,0 +1,267 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.specialized; + +import com.azure.core.annotation.ServiceClientBuilder; +import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.blob.BaseBlobClientBuilder; +import com.azure.storage.blob.BlobURLParts; +import com.azure.storage.blob.ContainerAsyncClient; +import com.azure.storage.blob.ContainerClient; +import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; +import com.azure.storage.blob.implementation.AzureBlobStorageImpl; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.PageRange; +import com.azure.storage.common.credentials.SASTokenCredential; +import reactor.core.publisher.Flux; + +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.Objects; + +/** + * This class provides a fluent builder API to help aid the configuration and instantiation of specialized Storage Blob + * clients, {@link AppendBlobClient}, {@link AppendBlobAsyncClient}, {@link BlockBlobClient}, + * {@link BlockBlobAsyncClient}, {@link PageBlobClient}, and {@link PageBlobAsyncClient}. These clients are used to + * perform operations that are specific to the blob type. + * + * @see AppendBlobClient + * @see AppendBlobAsyncClient + * @see BlockBlobClient + * @see BlockBlobAsyncClient + * @see PageBlobClient + * @see PageBlobAsyncClient + */ +@ServiceClientBuilder(serviceClients = { + AppendBlobClient.class, AppendBlobAsyncClient.class, + BlockBlobClient.class, BlockBlobAsyncClient.class, + PageBlobClient.class, PageBlobAsyncClient.class +}) +public final class SpecializedBlobClientBuilder extends BaseBlobClientBuilder { + private final ClientLogger logger = new ClientLogger(SpecializedBlobClientBuilder.class); + + private String containerName; + private String blobName; + private String snapshot; + + /** + * Creates a {@link AppendBlobClient} based on options set in the Builder. AppendBlobClients are used to perform + * append blob specific operations such as {@link AppendBlobClient#appendBlock(InputStream, long) append block}, + * only use this when the blob is known to be an append blob. + * + * @return a {@link AppendBlobClient} created from the configurations in this builder. + * @throws NullPointerException If {@code endpoint}, {@code containerName}, or {@code blobName} is {@code null}. + */ + public AppendBlobClient buildAppendBlobClient() { + return new AppendBlobClient(buildAppendBlobAsyncClient()); + } + + /** + * Creates a {@link AppendBlobAsyncClient} based on options set in the Builder. AppendBlobAsyncClients are used to + * perform append blob specific operations such as {@link AppendBlobAsyncClient#appendBlock(Flux, long) append + * blob}, only use this when the blob is known to be an append blob. + * + * @return a {@link AppendBlobAsyncClient} created from the configurations in this builder. + * @throws NullPointerException If {@code endpoint}, {@code containerName}, or {@code blobName} is {@code null}. + */ + public AppendBlobAsyncClient buildAppendBlobAsyncClient() { + return new AppendBlobAsyncClient(constructImpl(), snapshot, customerProvidedKey); + } + + /** + * Creates a {@link BlockBlobClient} based on options set in the Builder. BlockBlobClients are used to perform + * generic upload operations such as {@link BlockBlobClient#uploadFromFile(String) upload from file} and block blob + * specific operations such as {@link BlockBlobClient#stageBlock(String, InputStream, long) stage block} and {@link + * BlockBlobClient#commitBlockList(List)}, only use this when the blob is known to be a block blob. + * + * @return a {@link BlockBlobClient} created from the configurations in this builder. + * @throws NullPointerException If {@code endpoint}, {@code containerName}, or {@code blobName} is {@code null}. + */ + public BlockBlobClient buildBlockBlobClient() { + return new BlockBlobClient(buildBlockBlobAsyncClient()); + } + + /** + * Creates a {@link BlockBlobAsyncClient} based on options set in the Builder. BlockBlobAsyncClients are used to + * perform generic upload operations such as {@link BlockBlobAsyncClient#uploadFromFile(String) upload from file} + * and block blob specific operations such as {@link BlockBlobAsyncClient#stageBlockWithResponse(String, Flux, long, + * LeaseAccessConditions) stage block} and {@link BlockBlobAsyncClient#commitBlockList(List) commit block list}, + * only use this when the blob is known to be a block blob. + * + * @return a {@link BlockBlobAsyncClient} created from the configurations in this builder. + * @throws NullPointerException If {@code endpoint}, {@code containerName}, or {@code blobName} is {@code null}. + */ + public BlockBlobAsyncClient buildBlockBlobAsyncClient() { + return new BlockBlobAsyncClient(constructImpl(), snapshot, customerProvidedKey); + } + + /** + * Creates a {@link PageBlobClient} based on options set in the Builder. PageBlobClients are used to perform page + * blob specific operations such as {@link PageBlobClient#uploadPages(PageRange, InputStream) upload pages} and + * {@link PageBlobClient#clearPages(PageRange) clear pages}, only use this when the blob is known to be a page + * blob. + * + * @return a {@link PageBlobClient} created from the configurations in this builder. + * @throws NullPointerException If {@code endpoint}, {@code containerName}, or {@code blobName} is {@code null}. + */ + public PageBlobClient buildPageBlobClient() { + return new PageBlobClient(buildPageBlobAsyncClient()); + } + + /** + * Creates a {@link PageBlobAsyncClient} based on options set in the Builder. PageBlobAsyncClients are used to + * perform page blob specific operations such as {@link PageBlobAsyncClient#uploadPages(PageRange, Flux) upload + * pages} and {@link PageBlobAsyncClient#clearPages(PageRange) clear pages}, only use this when the blob is known to + * be a page blob. + * + * @return a {@link PageBlobAsyncClient} created from the configurations in this builder. + * @throws NullPointerException If {@code endpoint}, {@code containerName}, or {@code blobName} is {@code null}. + */ + public PageBlobAsyncClient buildPageBlobAsyncClient() { + return new PageBlobAsyncClient(constructImpl(), snapshot, customerProvidedKey); + } + + private AzureBlobStorageImpl constructImpl() { + return new AzureBlobStorageBuilder() + .pipeline(getPipeline()) + .url(String.format("%s/%s/%s", endpoint, containerName, blobName)) + .build(); + } + + /** + * Configures the builder based on the {@link BlobClientBase}. + * + * @param blobClient The {@code BlobClientBase} used to configure this builder. + * @return the updated SpecializedBlobClientBuilder object. + */ + public SpecializedBlobClientBuilder blobClient(BlobClientBase blobClient) { + pipeline(blobClient.getHttpPipeline()); + endpoint(blobClient.getBlobUrl().toString()); + this.snapshot = blobClient.getSnapshotId(); + this.customerProvidedKey = blobClient.getCustomerProvidedKey(); + return this; + } + + /** + * Configures the builder based on the {@link BlobAsyncClientBase}. + * + * @param blobAsyncClient The {@code BlobAsyncClientBase} used to configure this builder. + * @return the updated SpecializedBlobClientBuilder object. + */ + public SpecializedBlobClientBuilder blobAsyncClient(BlobAsyncClientBase blobAsyncClient) { + pipeline(blobAsyncClient.getHttpPipeline()); + endpoint(blobAsyncClient.getBlobUrl().toString()); + this.snapshot = blobAsyncClient.getSnapshotId(); + this.customerProvidedKey = blobAsyncClient.getCustomerProvidedKey(); + return this; + } + + /** + * Configures the builder based on the {@link ContainerClient} and appends the blob name to the container's URL. + * + * @param containerClient The {@code ContainerClient} used to configure this builder. + * @param blobName Name of the blob. + * @return the updated SpecializedBlobClientBuilder object. + */ + public SpecializedBlobClientBuilder containerClient(ContainerClient containerClient, String blobName) { + pipeline(containerClient.getHttpPipeline()); + endpoint(containerClient.getContainerUrl().toString()); + blobName(blobName); + this.customerProvidedKey = containerClient.getCustomerProvidedKey(); + return this; + } + + /** + * Configures the builder based on the {@link ContainerAsyncClient} and appends the blob name to the container's + * URL. + * + * @param containerAsyncClient The {@code ContainerAsyncClient} used to configure this builder. + * @param blobName Name of the blob. + * @return the updated SpecializedBlobClientBuilder object. + */ + public SpecializedBlobClientBuilder containerAsyncClient(ContainerAsyncClient containerAsyncClient, + String blobName) { + pipeline(containerAsyncClient.getHttpPipeline()); + endpoint(containerAsyncClient.getContainerUrl().toString()); + blobName(blobName); + this.customerProvidedKey = containerAsyncClient.getCustomerProvidedKey(); + return this; + } + + /** + * Sets the service endpoint, additionally parses it for information (SAS token, container name, blob name) + * + * @param endpoint URL of the service + * @return the updated BlobClientBuilder object + * @throws IllegalArgumentException If {@code endpoint} is {@code null} or is a malformed URL. + */ + @Override + public SpecializedBlobClientBuilder endpoint(String endpoint) { + try { + URL url = new URL(endpoint); + BlobURLParts parts = BlobURLParts.parse(url); + + this.endpoint = parts.getScheme() + "://" + parts.getHost(); + this.containerName = parts.getContainerName(); + this.blobName = parts.getBlobName(); + this.snapshot = parts.getSnapshot(); + + SASTokenCredential sasTokenCredential = + SASTokenCredential.fromSASTokenString(parts.getSasQueryParameters().encode()); + if (sasTokenCredential != null) { + super.credential(sasTokenCredential); + } + } catch (MalformedURLException ex) { + throw logger.logExceptionAsError( + new IllegalArgumentException("The Azure Storage Blob endpoint url is malformed.")); + } + return this; + } + + /** + * Sets the name of the container this client is connecting to. + * + *

    Code Samples

    + * + * {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.Builder.containerName#String} + * + * @param containerName the name of the container + * @return the updated BlobClientBuilder object + * @throws NullPointerException If {@code containerName} is {@code null} + */ + public SpecializedBlobClientBuilder containerName(String containerName) { + this.containerName = Objects.requireNonNull(containerName); + return this; + } + + /** + * Sets the name of the blob this client is connecting to. + * + * @param blobName the name of the blob + * @return the updated BlobClientBuilder object + * @throws NullPointerException If {@code blobName} is {@code null} + */ + public SpecializedBlobClientBuilder blobName(String blobName) { + this.blobName = Objects.requireNonNull(blobName); + return this; + } + + /** + * Sets the snapshot of the blob this client is connecting to. + * + * @param snapshot the snapshot identifier for the blob + * @return the updated BlobClientBuilder object + */ + public SpecializedBlobClientBuilder snapshot(String snapshot) { + this.snapshot = snapshot; + return this; + } + + @Override + protected Class getClazz() { + return SpecializedBlobClientBuilder.class; + } +} diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/UploadBufferPool.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/UploadBufferPool.java similarity index 99% rename from sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/UploadBufferPool.java rename to sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/UploadBufferPool.java index b6278f480c2c..00dafa2fab00 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/UploadBufferPool.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/UploadBufferPool.java @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; import com.azure.core.util.logging.ClientLogger; import com.azure.storage.common.Utility; @@ -41,7 +41,7 @@ final class UploadBufferPool { private final int maxBuffs; // The number of buffs we have allocated. We can query the queue for how many are available. - private int numBuffs = 0; + private int numBuffs; private final int buffSize; diff --git a/sdk/storage/azure-storage-blob/src/main/java/module-info.java b/sdk/storage/azure-storage-blob/src/main/java/module-info.java index 84cfc1b4fe0b..a48f0b46e344 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/module-info.java +++ b/sdk/storage/azure-storage-blob/src/main/java/module-info.java @@ -8,6 +8,7 @@ exports com.azure.storage.blob; exports com.azure.storage.blob.models; + exports com.azure.storage.blob.specialized; opens com.azure.storage.blob.models to com.fasterxml.jackson.databind, diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/AsyncBufferedUploadExample.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/AsyncBufferedUploadExample.java index 5c4478f45971..cea248c4dfd4 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/AsyncBufferedUploadExample.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/AsyncBufferedUploadExample.java @@ -3,6 +3,7 @@ package com.azure.storage.blob; +import com.azure.storage.blob.specialized.BlockBlobAsyncClient; import com.azure.storage.common.credentials.SharedKeyCredential; import reactor.core.publisher.Flux; @@ -42,7 +43,7 @@ public static void main(String[] args) throws IOException { containerClient.create().block(); uploadSourceBlob(endpoint, credential, containerName); - BlockBlobAsyncClient blobClient = containerClient.getBlockBlobAsyncClient("HelloWorld.txt"); + BlockBlobAsyncClient blobClient = containerClient.getBlobAsyncClient("HelloWorld.txt").asBlockBlobAsyncClient(); /* @@ -86,6 +87,6 @@ private static void uploadSourceBlob(String endpoint, SharedKeyCredential creden private static BlockBlobAsyncClient getSourceBlobClient(String endpoint, SharedKeyCredential credential, String containerName) { return new BlobServiceClientBuilder().endpoint(endpoint).credential(credential).buildAsyncClient() - .getContainerAsyncClient(containerName).getBlockBlobAsyncClient("sourceBlob"); + .getContainerAsyncClient(containerName).getBlobAsyncClient("sourceBlob").asBlockBlobAsyncClient(); } } diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BasicExample.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BasicExample.java index 3283c0e51512..73415b2ea1ef 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BasicExample.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BasicExample.java @@ -3,6 +3,7 @@ package com.azure.storage.blob; +import com.azure.storage.blob.specialized.BlockBlobClient; import com.azure.storage.common.credentials.SharedKeyCredential; import java.io.ByteArrayInputStream; @@ -20,6 +21,7 @@ public class BasicExample { /** * Entry point into the basic examples for Storage blobs. + * * @param args Unused. Arguments to the program. * @throws IOException If an I/O error occurs * @throws RuntimeException If the downloaded data doesn't match the uploaded data @@ -69,7 +71,7 @@ public static void main(String[] args) throws IOException { * This returns a BlockBlobClient object that wraps the blob's endpoint, credential and a request pipeline * (inherited from containerClient). Note that blob names can be mixed case. */ - BlockBlobClient blobClient = containerClient.getBlockBlobClient("HelloWorld.txt"); + BlockBlobClient blobClient = containerClient.getBlobClient("HelloWorld.txt").asBlockBlobClient(); String data = "Hello world!"; InputStream dataStream = new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)); @@ -102,8 +104,8 @@ public static void main(String[] args) throws IOException { for (int i = 0; i < 3; i++) { String sampleData = "Samples"; InputStream dataInBlobs = new ByteArrayInputStream(sampleData.getBytes(Charset.defaultCharset())); - containerClient.getBlockBlobClient("myblobsforlisting" + System.currentTimeMillis()) - .upload(dataInBlobs, sampleData.length()); + containerClient.getBlobClient("myblobsforlisting" + System.currentTimeMillis()).asBlockBlobClient() + .upload(dataInBlobs, sampleData.length()); dataInBlobs.close(); } diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobAsyncClientJavaDocCodeSnippets.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobAsyncClientJavaDocCodeSnippets.java index e890b6a60df1..09faa7f6cda2 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobAsyncClientJavaDocCodeSnippets.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobAsyncClientJavaDocCodeSnippets.java @@ -403,7 +403,7 @@ public void generateUserDelegationSASCodeSnippets() { .setReadPermission(true) .setWritePermission(true) .setCreatePermission(true) - .getDeletePermission(true) + .setDeletePermission(true) .setAddPermission(true); OffsetDateTime startTime = OffsetDateTime.now().minusDays(1); OffsetDateTime expiryTime = OffsetDateTime.now().plusDays(1); @@ -436,7 +436,7 @@ public void generateSASCodeSnippets() { .setReadPermission(true) .setWritePermission(true) .setCreatePermission(true) - .getDeletePermission(true) + .setDeletePermission(true) .setAddPermission(true); OffsetDateTime startTime = OffsetDateTime.now().minusDays(1); OffsetDateTime expiryTime = OffsetDateTime.now().plusDays(1); @@ -462,19 +462,19 @@ public void generateSASCodeSnippets() { * Generates a code sample for using {@link BlobAsyncClient#getContainerName()} */ public void getContainerName() { - // BEGIN: com.azure.storage.blob.BlobAsyncClient.getContainerName + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.getContainerName String containerName = client.getContainerName(); System.out.println("The name of the container is " + containerName); - // END: com.azure.storage.blob.BlobAsyncClient.getContainerName + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.getContainerName } /** * Generates a code sample for using {@link BlobAsyncClient#getBlobName()} */ public void getBlobName() { - // BEGIN: com.azure.storage.blob.BlobAsyncClient.getBlobName + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.getBlobName String blobName = client.getBlobName(); System.out.println("The name of the blob is " + blobName); - // END: com.azure.storage.blob.BlobAsyncClient.getBlobName + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.getBlobName } } diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobClientBuilderJavaDocCodeSnippets.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobClientBuilderJavaDocCodeSnippets.java index 93f08404f089..fe430e33e7bf 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobClientBuilderJavaDocCodeSnippets.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobClientBuilderJavaDocCodeSnippets.java @@ -34,45 +34,45 @@ public class BlobClientBuilderJavaDocCodeSnippets { * Code snippet for {@link BlobClientBuilder#buildBlobClient()} using connection string */ public void blobClientConnectionString() { - // BEGIN: com.azure.storage.blob.BlobClientBuilder.buildBlobClient + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.Builder.buildBlobClient BlobClient client = new BlobClientBuilder() .connectionString(connectionString) .buildBlobClient(); - // END: com.azure.storage.blob.BlobClientBuilder.buildBlobClient + // END: com.azure.storage.blob.specialized.BlobClientBase.Builder.buildBlobClient } /** * Code snippet for {@link BlobClientBuilder#buildBlobAsyncClient()} using connection string */ public void blobAsyncClientConnectionString() { - // BEGIN: com.azure.storage.blob.BlobClientBuilder.buildBlobAsyncClient + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.Builder.buildBlobAsyncClient BlobAsyncClient client = new BlobClientBuilder() .connectionString(connectionString) .buildBlobAsyncClient(); - // END: com.azure.storage.blob.BlobClientBuilder.buildBlobAsyncClient + // END: com.azure.storage.blob.specialized.BlobClientBase.Builder.buildBlobAsyncClient } /** * Code snippet for {@link BlobClientBuilder#endpoint(String)} using credential and endpoint */ public void blobClientCredentialAndEndpoint() { - // BEGIN: com.azure.storage.blob.BlobClientBuilder.endpoint#String + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.Builder.endpoint#String BlobClient client = new BlobClientBuilder() .endpoint(endpoint) .credential(sharedKeyCredential) .buildBlobClient(); - // END: com.azure.storage.blob.BlobClientBuilder.endpoint#String + // END: com.azure.storage.blob.specialized.BlobClientBase.Builder.endpoint#String } /** * Code snippet for {@link BlobClientBuilder#containerName(String)} using HttpPipeline */ public void blobClientHttpPipeline() { - // BEGIN: com.azure.storage.blob.BlobClientBuilder.containerName#String + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.Builder.containerName#String BlobClient client = new BlobClientBuilder() .endpoint(endpoint) .containerName(containerName) .buildBlobClient(); - // END: com.azure.storage.blob.BlobClientBuilder.containerName#String + // END: com.azure.storage.blob.specialized.BlobClientBase.Builder.containerName#String } } diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobClientJavaDocCodeSnippets.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobClientJavaDocCodeSnippets.java index 7b95c5d89a3d..bd4765027427 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobClientJavaDocCodeSnippets.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobClientJavaDocCodeSnippets.java @@ -395,7 +395,7 @@ public void generateUserDelegationSASCodeSnippets() { .setReadPermission(true) .setWritePermission(true) .setCreatePermission(true) - .getDeletePermission(true) + .setDeletePermission(true) .setAddPermission(true); OffsetDateTime startTime = OffsetDateTime.now().minusDays(1); OffsetDateTime expiryTime = OffsetDateTime.now().plusDays(1); @@ -428,7 +428,7 @@ public void generateSASCodeSnippets() { .setReadPermission(true) .setWritePermission(true) .setCreatePermission(true) - .getDeletePermission(true) + .setDeletePermission(true) .setAddPermission(true); OffsetDateTime startTime = OffsetDateTime.now().minusDays(1); OffsetDateTime expiryTime = OffsetDateTime.now().plusDays(1); @@ -454,19 +454,19 @@ public void generateSASCodeSnippets() { * Generates a code sample for using {@link BlobClient#getContainerName()} */ public void getContainerName() { - // BEGIN: com.azure.storage.blob.BlobClient.getContainerName + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.getContainerName String containerName = client.getContainerName(); System.out.println("The name of the blob is " + containerName); - // END: com.azure.storage.blob.BlobClient.getContainerName + // END: com.azure.storage.blob.specialized.BlobClientBase.getContainerName } /** * Generates a code sample for using {@link BlobClient#getBlobName()} */ public void getBlobName() { - // BEGIN: com.azure.storage.blob.BlobClient.getBlobName + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.getBlobName String blobName = client.getBlobName(); System.out.println("The name of the blob is " + blobName); - // END: com.azure.storage.blob.BlobClient.getBlobName + // END: com.azure.storage.blob.specialized.BlobClientBase.getBlobName } } diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/ContainerAsyncClientJavaDocCodeSnippets.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/ContainerAsyncClientJavaDocCodeSnippets.java index 41a8dfb46113..f0a69f71ce5d 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/ContainerAsyncClientJavaDocCodeSnippets.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/ContainerAsyncClientJavaDocCodeSnippets.java @@ -122,60 +122,6 @@ public void getSnapshotBlobAsyncClient() { // END: com.azure.storage.blob.ContainerAsyncClient.getBlobAsyncClient#String-String } - /** - * Code snippet for {@link ContainerAsyncClient#getAppendBlobAsyncClient(String)} - */ - public void getAppendBlobAsyncClient() { - // BEGIN: com.azure.storage.blob.ContainerAsyncClient.getAppendBlobAsyncClient#String - AppendBlobAsyncClient appendBlobAsyncClient = client.getAppendBlobAsyncClient(blobName); - // END: com.azure.storage.blob.ContainerAsyncClient.getAppendBlobAsyncClient#String - } - - /** - * Code snippet for {@link ContainerAsyncClient#getAppendBlobAsyncClient(String, String)} - */ - public void getSnapshotAppendBlobAsyncClient() { - // BEGIN: com.azure.storage.blob.ContainerAsyncClient.getAppendBlobAsyncClient#String-String - AppendBlobAsyncClient appendBlobAsyncClient = client.getAppendBlobAsyncClient(blobName, snapshot); - // END: com.azure.storage.blob.ContainerAsyncClient.getAppendBlobAsyncClient#String-String - } - - /** - * Code snippet for {@link ContainerAsyncClient#getBlockBlobAsyncClient(String)} - */ - public void getBlockBlobAsyncClient() { - // BEGIN: com.azure.storage.blob.ContainerAsyncClient.getBlockBlobAsyncClient#String - BlockBlobAsyncClient blockBlobAsyncClient = client.getBlockBlobAsyncClient(blobName); - // END: com.azure.storage.blob.ContainerAsyncClient.getBlockBlobAsyncClient#String - } - - /** - * Code snippet for {@link ContainerAsyncClient#getBlockBlobAsyncClient(String, String)} - */ - public void getSnapshotBlockBlobAsyncClient() { - // BEGIN: com.azure.storage.blob.ContainerAsyncClient.getBlockBlobAsyncClient#String-String - BlockBlobAsyncClient blockBlobAsyncClient = client.getBlockBlobAsyncClient(blobName, snapshot); - // END: com.azure.storage.blob.ContainerAsyncClient.getBlockBlobAsyncClient#String-String - } - - /** - * Code snippet for {@link ContainerAsyncClient#getPageBlobAsyncClient(String)} - */ - public void getPageBlobAsyncClient() { - // BEGIN: com.azure.storage.blob.ContainerAsyncClient.getPageBlobAsyncClient#String - PageBlobAsyncClient pageBlobAsyncClient = client.getPageBlobAsyncClient(blobName); - // END: com.azure.storage.blob.ContainerAsyncClient.getPageBlobAsyncClient#String - } - - /** - * Code snippet for {@link ContainerAsyncClient#getPageBlobAsyncClient(String, String)} - */ - public void getSnapshotPageBlobAsyncClient() { - // BEGIN: com.azure.storage.blob.ContainerAsyncClient.getPageBlobAsyncClient#String-String - PageBlobAsyncClient pageBlobAsyncClient = client.getPageBlobAsyncClient(blobName, snapshot); - // END: com.azure.storage.blob.ContainerAsyncClient.getPageBlobAsyncClient#String-String - } - /** * Code snippet for {@link ContainerAsyncClient#exists()} */ diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/ContainerClientJavaDocCodeSnippets.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/ContainerClientJavaDocCodeSnippets.java index d36c5dccebf0..cc944bee542e 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/ContainerClientJavaDocCodeSnippets.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/ContainerClientJavaDocCodeSnippets.java @@ -124,60 +124,6 @@ public void getSnapshotBlobClient() { // END: com.azure.storage.blob.ContainerClient.getBlobClient#String-String } - /** - * Code snippet for {@link ContainerClient#getAppendBlobClient(String)} - */ - public void getAppendBlobClient() { - // BEGIN: com.azure.storage.blob.ContainerClient.getAppendBlobClient#String - AppendBlobClient appendBlobClient = client.getAppendBlobClient(blobName); - // END: com.azure.storage.blob.ContainerClient.getAppendBlobClient#String - } - - /** - * Code snippet for {@link ContainerClient#getAppendBlobClient(String, String)} - */ - public void getSnapshotAppendBlobClient() { - // BEGIN: com.azure.storage.blob.ContainerClient.getAppendBlobClient#String-String - AppendBlobClient appendBlobClient = client.getAppendBlobClient(blobName, snapshot); - // END: com.azure.storage.blob.ContainerClient.getAppendBlobClient#String-String - } - - /** - * Code snippet for {@link ContainerClient#getBlockBlobClient(String)} - */ - public void getBlockBlobClient() { - // BEGIN: com.azure.storage.blob.ContainerClient.getBlockBlobClient#String - BlockBlobClient blockBlobClient = client.getBlockBlobClient(blobName); - // END: com.azure.storage.blob.ContainerClient.getBlockBlobClient#String - } - - /** - * Code snippet for {@link ContainerClient#getBlockBlobClient(String, String)} - */ - public void getSnapshotBlockBlobClient() { - // BEGIN: com.azure.storage.blob.ContainerClient.getBlockBlobClient#String-String - BlockBlobClient blockBlobClient = client.getBlockBlobClient(blobName, snapshot); - // END: com.azure.storage.blob.ContainerClient.getBlockBlobClient#String-String - } - - /** - * Code snippet for {@link ContainerClient#getPageBlobClient(String)} - */ - public void getPageBlobClient() { - // BEGIN: com.azure.storage.blob.ContainerClient.getPageBlobClient#String - PageBlobClient pageBlobClient = client.getPageBlobClient(blobName); - // END: com.azure.storage.blob.ContainerClient.getPageBlobClient#String - } - - /** - * Code snippet for {@link ContainerClient#getPageBlobClient(String, String)} - */ - public void getSnapshotPageBlobClient() { - // BEGIN: com.azure.storage.blob.ContainerClient.getPageBlobClient#String-String - PageBlobClient pageBlobClient = client.getPageBlobClient(blobName, snapshot); - // END: com.azure.storage.blob.ContainerClient.getPageBlobClient#String-String - } - /** * Code snippets for {@link ContainerClient#exists()} and {@link ContainerClient#existsWithResponse(Duration, * Context)} diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/FileTransferExample.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/FileTransferExample.java index 6d462368bba7..e8ac5641e57d 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/FileTransferExample.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/FileTransferExample.java @@ -3,6 +3,7 @@ package com.azure.storage.blob; +import com.azure.storage.blob.specialized.BlockBlobClient; import com.azure.storage.common.credentials.SharedKeyCredential; import java.io.File; @@ -77,7 +78,7 @@ public static void main(String[] args) throws IOException, NoSuchAlgorithmExcept * Create a BlockBlobClient object that wraps a blob's endpoint and a default pipeline, the blockBlobClient give us access to upload the file. */ String filename = "BigFile.bin"; - BlockBlobClient blobClient = containerClient.getBlockBlobClient(filename); + BlockBlobClient blobClient = containerClient.getBlobClient(filename).asBlockBlobClient(); /* * Create the empty uploadFile and downloadFile. diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/JavaDocCodeSnippetsHelpers.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/JavaDocCodeSnippetsHelpers.java index 13bffad9de2a..81e749932ffa 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/JavaDocCodeSnippetsHelpers.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/JavaDocCodeSnippetsHelpers.java @@ -23,20 +23,6 @@ static BlobClient getBlobClient(String blobName) { return new BlobClient(getBlobAsyncClient(blobName)); } - static PageBlobClient getPageBlobClient(String blobName, String containerName) { - return new BlobClientBuilder() - .blobName(blobName) - .containerName(containerName) - .buildPageBlobClient(); - } - - static PageBlobAsyncClient getPageBlobAsyncClient(String blobName, String containerName) { - return new BlobClientBuilder() - .blobName(blobName) - .containerName(containerName) - .buildPageBlobAsyncClient(); - } - static BlobServiceAsyncClient getBlobServiceAsyncClient() { return new BlobServiceClientBuilder().buildAsyncClient(); } diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/SetMetadataAndHTTPHeadersExample.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/SetMetadataAndHTTPHeadersExample.java index 0599c91f3b45..480f7eada9d5 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/SetMetadataAndHTTPHeadersExample.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/SetMetadataAndHTTPHeadersExample.java @@ -6,6 +6,7 @@ import com.azure.core.util.Context; import com.azure.storage.blob.models.BlobHTTPHeaders; import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.specialized.BlockBlobClient; import com.azure.storage.common.credentials.SharedKeyCredential; import java.io.ByteArrayInputStream; @@ -16,15 +17,15 @@ import java.util.Locale; /** - * This example shows how to set metadata for containers and blobs and how to set HTTPHeaders for blobs - * using the Azure Storage Blob SDK for Java. + * This example shows how to set metadata for containers and blobs and how to set HTTPHeaders for blobs using the Azure + * Storage Blob SDK for Java. */ public class SetMetadataAndHTTPHeadersExample { /** * Entry point into the setting metadata examples for Storage blobs. - * @param args Unused. Arguments to the program. * + * @param args Unused. Arguments to the program. * @throws IOException If an I/O error occurs */ public static void main(String[] args) throws IOException { @@ -65,7 +66,7 @@ public static void main(String[] args) throws IOException { /* * Create a blob client. */ - BlockBlobClient blobClient = containerClient.getBlockBlobClient("myblob" + System.currentTimeMillis()); + BlockBlobClient blobClient = containerClient.getBlobClient("myblob" + System.currentTimeMillis()).asBlockBlobClient(); /* * Create a blob with blob's blobMetadata and BlobHttpHeaders. diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/AppendBlobAsyncClientJavaDocCodeSnippets.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/AppendBlobAsyncClientJavaDocCodeSnippets.java similarity index 70% rename from sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/AppendBlobAsyncClientJavaDocCodeSnippets.java rename to sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/AppendBlobAsyncClientJavaDocCodeSnippets.java index 839e07fada36..b072e1e6e1af 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/AppendBlobAsyncClientJavaDocCodeSnippets.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/AppendBlobAsyncClientJavaDocCodeSnippets.java @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; import com.azure.storage.blob.models.AppendBlobAccessConditions; import com.azure.storage.blob.models.AppendPositionAccessConditions; @@ -14,9 +14,10 @@ import com.azure.storage.blob.models.SourceModifiedAccessConditions; import reactor.core.publisher.Flux; -import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; import java.net.URL; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.time.OffsetDateTime; import java.util.Collections; @@ -24,39 +25,37 @@ * Code snippets for {@link AppendBlobAsyncClient} */ public class AppendBlobAsyncClientJavaDocCodeSnippets { - private AppendBlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient("blobName") - .asAppendBlobAsyncClient(); + private AppendBlobAsyncClient client = new SpecializedBlobClientBuilder().buildAppendBlobAsyncClient(); private String leaseId = "leaseId"; - private Flux data = Flux.just(ByteBuffer.wrap("data".getBytes("UTF-8"))); + private Flux data = Flux.just(ByteBuffer.wrap("data".getBytes(StandardCharsets.UTF_8))); private long length = 4L; private static final Long POSITION = null; private Long maxSize = length; - private URL sourceUrl = JavaDocCodeSnippetsHelpers.generateURL("https://example.com"); + private URL sourceUrl = new URL("https://example.com"); private long offset = 1024; private long count = 1024; /** - * - * @throws UnsupportedEncodingException if cannot get bytes from sample sting as utf-8 encoding + * @throws MalformedURLException Ignore */ - AppendBlobAsyncClientJavaDocCodeSnippets() throws UnsupportedEncodingException { + public AppendBlobAsyncClientJavaDocCodeSnippets() throws MalformedURLException { } /** * Code snippet for {@link AppendBlobAsyncClient#create()} */ public void create() { - // BEGIN: com.azure.storage.blob.AppendBlobAsyncClient.create + // BEGIN: com.azure.storage.blob.specialized.AppendBlobAsyncClient.create client.create().subscribe(response -> System.out.printf("Created AppendBlob at %s%n", response.getLastModified())); - // END: com.azure.storage.blob.AppendBlobAsyncClient.create + // END: com.azure.storage.blob.specialized.AppendBlobAsyncClient.create } /** * Code snippet for {@link AppendBlobAsyncClient#createWithResponse(BlobHTTPHeaders, Metadata, BlobAccessConditions)} */ public void create2() { - // BEGIN: com.azure.storage.blob.AppendBlobAsyncClient.createWithResponse#BlobHTTPHeaders-Metadata-BlobAccessConditions + // BEGIN: com.azure.storage.blob.specialized.AppendBlobAsyncClient.createWithResponse#BlobHTTPHeaders-Metadata-BlobAccessConditions BlobHTTPHeaders headers = new BlobHTTPHeaders() .setBlobContentType("binary") .setBlobContentLanguage("en-US"); @@ -68,24 +67,24 @@ public void create2() { client.createWithResponse(headers, metadata, accessConditions).subscribe(response -> System.out.printf("Created AppendBlob at %s%n", response.getValue().getLastModified())); - // END: com.azure.storage.blob.AppendBlobAsyncClient.createWithResponse#BlobHTTPHeaders-Metadata-BlobAccessConditions + // END: com.azure.storage.blob.specialized.AppendBlobAsyncClient.createWithResponse#BlobHTTPHeaders-Metadata-BlobAccessConditions } /** * Code snippet for {@link AppendBlobAsyncClient#appendBlock(Flux, long)} */ public void appendBlock() { - // BEGIN: com.azure.storage.blob.AppendBlobAsyncClient.appendBlock#Flux-long + // BEGIN: com.azure.storage.blob.specialized.AppendBlobAsyncClient.appendBlock#Flux-long client.appendBlock(data, length).subscribe(response -> System.out.printf("AppendBlob has %d committed blocks%n", response.getBlobCommittedBlockCount())); - // END: com.azure.storage.blob.AppendBlobAsyncClient.appendBlock#Flux-long + // END: com.azure.storage.blob.specialized.AppendBlobAsyncClient.appendBlock#Flux-long } /** * Code snippet for {@link AppendBlobAsyncClient#appendBlockWithResponse(Flux, long, AppendBlobAccessConditions)} */ public void appendBlock2() { - // BEGIN: com.azure.storage.blob.AppendBlobAsyncClient.appendBlockWithResponse#Flux-long-AppendBlobAccessConditions + // BEGIN: com.azure.storage.blob.specialized.AppendBlobAsyncClient.appendBlockWithResponse#Flux-long-AppendBlobAccessConditions AppendBlobAccessConditions accessConditions = new AppendBlobAccessConditions() .setAppendPositionAccessConditions(new AppendPositionAccessConditions() .setAppendPosition(POSITION) @@ -93,24 +92,24 @@ public void appendBlock2() { client.appendBlockWithResponse(data, length, accessConditions).subscribe(response -> System.out.printf("AppendBlob has %d committed blocks%n", response.getValue().getBlobCommittedBlockCount())); - // END: com.azure.storage.blob.AppendBlobAsyncClient.appendBlockWithResponse#Flux-long-AppendBlobAccessConditions + // END: com.azure.storage.blob.specialized.AppendBlobAsyncClient.appendBlockWithResponse#Flux-long-AppendBlobAccessConditions } /** * Code snippet for {@link AppendBlobAsyncClient#appendBlockFromUrl(URL, BlobRange)} */ public void appendBlockFromUrl() { - // BEGIN: com.azure.storage.blob.AppendBlobAsyncClient.appendBlockFromUrl#URL-BlobRange + // BEGIN: com.azure.storage.blob.specialized.AppendBlobAsyncClient.appendBlockFromUrl#URL-BlobRange client.appendBlockFromUrl(sourceUrl, new BlobRange(offset, count)).subscribe(response -> System.out.printf("AppendBlob has %d committed blocks%n", response.getBlobCommittedBlockCount())); - // END: com.azure.storage.blob.AppendBlobAsyncClient.appendBlockFromUrl#URL-BlobRange + // END: com.azure.storage.blob.specialized.AppendBlobAsyncClient.appendBlockFromUrl#URL-BlobRange } /** * Code snippet for {@link AppendBlobAsyncClient#appendBlockFromUrlWithResponse(URL, BlobRange, byte[], AppendBlobAccessConditions, SourceModifiedAccessConditions)} */ public void appendBlockFromUrl2() { - // BEGIN: com.azure.storage.blob.AppendBlobAsyncClient.appendBlockFromUrlWithResponse#URL-BlobRange-byte-AppendBlobAccessConditions-SourceModifiedAccessConditions + // BEGIN: com.azure.storage.blob.specialized.AppendBlobAsyncClient.appendBlockFromUrlWithResponse#URL-BlobRange-byte-AppendBlobAccessConditions-SourceModifiedAccessConditions AppendBlobAccessConditions appendBlobAccessConditions = new AppendBlobAccessConditions() .setAppendPositionAccessConditions(new AppendPositionAccessConditions() .setAppendPosition(POSITION) @@ -122,6 +121,6 @@ public void appendBlockFromUrl2() { client.appendBlockFromUrlWithResponse(sourceUrl, new BlobRange(offset, count), null, appendBlobAccessConditions, modifiedAccessConditions).subscribe(response -> System.out.printf("AppendBlob has %d committed blocks%n", response.getValue().getBlobCommittedBlockCount())); - // END: com.azure.storage.blob.AppendBlobAsyncClient.appendBlockFromUrlWithResponse#URL-BlobRange-byte-AppendBlobAccessConditions-SourceModifiedAccessConditions + // END: com.azure.storage.blob.specialized.AppendBlobAsyncClient.appendBlockFromUrlWithResponse#URL-BlobRange-byte-AppendBlobAccessConditions-SourceModifiedAccessConditions } } diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/AppendBlobClientJavaDocCodeSnippets.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/AppendBlobClientJavaDocCodeSnippets.java similarity index 71% rename from sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/AppendBlobClientJavaDocCodeSnippets.java rename to sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/AppendBlobClientJavaDocCodeSnippets.java index 60e4934ab021..f4970d1ea2e6 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/AppendBlobClientJavaDocCodeSnippets.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/AppendBlobClientJavaDocCodeSnippets.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; import com.azure.core.util.Context; - import com.azure.storage.blob.models.AppendBlobAccessConditions; import com.azure.storage.blob.models.AppendPositionAccessConditions; import com.azure.storage.blob.models.BlobAccessConditions; @@ -17,8 +16,9 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.OffsetDateTime; import java.util.Collections; @@ -28,31 +28,30 @@ */ public class AppendBlobClientJavaDocCodeSnippets { - private AppendBlobClient client = JavaDocCodeSnippetsHelpers.getBlobClient("blobName") - .asAppendBlobClient(); + private AppendBlobClient client = new SpecializedBlobClientBuilder().buildAppendBlobClient(); private Duration timeout = Duration.ofSeconds(30); private String leaseId = "leaseId"; - private InputStream data = new ByteArrayInputStream("data".getBytes("UTF-8")); + private InputStream data = new ByteArrayInputStream("data".getBytes(StandardCharsets.UTF_8)); private long length = 4L; private static final Long POSITION = null; private Long maxSize = length; - private URL sourceUrl = JavaDocCodeSnippetsHelpers.generateURL("https://example.com"); + private URL sourceUrl = new URL("https://example.com"); private long offset = 1024; private long count = 1024; /** - * @throws UnsupportedEncodingException if cannot get bytes from sample sting as utf-8 encoding + * @throws MalformedURLException Ignore */ - AppendBlobClientJavaDocCodeSnippets() throws UnsupportedEncodingException { + public AppendBlobClientJavaDocCodeSnippets() throws MalformedURLException { } /** * Code snippet for {@link AppendBlobClient#create()} */ public void create() { - // BEGIN: com.azure.storage.blob.AppendBlobClient.create + // BEGIN: com.azure.storage.blob.specialized.AppendBlobClient.create System.out.printf("Created AppendBlob at %s%n", client.create().getLastModified()); - // END: com.azure.storage.blob.AppendBlobClient.create + // END: com.azure.storage.blob.specialized.AppendBlobClient.create } /** @@ -60,7 +59,7 @@ public void create() { * Duration, Context)} */ public void createWithResponse() { - // BEGIN: com.azure.storage.blob.AppendBlobClient.createWithResponse#BlobHTTPHeaders-Metadata-BlobAccessConditions-Duration-Context + // BEGIN: com.azure.storage.blob.specialized.AppendBlobClient.createWithResponse#BlobHTTPHeaders-Metadata-BlobAccessConditions-Duration-Context BlobHTTPHeaders headers = new BlobHTTPHeaders() .setBlobContentType("binary") .setBlobContentLanguage("en-US"); @@ -73,17 +72,17 @@ public void createWithResponse() { System.out.printf("Created AppendBlob at %s%n", client.createWithResponse(headers, metadata, accessConditions, timeout, context).getValue().getLastModified()); - // END: com.azure.storage.blob.AppendBlobClient.createWithResponse#BlobHTTPHeaders-Metadata-BlobAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.AppendBlobClient.createWithResponse#BlobHTTPHeaders-Metadata-BlobAccessConditions-Duration-Context } /** * Code snippet for {@link AppendBlobClient#appendBlock(InputStream, long)} */ public void appendBlock() { - // BEGIN: com.azure.storage.blob.AppendBlobClient.appendBlock#InputStream-long + // BEGIN: com.azure.storage.blob.specialized.AppendBlobClient.appendBlock#InputStream-long System.out.printf("AppendBlob has %d committed blocks%n", client.appendBlock(data, length).getBlobCommittedBlockCount()); - // END: com.azure.storage.blob.AppendBlobClient.appendBlock#InputStream-long + // END: com.azure.storage.blob.specialized.AppendBlobClient.appendBlock#InputStream-long } /** @@ -91,7 +90,7 @@ public void appendBlock() { * Duration, Context)} */ public void appendBlock2() { - // BEGIN: com.azure.storage.blob.AppendBlobClient.appendBlockWithResponse#InputStream-long-AppendBlobAccessConditions-Duration-Context + // BEGIN: com.azure.storage.blob.specialized.AppendBlobClient.appendBlockWithResponse#InputStream-long-AppendBlobAccessConditions-Duration-Context AppendBlobAccessConditions accessConditions = new AppendBlobAccessConditions() .setAppendPositionAccessConditions(new AppendPositionAccessConditions() .setAppendPosition(POSITION) @@ -101,17 +100,17 @@ public void appendBlock2() { System.out.printf("AppendBlob has %d committed blocks%n", client.appendBlockWithResponse(data, length, accessConditions, timeout, context).getValue().getBlobCommittedBlockCount()); - // END: com.azure.storage.blob.AppendBlobClient.appendBlockWithResponse#InputStream-long-AppendBlobAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.AppendBlobClient.appendBlockWithResponse#InputStream-long-AppendBlobAccessConditions-Duration-Context } /** * Code snippet for {@link AppendBlobClient#appendBlockFromUrl(URL, BlobRange)} */ public void appendBlockFromUrl() { - // BEGIN: com.azure.storage.blob.AppendBlobClient.appendBlockFromUrl#URL-BlobRange + // BEGIN: com.azure.storage.blob.specialized.AppendBlobClient.appendBlockFromUrl#URL-BlobRange System.out.printf("AppendBlob has %d committed blocks%n", client.appendBlockFromUrl(sourceUrl, new BlobRange(offset, count)).getBlobCommittedBlockCount()); - // END: com.azure.storage.blob.AppendBlobClient.appendBlockFromUrl#URL-BlobRange + // END: com.azure.storage.blob.specialized.AppendBlobClient.appendBlockFromUrl#URL-BlobRange } /** @@ -119,7 +118,7 @@ public void appendBlockFromUrl() { * AppendBlobAccessConditions, SourceModifiedAccessConditions, Duration, Context)} */ public void appendBlockFromUrlWithResponse() { - // BEGIN: com.azure.storage.blob.AppendBlobClient.appendBlockFromUrlWithResponse#URL-BlobRange-byte-AppendBlobAccessConditions-SourceModifiedAccessConditions-Duration-Context + // BEGIN: com.azure.storage.blob.specialized.AppendBlobClient.appendBlockFromUrlWithResponse#URL-BlobRange-byte-AppendBlobAccessConditions-SourceModifiedAccessConditions-Duration-Context AppendBlobAccessConditions appendBlobAccessConditions = new AppendBlobAccessConditions() .setAppendPositionAccessConditions(new AppendPositionAccessConditions() .setAppendPosition(POSITION) @@ -134,6 +133,6 @@ public void appendBlockFromUrlWithResponse() { client.appendBlockFromUrlWithResponse(sourceUrl, new BlobRange(offset, count), null, appendBlobAccessConditions, modifiedAccessConditions, timeout, context).getValue().getBlobCommittedBlockCount()); - // END: com.azure.storage.blob.AppendBlobClient.appendBlockFromUrlWithResponse#URL-BlobRange-byte-AppendBlobAccessConditions-SourceModifiedAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.AppendBlobClient.appendBlockFromUrlWithResponse#URL-BlobRange-byte-AppendBlobAccessConditions-SourceModifiedAccessConditions-Duration-Context } } diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/BlobAsyncClientBaseJavaDocCodeSnippets.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/BlobAsyncClientBaseJavaDocCodeSnippets.java new file mode 100644 index 000000000000..c5eb68ee8c64 --- /dev/null +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/BlobAsyncClientBaseJavaDocCodeSnippets.java @@ -0,0 +1,468 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.specialized; + +import com.azure.storage.blob.BlobSASPermission; +import com.azure.storage.blob.models.AccessTier; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.DeleteSnapshotsOptionType; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.RehydratePriority; +import com.azure.storage.blob.models.ReliableDownloadOptions; +import com.azure.storage.blob.models.UserDelegationKey; +import com.azure.storage.common.Constants; +import com.azure.storage.common.IPRange; +import com.azure.storage.common.SASProtocol; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.time.OffsetDateTime; +import java.util.Collections; + +/** + * Code snippets for {@link BlobAsyncClientBase} + */ +@SuppressWarnings("unused") +public class BlobAsyncClientBaseJavaDocCodeSnippets { + private BlobAsyncClientBase client = new BlobAsyncClientBase(null, null, null); + private String leaseId = "leaseId"; + private String copyId = "copyId"; + private URL url = new URL("https://sample.com"); + private String file = "file"; + + /** + * @throws MalformedURLException Ignore + */ + public BlobAsyncClientBaseJavaDocCodeSnippets() throws MalformedURLException { + } + + /** + * Code snippet for {@link BlobAsyncClientBase#exists()} + */ + public void existsCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.exists + client.exists().subscribe(response -> System.out.printf("Exists? %b%n", response)); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.exists + } + + /** + * Code snippets for {@link BlobAsyncClientBase#startCopyFromURL(URL)} + */ + public void startCopyFromURLCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.startCopyFromURL#URL + client.startCopyFromURL(url) + .subscribe(response -> System.out.printf("Copy identifier: %s%n", response)); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.startCopyFromURL#URL + } + + /** + * Code snippets for {@link BlobAsyncClientBase#abortCopyFromURL(String)} + */ + public void abortCopyFromURLCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.abortCopyFromURL#String + client.abortCopyFromURL(copyId).doOnSuccess(response -> System.out.println("Aborted copy from URL")); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.abortCopyFromURL#String + } + + /** + * Code snippets for {@link BlobAsyncClientBase#copyFromURL(URL)} + */ + public void copyFromURLCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.copyFromURL#URL + client.copyFromURL(url).subscribe(response -> System.out.printf("Copy identifier: %s%n", response)); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.copyFromURL#URL + } + + /** + * Code snippets for {@link BlobAsyncClientBase#download()} + * + * @throws UncheckedIOException If an I/O error occurs + */ + public void downloadCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.download + client.download().subscribe(response -> { + ByteArrayOutputStream downloadData = new ByteArrayOutputStream(); + response.subscribe(piece -> { + try { + downloadData.write(piece.array()); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); + }); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.download + + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.download#BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean + BlobRange range = new BlobRange(1024, 2048L); + ReliableDownloadOptions options = new ReliableDownloadOptions().maxRetryRequests(5); + + client.downloadWithResponse(range, options, null, false).subscribe(response -> { + ByteArrayOutputStream downloadData = new ByteArrayOutputStream(); + response.getValue().subscribe(piece -> { + try { + downloadData.write(piece.array()); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); + }); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.download#BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean + } + + /** + * Code snippets for {@link BlobAsyncClientBase#downloadToFile(String)} and {@link BlobAsyncClientBase#downloadToFile(String, + * BlobRange, Integer, ReliableDownloadOptions, BlobAccessConditions, boolean)} + */ + public void downloadToFileCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadToFile#String + client.downloadToFile(file).subscribe(response -> System.out.println("Completed download to file")); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadToFile#String + + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadToFile#String-BlobRange-Integer-ReliableDownloadOptions-BlobAccessConditions-boolean + BlobRange range = new BlobRange(1024, 2048L); + ReliableDownloadOptions options = new ReliableDownloadOptions().maxRetryRequests(5); + + client.downloadToFile(file, range, null, options, null, false) + .subscribe(response -> System.out.println("Completed download to file")); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadToFile#String-BlobRange-Integer-ReliableDownloadOptions-BlobAccessConditions-boolean + } + + /** + * Code snippets for {@link BlobAsyncClientBase#delete()} + */ + public void deleteCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.delete + client.delete().doOnSuccess(response -> System.out.println("Completed delete")); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.delete + } + + /** + * Code snippets for {@link BlobAsyncClientBase#getProperties()} + */ + public void getPropertiesCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.getProperties + client.getProperties().subscribe(response -> + System.out.printf("Type: %s, Size: %d%n", response.getBlobType(), response.getBlobSize())); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.getProperties + } + + /** + * Code snippets for {@link BlobAsyncClientBase#setHTTPHeaders(BlobHTTPHeaders)} + */ + public void setHTTPHeadersCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.setHTTPHeaders#BlobHTTPHeaders + client.setHTTPHeaders(new BlobHTTPHeaders() + .setBlobContentLanguage("en-US") + .setBlobContentType("binary")); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.setHTTPHeaders#BlobHTTPHeaders + } + + /** + * Code snippets for {@link BlobAsyncClientBase#setMetadata(Metadata)} + */ + public void setMetadataCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.setMetadata#Metadata + client.setMetadata(new Metadata(Collections.singletonMap("metadata", "value"))); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.setMetadata#Metadata + } + + /** + * Code snippets for {@link BlobAsyncClientBase#createSnapshot()} + */ + public void createSnapshotCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.createSnapshot + client.createSnapshot() + .subscribe(response -> System.out.printf("Identifier for the snapshot is %s%n", + response.getSnapshotId())); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.createSnapshot + } + + /** + * Code snippets for {@link BlobAsyncClientBase#setTier(AccessTier)} + */ + public void setTierCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.setTier#AccessTier + client.setTier(AccessTier.HOT); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.setTier#AccessTier + } + + /** + * Code snippet for {@link BlobAsyncClientBase#undelete()} + */ + public void undeleteCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.undelete + client.undelete().doOnSuccess(response -> System.out.println("Completed undelete")); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.undelete + } + + /** + * Code snippet for {@link BlobAsyncClientBase#getAccountInfo()} + */ + public void getAccountInfoCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.getAccountInfo + client.getAccountInfo().subscribe(response -> System.out.printf("Account Kind: %s, SKU: %s%n", + response.getAccountKind(), response.getSkuName())); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.getAccountInfo + } + + /** + * Code snippet for {@link BlobAsyncClientBase#existsWithResponse()} + */ + public void existsWithResponseCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.existsWithResponse + client.existsWithResponse().subscribe(response -> System.out.printf("Exists? %b%n", response.getValue())); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.existsWithResponse + } + + /** + * Code snippets for {@link BlobAsyncClientBase#startCopyFromURLWithResponse(URL, Metadata, AccessTier, + * RehydratePriority, ModifiedAccessConditions, BlobAccessConditions)} + */ + public void startCopyFromURLWithResponseCodeSnippets() { + + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.startCopyFromURLWithResponse#URL-Metadata-AccessTier-RehydratePriority-ModifiedAccessConditions-BlobAccessConditions + Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .setIfUnmodifiedSince(OffsetDateTime.now().minusDays(7)); + BlobAccessConditions blobAccessConditions = new BlobAccessConditions() + .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseId)); + + client.startCopyFromURLWithResponse(url, metadata, AccessTier.HOT, RehydratePriority.STANDARD, + modifiedAccessConditions, blobAccessConditions) + .subscribe(response -> System.out.printf("Copy identifier: %s%n", response.getValue())); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.startCopyFromURLWithResponse#URL-Metadata-AccessTier-RehydratePriority-ModifiedAccessConditions-BlobAccessConditions + } + + /** + * Code snippets for {@link BlobAsyncClientBase#abortCopyFromURLWithResponse(String, LeaseAccessConditions)} + */ + public void abortCopyFromURLWithResponseCodeSnippets() { + + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.abortCopyFromURLWithResponse#String-LeaseAccessConditions + LeaseAccessConditions leaseAccessConditions = new LeaseAccessConditions().setLeaseId(leaseId); + client.abortCopyFromURLWithResponse(copyId, leaseAccessConditions) + .subscribe(response -> System.out.printf("Aborted copy completed with status %d%n", response.getStatusCode())); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.abortCopyFromURLWithResponse#String-LeaseAccessConditions + } + + /** + * Code snippets for {@link BlobAsyncClientBase#copyFromURLWithResponse(URL, Metadata, AccessTier, + * ModifiedAccessConditions, BlobAccessConditions)} + */ + public void copyFromURLWithResponseCodeSnippets() { + + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.copyFromURLWithResponse#URL-Metadata-AccessTier-ModifiedAccessConditions-BlobAccessConditions + Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .setIfUnmodifiedSince(OffsetDateTime.now().minusDays(7)); + BlobAccessConditions blobAccessConditions = new BlobAccessConditions() + .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseId)); + + client.copyFromURLWithResponse(url, metadata, AccessTier.HOT, modifiedAccessConditions, blobAccessConditions) + .subscribe(response -> System.out.printf("Copy identifier: %s%n", response)); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.copyFromURLWithResponse#URL-Metadata-AccessTier-ModifiedAccessConditions-BlobAccessConditions + } + + /** + * Code snippets for {@link BlobAsyncClientBase#downloadWithResponse(BlobRange, ReliableDownloadOptions, + * BlobAccessConditions, boolean)} + * + * @throws UncheckedIOException If an I/O error occurs + */ + public void downloadWithResponseCodeSnippets() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadWithResponse#BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean + BlobRange range = new BlobRange(1024, (long) 2048); + ReliableDownloadOptions options = new ReliableDownloadOptions().maxRetryRequests(5); + + client.downloadWithResponse(range, options, null, false).subscribe(response -> { + ByteArrayOutputStream downloadData = new ByteArrayOutputStream(); + response.getValue().subscribe(piece -> { + try { + downloadData.write(piece.array()); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); + }); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadWithResponse#BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean + } + + /** + * Code snippets for {@link BlobAsyncClientBase#deleteWithResponse(DeleteSnapshotsOptionType, BlobAccessConditions)} + */ + public void deleteWithResponseCodeSnippets() { + + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.deleteWithResponse#DeleteSnapshotsOptionType-BlobAccessConditions + client.deleteWithResponse(DeleteSnapshotsOptionType.INCLUDE, null) + .subscribe(response -> System.out.printf("Delete completed with status %d%n", response.getStatusCode())); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.deleteWithResponse#DeleteSnapshotsOptionType-BlobAccessConditions + } + + /** + * Code snippets for {@link BlobAsyncClientBase#getPropertiesWithResponse(BlobAccessConditions)} + */ + public void getPropertiesWithResponseCodeSnippets() { + + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.getPropertiesWithResponse#BlobAccessConditions + BlobAccessConditions accessConditions = new BlobAccessConditions() + .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseId)); + + client.getPropertiesWithResponse(accessConditions).subscribe( + response -> System.out.printf("Type: %s, Size: %d%n", response.getValue().getBlobType(), + response.getValue().getBlobSize())); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.getPropertiesWithResponse#BlobAccessConditions + } + + /** + * Code snippets for {@link BlobAsyncClientBase#setHTTPHeadersWithResponse(BlobHTTPHeaders, BlobAccessConditions)} + */ + public void setHTTPHeadersWithResponseCodeSnippets() { + + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.setHTTPHeadersWithResponse#BlobHTTPHeaders-BlobAccessConditions + BlobAccessConditions accessConditions = new BlobAccessConditions() + .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseId)); + + client.setHTTPHeadersWithResponse(new BlobHTTPHeaders() + .setBlobContentLanguage("en-US") + .setBlobContentType("binary"), accessConditions).subscribe( + response -> + System.out.printf("Set HTTP headers completed with status %d%n", + response.getStatusCode())); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.setHTTPHeadersWithResponse#BlobHTTPHeaders-BlobAccessConditions + } + + /** + * Code snippets for {@link BlobAsyncClientBase#setMetadataWithResponse(Metadata, BlobAccessConditions)} + */ + public void setMetadataWithResponseCodeSnippets() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.setMetadataWithResponse#Metadata-BlobAccessConditions + BlobAccessConditions accessConditions = new BlobAccessConditions() + .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseId)); + + client.setMetadataWithResponse(new Metadata(Collections.singletonMap("metadata", "value")), accessConditions) + .subscribe(response -> System.out.printf("Set metadata completed with status %d%n", response.getStatusCode())); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.setMetadataWithResponse#Metadata-BlobAccessConditions + } + + /** + * Code snippets for {@link BlobAsyncClientBase#createSnapshotWithResponse(Metadata, BlobAccessConditions)} + */ + public void createSnapshotWithResponseCodeSnippets() { + + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.createSnapshotWithResponse#Metadata-BlobAccessConditions + Metadata snapshotMetadata = new Metadata(Collections.singletonMap("metadata", "value")); + BlobAccessConditions accessConditions = new BlobAccessConditions().setLeaseAccessConditions( + new LeaseAccessConditions().setLeaseId(leaseId)); + + client.createSnapshotWithResponse(snapshotMetadata, accessConditions) + .subscribe(response -> System.out.printf("Identifier for the snapshot is %s%n", response.getValue())); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.createSnapshotWithResponse#Metadata-BlobAccessConditions + } + + /** + * Code snippets for {@link BlobAsyncClientBase#setTierWithResponse(AccessTier, RehydratePriority, + * LeaseAccessConditions)} + */ + public void setTierWithResponseCodeSnippets() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.setTierWithResponse#AccessTier-RehydratePriority-LeaseAccessConditions + LeaseAccessConditions accessConditions = new LeaseAccessConditions().setLeaseId(leaseId); + + client.setTierWithResponse(AccessTier.HOT, RehydratePriority.STANDARD, accessConditions) + .subscribe(response -> System.out.printf("Set tier completed with status code %d%n", + response.getStatusCode())); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.setTierWithResponse#AccessTier-RehydratePriority-LeaseAccessConditions + } + + /** + * Code snippet for {@link BlobAsyncClientBase#undeleteWithResponse()} + */ + public void undeleteWithResponseCodeSnippets() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.undeleteWithResponse + client.undeleteWithResponse() + .subscribe(response -> System.out.printf("Undelete completed with status %d%n", response.getStatusCode())); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.undeleteWithResponse + } + + /** + * Code snippet for {@link BlobAsyncClientBase#getAccountInfoWithResponse()} + */ + public void getAccountInfoWithResponseCodeSnippets() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.getAccountInfoWithResponse + client.getAccountInfoWithResponse().subscribe(response -> System.out.printf("Account Kind: %s, SKU: %s%n", + response.getValue().getAccountKind(), response.getValue().getSkuName())); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.getAccountInfoWithResponse + } + + /** + * Code snippet for {@link BlobAsyncClientBase#generateUserDelegationSAS(UserDelegationKey, String, BlobSASPermission, + * OffsetDateTime, OffsetDateTime, String, SASProtocol, IPRange, String, String, String, String, String)} + */ + public void generateUserDelegationSASCodeSnippets() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.generateUserDelegationSAS#UserDelegationKey-String-BlobSASPermission-OffsetDateTime-OffsetDateTime-String-SASProtocol-IPRange-String-String-String-String-String + BlobSASPermission permissions = new BlobSASPermission() + .setAddPermission(true) + .setWritePermission(true) + .setCreatePermission(true) + .setDeletePermission(true) + .setAddPermission(true); + OffsetDateTime startTime = OffsetDateTime.now().minusDays(1); + OffsetDateTime expiryTime = OffsetDateTime.now().plusDays(1); + IPRange ipRange = new IPRange() + .setIpMin("0.0.0.0") + .setIpMax("255.255.255.255"); + SASProtocol sasProtocol = SASProtocol.HTTPS_HTTP; + String cacheControl = "cache"; + String contentDisposition = "disposition"; + String contentEncoding = "encoding"; + String contentLanguage = "language"; + String contentType = "type"; + String version = Constants.HeaderConstants.TARGET_STORAGE_VERSION; + String accountName = "accountName"; + UserDelegationKey userDelegationKey = new UserDelegationKey(); + + String sas = client.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime, + startTime, version, sasProtocol, ipRange, cacheControl, contentDisposition, contentEncoding, + contentLanguage, contentType); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.generateUserDelegationSAS#UserDelegationKey-String-BlobSASPermission-OffsetDateTime-OffsetDateTime-String-SASProtocol-IPRange-String-String-String-String-String + } + + /** + * Code snippet for {@link BlobAsyncClientBase#generateSAS(String, BlobSASPermission, OffsetDateTime, OffsetDateTime, + * String, SASProtocol, IPRange, String, String, String, String, String)} + */ + public void generateSASCodeSnippets() { + // BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.generateSAS#String-BlobSASPermission-OffsetDateTime-OffsetDateTime-String-SASProtocol-IPRange-String-String-String-String-String + BlobSASPermission permissions = new BlobSASPermission() + .setReadPermission(true) + .setWritePermission(true) + .setCreatePermission(true) + .setDeletePermission(true) + .setAddPermission(true); + OffsetDateTime startTime = OffsetDateTime.now().minusDays(1); + OffsetDateTime expiryTime = OffsetDateTime.now().plusDays(1); + IPRange ipRange = new IPRange() + .setIpMin("0.0.0.0") + .setIpMax("255.255.255.255"); + SASProtocol sasProtocol = SASProtocol.HTTPS_HTTP; + String cacheControl = "cache"; + String contentDisposition = "disposition"; + String contentEncoding = "encoding"; + String contentLanguage = "language"; + String contentType = "type"; + String identifier = "identifier"; + String version = Constants.HeaderConstants.TARGET_STORAGE_VERSION; + + // Note either "identifier", or "expiryTime and permissions" are required to be set + String sas = client.generateSAS(identifier, permissions, expiryTime, startTime, version, sasProtocol, ipRange, + cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); + // END: com.azure.storage.blob.specialized.BlobAsyncClientBase.generateSAS#String-BlobSASPermission-OffsetDateTime-OffsetDateTime-String-SASProtocol-IPRange-String-String-String-String-String + } +} diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/BlobClientBaseJavaDocCodeSnippets.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/BlobClientBaseJavaDocCodeSnippets.java new file mode 100644 index 000000000000..fff7e9bb1b71 --- /dev/null +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/BlobClientBaseJavaDocCodeSnippets.java @@ -0,0 +1,461 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.specialized; + +import com.azure.core.util.Context; +import com.azure.storage.blob.BlobProperties; +import com.azure.storage.blob.BlobSASPermission; +import com.azure.storage.blob.models.AccessTier; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.DeleteSnapshotsOptionType; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.RehydratePriority; +import com.azure.storage.blob.models.ReliableDownloadOptions; +import com.azure.storage.blob.models.StorageAccountInfo; +import com.azure.storage.blob.models.UserDelegationKey; +import com.azure.storage.common.Constants; +import com.azure.storage.common.IPRange; +import com.azure.storage.common.SASProtocol; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.time.Duration; +import java.time.OffsetDateTime; +import java.util.Collections; + +/** + * Code snippets for {@link BlobClientBase} + */ +@SuppressWarnings("unused") +public class BlobClientBaseJavaDocCodeSnippets { + private BlobClientBase client = new BlobClientBase(null); + private String leaseId = "leaseId"; + private String copyId = "copyId"; + private URL url = new URL("https://sample.com"); + private String file = "file"; + private Duration timeout = Duration.ofSeconds(30); + private String key1 = "key1"; + private String key2 = "key2"; + private String value1 = "val1"; + private String value2 = "val2"; + + /** + * @throws MalformedURLException Ignore + */ + public BlobClientBaseJavaDocCodeSnippets() throws MalformedURLException { + } + + /** + * Code snippets for {@link BlobClientBase#exists()} + */ + public void existsCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.exists + System.out.printf("Exists? %b%n", client.exists()); + // END: com.azure.storage.blob.specialized.BlobClientBase.exists + } + + /** + * Code snippets for {@link BlobClientBase#startCopyFromURL(URL)} + */ + public void startCopyFromURL() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.startCopyFromURL#URL + System.out.printf("Copy identifier: %s%n", client.startCopyFromURL(url)); + // END: com.azure.storage.blob.specialized.BlobClientBase.startCopyFromURL#URL + } + + /** + * Code snippets for {@link BlobClientBase#abortCopyFromURL(String)} + */ + public void abortCopyFromURL() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.abortCopyFromURL#String + client.abortCopyFromURL(copyId); + System.out.println("Aborted copy completed."); + // END: com.azure.storage.blob.specialized.BlobClientBase.abortCopyFromURL#String + } + + /** + * Code snippets for {@link BlobClientBase#copyFromURL(URL)} + */ + public void copyFromURL() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.copyFromURL#URL + System.out.printf("Copy identifier: %s%n", client.copyFromURL(url)); + // END: com.azure.storage.blob.specialized.BlobClientBase.copyFromURL#URL + } + + /** + * Code snippets for {@link BlobClientBase#download(OutputStream)} + */ + public void download() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.download#OutputStream + client.download(new ByteArrayOutputStream()); + System.out.println("Download completed."); + // END: com.azure.storage.blob.specialized.BlobClientBase.download#OutputStream + } + + /** + * Code snippets for {@link BlobClientBase#downloadToFile(String)} and + * {@link BlobClientBase#downloadToFile(String, BlobRange, Integer, ReliableDownloadOptions, BlobAccessConditions, + * boolean, Duration, Context)} + */ + public void downloadToFile() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.downloadToFile#String + client.downloadToFile(file); + System.out.println("Completed download to file"); + // END: com.azure.storage.blob.specialized.BlobClientBase.downloadToFile#String + + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.downloadToFile#String-BlobRange-Integer-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration-Context + BlobRange range = new BlobRange(1024, 2048L); + ReliableDownloadOptions options = new ReliableDownloadOptions().maxRetryRequests(5); + + client.downloadToFile(file, range, 4 * Constants.MB, options, null, false, timeout, new Context(key2, value2)); + System.out.println("Completed download to file"); + // END: com.azure.storage.blob.specialized.BlobClientBase.downloadToFile#String-BlobRange-Integer-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration-Context + } + + /** + * Code snippets for {@link BlobClientBase#delete()} + */ + public void setDelete() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.delete + client.delete(); + System.out.println("Delete completed."); + // END: com.azure.storage.blob.specialized.BlobClientBase.delete + } + + /** + * Code snippets for {@link BlobClientBase#getProperties()} + */ + public void getProperties() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.getProperties + BlobProperties properties = client.getProperties(); + System.out.printf("Type: %s, Size: %d%n", properties.getBlobType(), properties.getBlobSize()); + // END: com.azure.storage.blob.specialized.BlobClientBase.getProperties + } + + /** + * Code snippets for {@link BlobClientBase#setHTTPHeaders(BlobHTTPHeaders)} + */ + public void setHTTPHeaders() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.setHTTPHeaders#BlobHTTPHeaders + client.setHTTPHeaders(new BlobHTTPHeaders() + .setBlobContentLanguage("en-US") + .setBlobContentType("binary")); + System.out.println("Set HTTP headers completed"); + // END: com.azure.storage.blob.specialized.BlobClientBase.setHTTPHeaders#BlobHTTPHeaders + } + + /** + * Code snippets for {@link BlobClientBase#setMetadata(Metadata)} + */ + public void setMetadata() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.setMetadata#Metadata + client.setMetadata(new Metadata(Collections.singletonMap("metadata", "value"))); + System.out.println("Set metadata completed"); + // END: com.azure.storage.blob.specialized.BlobClientBase.setMetadata#Metadata + } + + /** + * Code snippets for {@link BlobClientBase#createSnapshot()} + */ + public void createSnapshot() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.createSnapshot + System.out.printf("Identifier for the snapshot is %s%n", client.createSnapshot().getSnapshotId()); + // END: com.azure.storage.blob.specialized.BlobClientBase.createSnapshot + } + + /** + * Code snippets for {@link BlobClientBase#setTier(AccessTier)} and + * {@link BlobClientBase#setTierWithResponse(AccessTier, RehydratePriority, LeaseAccessConditions, Duration, Context)} + */ + public void setTier() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.setTier#AccessTier + System.out.printf("Set tier completed with status code %d%n", + client.setTierWithResponse(AccessTier.HOT, null, null, null, null).getStatusCode()); + // END: com.azure.storage.blob.specialized.BlobClientBase.setTier#AccessTier + + + } + + /** + * Code snippets for {@link BlobClientBase#undelete()} + */ + public void unsetDelete() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.undelete + client.undelete(); + System.out.println("Undelete completed"); + // END: com.azure.storage.blob.specialized.BlobClientBase.undelete + } + + /** + * Code snippet for {@link BlobClientBase#getAccountInfo()} + */ + public void getAccountInfo() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.getAccountInfo + StorageAccountInfo accountInfo = client.getAccountInfo(); + System.out.printf("Account Kind: %s, SKU: %s%n", accountInfo.getAccountKind(), accountInfo.getSkuName()); + // END: com.azure.storage.blob.specialized.BlobClientBase.getAccountInfo + } + + /** + * Code snippet for {@link BlobClientBase#existsWithResponse(Duration, Context)} + */ + public void existsWithResponseCodeSnippet() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.existsWithResponse#Duration-Context + System.out.printf("Exists? %b%n", client.existsWithResponse(timeout, new Context(key2, value2)).getValue()); + // END: com.azure.storage.blob.specialized.BlobClientBase.existsWithResponse#Duration-Context + } + + /** + * Code snippets for {@link BlobClientBase#startCopyFromURLWithResponse(URL, Metadata, AccessTier, RehydratePriority, + * ModifiedAccessConditions, BlobAccessConditions, Duration, Context)} + */ + public void startCopyFromURLWithResponseCodeSnippets() { + + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.startCopyFromURLWithResponse#URL-Metadata-AccessTier-RehydratePriority-ModifiedAccessConditions-BlobAccessConditions-Duration-Context + Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .setIfUnmodifiedSince(OffsetDateTime.now().minusDays(7)); + BlobAccessConditions blobAccessConditions = new BlobAccessConditions().setLeaseAccessConditions( + new LeaseAccessConditions().setLeaseId(leaseId)); + + System.out.printf("Copy identifier: %s%n", + client.startCopyFromURLWithResponse(url, metadata, AccessTier.HOT, RehydratePriority.STANDARD, + modifiedAccessConditions, blobAccessConditions, timeout, + new Context(key2, value2))); + // END: com.azure.storage.blob.specialized.BlobClientBase.startCopyFromURLWithResponse#URL-Metadata-AccessTier-RehydratePriority-ModifiedAccessConditions-BlobAccessConditions-Duration-Context + } + + /** + * Code snippets for {@link BlobClientBase#abortCopyFromURLWithResponse(String, LeaseAccessConditions, Duration, Context)} + */ + public void abortCopyFromURLWithResponseCodeSnippets() { + + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.abortCopyFromURLWithResponse#String-LeaseAccessConditions-Duration-Context + LeaseAccessConditions leaseAccessConditions = new LeaseAccessConditions().setLeaseId(leaseId); + System.out.printf("Aborted copy completed with status %d%n", + client.abortCopyFromURLWithResponse(copyId, leaseAccessConditions, timeout, + new Context(key2, value2)).getStatusCode()); + // END: com.azure.storage.blob.specialized.BlobClientBase.abortCopyFromURLWithResponse#String-LeaseAccessConditions-Duration-Context + } + + /** + * Code snippets for {@link BlobClientBase#copyFromURLWithResponse(URL, Metadata, AccessTier, ModifiedAccessConditions, + * BlobAccessConditions, Duration, Context)} + */ + public void copyFromURLWithResponseCodeSnippets() { + + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.copyFromURLWithResponse#URL-Metadata-AccessTier-ModifiedAccessConditions-BlobAccessConditions-Duration-Context + Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .setIfUnmodifiedSince(OffsetDateTime.now().minusDays(7)); + BlobAccessConditions blobAccessConditions = new BlobAccessConditions().setLeaseAccessConditions( + new LeaseAccessConditions().setLeaseId(leaseId)); + + System.out.printf("Copy identifier: %s%n", + client.copyFromURLWithResponse(url, metadata, AccessTier.HOT, modifiedAccessConditions, + blobAccessConditions, timeout, + new Context(key1, value1)).getValue()); + // END: com.azure.storage.blob.specialized.BlobClientBase.copyFromURLWithResponse#URL-Metadata-AccessTier-ModifiedAccessConditions-BlobAccessConditions-Duration-Context + } + + /** + * Code snippets for {@link BlobClientBase#downloadWithResponse(OutputStream, BlobRange, ReliableDownloadOptions, + * BlobAccessConditions, boolean, Duration, Context)} + * @throws UncheckedIOException If an I/O error occurs + */ + public void downloadWithResponseCodeSnippets() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.downloadWithResponse#OutputStream-BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration-Context + BlobRange range = new BlobRange(1024, 2048L); + ReliableDownloadOptions options = new ReliableDownloadOptions().maxRetryRequests(5); + + System.out.printf("Download completed with status %d%n", + client.downloadWithResponse(new ByteArrayOutputStream(), range, options, null, false, + timeout, new Context(key2, value2)).getStatusCode()); + // END: com.azure.storage.blob.specialized.BlobClientBase.downloadWithResponse#OutputStream-BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration-Context + + } + + /** + * Code snippets for {@link BlobClientBase#deleteWithResponse(DeleteSnapshotsOptionType, BlobAccessConditions, Duration, + * Context)} + */ + public void deleteWithResponseCodeSnippets() { + + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.deleteWithResponse#DeleteSnapshotsOptionType-BlobAccessConditions-Duration-Context + System.out.printf("Delete completed with status %d%n", + client.deleteWithResponse(DeleteSnapshotsOptionType.INCLUDE, null, timeout, + new Context(key1, value1)).getStatusCode()); + // END: com.azure.storage.blob.specialized.BlobClientBase.deleteWithResponse#DeleteSnapshotsOptionType-BlobAccessConditions-Duration-Context + } + + /** + * Code snippets for {@link BlobClientBase#getPropertiesWithResponse(BlobAccessConditions, Duration, Context)} + */ + public void getPropertiesWithResponseCodeSnippets() { + + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.getPropertiesWithResponse#BlobAccessConditions-Duration-Context + BlobAccessConditions accessConditions = new BlobAccessConditions() + .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseId)); + + BlobProperties properties = client.getPropertiesWithResponse(accessConditions, timeout, + new Context(key2, value2)).getValue(); + System.out.printf("Type: %s, Size: %d%n", properties.getBlobType(), properties.getBlobSize()); + // END: com.azure.storage.blob.specialized.BlobClientBase.getPropertiesWithResponse#BlobAccessConditions-Duration-Context + } + + /** + * Code snippets for {@link BlobClientBase#setHTTPHeadersWithResponse(BlobHTTPHeaders, BlobAccessConditions, Duration, + * Context)} + */ + public void setHTTPHeadersWithResponseCodeSnippets() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.setHTTPHeadersWithResponse#BlobHTTPHeaders-BlobAccessConditions-Duration-Context + BlobAccessConditions accessConditions = new BlobAccessConditions() + .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseId)); + + System.out.printf("Set HTTP headers completed with status %d%n", + client.setHTTPHeadersWithResponse(new BlobHTTPHeaders() + .setBlobContentLanguage("en-US") + .setBlobContentType("binary"), accessConditions, timeout, new Context(key1, value1)) + .getStatusCode()); + // END: com.azure.storage.blob.specialized.BlobClientBase.setHTTPHeadersWithResponse#BlobHTTPHeaders-BlobAccessConditions-Duration-Context + } + + /** + * Code snippets for {@link BlobClientBase#setMetadataWithResponse(Metadata, BlobAccessConditions, Duration, Context)} + */ + public void setMetadataWithResponseCodeSnippets() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.setMetadataWithResponse#Metadata-BlobAccessConditions-Duration-Context + BlobAccessConditions accessConditions = new BlobAccessConditions().setLeaseAccessConditions( + new LeaseAccessConditions().setLeaseId(leaseId)); + + System.out.printf("Set metadata completed with status %d%n", + client.setMetadataWithResponse( + new Metadata(Collections.singletonMap("metadata", "value")), accessConditions, timeout, + new Context(key1, value1)).getStatusCode()); + // END: com.azure.storage.blob.specialized.BlobClientBase.setMetadataWithResponse#Metadata-BlobAccessConditions-Duration-Context + } + + /** + * Code snippets for {@link BlobClientBase#createSnapshotWithResponse(Metadata, BlobAccessConditions, Duration, + * Context)} + */ + public void createSnapshotWithResponseCodeSnippets() { + + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.createSnapshotWithResponse#Metadata-BlobAccessConditions-Duration-Context + Metadata snapshotMetadata = new Metadata(Collections.singletonMap("metadata", "value")); + BlobAccessConditions accessConditions = new BlobAccessConditions().setLeaseAccessConditions( + new LeaseAccessConditions().setLeaseId(leaseId)); + + System.out.printf("Identifier for the snapshot is %s%n", + client.createSnapshotWithResponse(snapshotMetadata, accessConditions, timeout, + new Context(key1, value1)).getValue()); + // END: com.azure.storage.blob.specialized.BlobClientBase.createSnapshotWithResponse#Metadata-BlobAccessConditions-Duration-Context + } + + /** + * Code snippets for {@link BlobClientBase#setTierWithResponse(AccessTier, RehydratePriority, LeaseAccessConditions, + * Duration, Context)} + */ + public void setTierWithResponseCodeSnippets() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.setTierWithResponse#AccessTier-RehydratePriority-LeaseAccessConditions-Duration-Context + LeaseAccessConditions accessConditions = new LeaseAccessConditions().setLeaseId(leaseId); + + System.out.printf("Set tier completed with status code %d%n", + client.setTierWithResponse(AccessTier.HOT, RehydratePriority.STANDARD, accessConditions, timeout, + new Context(key2, value2)).getStatusCode()); + // END: com.azure.storage.blob.specialized.BlobClientBase.setTierWithResponse#AccessTier-RehydratePriority-LeaseAccessConditions-Duration-Context + } + + /** + * Code snippet for {@link BlobClientBase#undeleteWithResponse(Duration, Context)} + */ + public void undeleteWithResponseCodeSnippets() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.undeleteWithResponse#Duration-Context + System.out.printf("Undelete completed with status %d%n", client.undeleteWithResponse(timeout, + new Context(key1, value1)).getStatusCode()); + // END: com.azure.storage.blob.specialized.BlobClientBase.undeleteWithResponse#Duration-Context + } + + /** + * Code snippet for {@link BlobClientBase#getAccountInfoWithResponse(Duration, Context)} + */ + public void getAccountInfoWithResponseCodeSnippets() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.getAccountInfoWithResponse#Duration-Context + StorageAccountInfo accountInfo = client.getAccountInfoWithResponse(timeout, new Context(key1, value1)).getValue(); + System.out.printf("Account Kind: %s, SKU: %s%n", accountInfo.getAccountKind(), accountInfo.getSkuName()); + // END: com.azure.storage.blob.specialized.BlobClientBase.getAccountInfoWithResponse#Duration-Context + } + + /** + * Code snippet for {@link BlobClientBase#generateUserDelegationSAS(UserDelegationKey, String, BlobSASPermission, + * OffsetDateTime, OffsetDateTime, String, SASProtocol, IPRange, String, String, String, String, String)} + */ + public void generateUserDelegationSASCodeSnippets() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.generateUserDelegationSAS#UserDelegationKey-String-BlobSASPermission-OffsetDateTime-OffsetDateTime-String-SASProtocol-IPRange-String-String-String-String-String + BlobSASPermission permissions = new BlobSASPermission() + .setReadPermission(true) + .setWritePermission(true) + .setCreatePermission(true) + .setDeletePermission(true) + .setAddPermission(true); + OffsetDateTime startTime = OffsetDateTime.now().minusDays(1); + OffsetDateTime expiryTime = OffsetDateTime.now().plusDays(1); + IPRange ipRange = new IPRange() + .setIpMin("0.0.0.0") + .setIpMax("255.255.255.255"); + SASProtocol sasProtocol = SASProtocol.HTTPS_HTTP; + String cacheControl = "cache"; + String contentDisposition = "disposition"; + String contentEncoding = "encoding"; + String contentLanguage = "language"; + String contentType = "type"; + String version = Constants.HeaderConstants.TARGET_STORAGE_VERSION; + UserDelegationKey userDelegationKey = new UserDelegationKey(); + String accountName = "accountName"; + + String sas = client.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime, + startTime, version, sasProtocol, ipRange, cacheControl, contentDisposition, contentEncoding, + contentLanguage, contentType); + // END: com.azure.storage.blob.specialized.BlobClientBase.generateUserDelegationSAS#UserDelegationKey-String-BlobSASPermission-OffsetDateTime-OffsetDateTime-String-SASProtocol-IPRange-String-String-String-String-String + } + + /** + * Code snippet for {@link BlobClientBase#generateSAS(String, BlobSASPermission, OffsetDateTime, OffsetDateTime, String, + * SASProtocol, IPRange, String, String, String, String, String)} + */ + public void generateSASCodeSnippets() { + // BEGIN: com.azure.storage.blob.specialized.BlobClientBase.generateSAS#String-BlobSASPermission-OffsetDateTime-OffsetDateTime-String-SASProtocol-IPRange-String-String-String-String-String + BlobSASPermission permissions = new BlobSASPermission() + .setReadPermission(true) + .setWritePermission(true) + .setCreatePermission(true) + .setDeletePermission(true) + .setAddPermission(true); + OffsetDateTime startTime = OffsetDateTime.now().minusDays(1); + OffsetDateTime expiryTime = OffsetDateTime.now().plusDays(1); + IPRange ipRange = new IPRange() + .setIpMin("0.0.0.0") + .setIpMax("255.255.255.255"); + SASProtocol sasProtocol = SASProtocol.HTTPS_HTTP; + String cacheControl = "cache"; + String contentDisposition = "disposition"; + String contentEncoding = "encoding"; + String contentLanguage = "language"; + String contentType = "type"; + String identifier = "identifier"; + String version = Constants.HeaderConstants.TARGET_STORAGE_VERSION; + + // Note either "identifier", or "expiryTime and permissions" are required to be set + String sas = client.generateSAS(identifier, permissions, expiryTime, startTime, version, sasProtocol, ipRange, + cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); + // END: com.azure.storage.blob.specialized.BlobClientBase.generateSAS#String-BlobSASPermission-OffsetDateTime-OffsetDateTime-String-SASProtocol-IPRange-String-String-String-String-String + } +} diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlockBlobAsyncClientJavaDocCodeSnippets.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/BlockBlobAsyncClientJavaDocCodeSnippets.java similarity index 73% rename from sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlockBlobAsyncClientJavaDocCodeSnippets.java rename to sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/BlockBlobAsyncClientJavaDocCodeSnippets.java index 992a0f598a6d..83e97f80e488 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlockBlobAsyncClientJavaDocCodeSnippets.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/BlockBlobAsyncClientJavaDocCodeSnippets.java @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; import com.azure.storage.blob.models.AccessTier; import com.azure.storage.blob.models.BlobAccessConditions; @@ -15,6 +15,7 @@ import com.azure.storage.blob.models.SourceModifiedAccessConditions; import reactor.core.publisher.Flux; +import java.net.MalformedURLException; import java.net.URL; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -28,42 +29,40 @@ */ @SuppressWarnings({"unused"}) public class BlockBlobAsyncClientJavaDocCodeSnippets { - private BlockBlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient("blobName") - .asBlockBlobAsyncClient(); - + private BlockBlobAsyncClient client = new SpecializedBlobClientBuilder().buildBlockBlobAsyncClient(); private Flux data = Flux.just(ByteBuffer.wrap("data".getBytes(StandardCharsets.UTF_8))); private long length = 4L; private String leaseId = "leaseId"; private String filePath = "filePath"; private String base64BlockID = "base64BlockID"; - private URL sourceURL = JavaDocCodeSnippetsHelpers.generateURL("https://example.com"); + private URL sourceURL = new URL("https://example.com"); private long offset = 1024L; private long count = length; private int blockSize = 50; private int numBuffers = 2; /** - * + * @throws MalformedURLException Ignore */ - public BlockBlobAsyncClientJavaDocCodeSnippets() { + public BlockBlobAsyncClientJavaDocCodeSnippets() throws MalformedURLException { } /** * Code snippet for {@link BlockBlobAsyncClient#upload(Flux, long)} */ public void upload() { - // BEGIN: com.azure.storage.blob.BlockBlobAsyncClient.upload#Flux-long + // BEGIN: com.azure.storage.blob.specialized.BlockBlobAsyncClient.upload#Flux-long client.upload(data, length).subscribe(response -> System.out.printf("Uploaded BlockBlob MD5 is %s%n", Base64.getEncoder().encodeToString(response.getContentMD5()))); - // END: com.azure.storage.blob.BlockBlobAsyncClient.upload#Flux-long + // END: com.azure.storage.blob.specialized.BlockBlobAsyncClient.upload#Flux-long } /** * Code snippet for {@link BlockBlobAsyncClient#uploadWithResponse(Flux, long, BlobHTTPHeaders, Metadata, AccessTier, BlobAccessConditions)} */ public void upload2() { - // BEGIN: com.azure.storage.blob.BlockBlobAsyncClient.uploadWithResponse#Flux-long-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions + // BEGIN: com.azure.storage.blob.specialized.BlockBlobAsyncClient.uploadWithResponse#Flux-long-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions BlobHTTPHeaders headers = new BlobHTTPHeaders() .setBlobContentMD5("data".getBytes(StandardCharsets.UTF_8)) .setBlobContentLanguage("en-US") @@ -78,25 +77,25 @@ public void upload2() { client.uploadWithResponse(data, length, headers, metadata, AccessTier.HOT, accessConditions) .subscribe(response -> System.out.printf("Uploaded BlockBlob MD5 is %s%n", Base64.getEncoder().encodeToString(response.getValue().getContentMD5()))); - // END: com.azure.storage.blob.BlockBlobAsyncClient.uploadWithResponse#Flux-long-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions + // END: com.azure.storage.blob.specialized.BlockBlobAsyncClient.uploadWithResponse#Flux-long-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions } /** * Code snippet for {@link BlockBlobAsyncClient#upload(Flux, int, int)} */ public void upload3() { - // BEGIN: com.azure.storage.blob.BlockBlobAsyncClient.upload#Flux-int-int + // BEGIN: com.azure.storage.blob.specialized.BlockBlobAsyncClient.upload#Flux-int-int client.upload(data, blockSize, numBuffers).subscribe(response -> System.out.printf("Uploaded BlockBlob MD5 is %s%n", Base64.getEncoder().encodeToString(response.getContentMD5()))); - // END: com.azure.storage.blob.BlockBlobAsyncClient.upload#Flux-int-int + // END: com.azure.storage.blob.specialized.BlockBlobAsyncClient.upload#Flux-int-int } /** * Code snippet for {@link BlockBlobAsyncClient#uploadWithResponse(Flux, int, int, BlobHTTPHeaders, Metadata, AccessTier, BlobAccessConditions)} */ public void upload4() { - // BEGIN: com.azure.storage.blob.BlockBlobAsyncClient.uploadWithResponse#Flux-int-int-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions + // BEGIN: com.azure.storage.blob.specialized.BlockBlobAsyncClient.uploadWithResponse#Flux-int-int-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions BlobHTTPHeaders headers = new BlobHTTPHeaders() .setBlobContentMD5("data".getBytes(StandardCharsets.UTF_8)) .setBlobContentLanguage("en-US") @@ -111,25 +110,25 @@ public void upload4() { client.uploadWithResponse(data, blockSize, numBuffers, headers, metadata, AccessTier.HOT, accessConditions) .subscribe(response -> System.out.printf("Uploaded BlockBlob MD5 is %s%n", Base64.getEncoder().encodeToString(response.getValue().getContentMD5()))); - // END: com.azure.storage.blob.BlockBlobAsyncClient.uploadWithResponse#Flux-int-int-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions + // END: com.azure.storage.blob.specialized.BlockBlobAsyncClient.uploadWithResponse#Flux-int-int-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions } /** * Code snippet for {@link BlockBlobAsyncClient#uploadFromFile(String)} */ public void uploadFromFile() { - // BEGIN: com.azure.storage.blob.BlockBlobAsyncClient.uploadFromFile#String + // BEGIN: com.azure.storage.blob.specialized.BlockBlobAsyncClient.uploadFromFile#String client.uploadFromFile(filePath) .doOnError(throwable -> System.err.printf("Failed to upload from file %s%n", throwable.getMessage())) .subscribe(completion -> System.out.println("Upload from file succeeded")); - // END: com.azure.storage.blob.BlockBlobAsyncClient.uploadFromFile#String + // END: com.azure.storage.blob.specialized.BlockBlobAsyncClient.uploadFromFile#String } /** * Code snippet for {@link BlockBlobAsyncClient#uploadFromFile(String, Integer, BlobHTTPHeaders, Metadata, AccessTier, BlobAccessConditions)} */ public void uploadFromFile2() { - // BEGIN: com.azure.storage.blob.BlockBlobAsyncClient.uploadFromFile#String-Integer-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions + // BEGIN: com.azure.storage.blob.specialized.BlockBlobAsyncClient.uploadFromFile#String-Integer-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions BlobHTTPHeaders headers = new BlobHTTPHeaders() .setBlobContentMD5("data".getBytes(StandardCharsets.UTF_8)) .setBlobContentLanguage("en-US") @@ -145,49 +144,49 @@ public void uploadFromFile2() { headers, metadata, AccessTier.HOT, accessConditions) .doOnError(throwable -> System.err.printf("Failed to upload from file %s%n", throwable.getMessage())) .subscribe(completion -> System.out.println("Upload from file succeeded")); - // END: com.azure.storage.blob.BlockBlobAsyncClient.uploadFromFile#String-Integer-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions + // END: com.azure.storage.blob.specialized.BlockBlobAsyncClient.uploadFromFile#String-Integer-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions } /** * Code snippet for {@link BlockBlobAsyncClient#stageBlock(String, Flux, long)} */ public void stageBlock() { - // BEGIN: com.azure.storage.blob.BlockBlobAsyncClient.stageBlock#String-Flux-long + // BEGIN: com.azure.storage.blob.specialized.BlockBlobAsyncClient.stageBlock#String-Flux-long client.stageBlock(base64BlockID, data, length) .subscribe( response -> System.out.println("Staging block completed"), error -> System.out.printf("Error when calling stage Block: %s", error)); - // END: com.azure.storage.blob.BlockBlobAsyncClient.stageBlock#String-Flux-long + // END: com.azure.storage.blob.specialized.BlockBlobAsyncClient.stageBlock#String-Flux-long } /** * Code snippet for {@link BlockBlobAsyncClient#stageBlockWithResponse(String, Flux, long, LeaseAccessConditions)} */ public void stageBlock2() { - // BEGIN: com.azure.storage.blob.BlockBlobAsyncClient.stageBlockWithResponse#String-Flux-long-LeaseAccessConditions + // BEGIN: com.azure.storage.blob.specialized.BlockBlobAsyncClient.stageBlockWithResponse#String-Flux-long-LeaseAccessConditions LeaseAccessConditions accessConditions = new LeaseAccessConditions().setLeaseId(leaseId); client.stageBlockWithResponse(base64BlockID, data, length, accessConditions).subscribe(response -> System.out.printf("Staging block completed with status %d%n", response.getStatusCode())); - // END: com.azure.storage.blob.BlockBlobAsyncClient.stageBlockWithResponse#String-Flux-long-LeaseAccessConditions + // END: com.azure.storage.blob.specialized.BlockBlobAsyncClient.stageBlockWithResponse#String-Flux-long-LeaseAccessConditions } /** * Code snippet for {@link BlockBlobAsyncClient#stageBlockFromURL(String, URL, BlobRange)} */ public void stageBlockFromURL() { - // BEGIN: com.azure.storage.blob.BlockBlobAsyncClient.stageBlockFromURL#String-URL-BlobRange + // BEGIN: com.azure.storage.blob.specialized.BlockBlobAsyncClient.stageBlockFromURL#String-URL-BlobRange client.stageBlockFromURL(base64BlockID, sourceURL, new BlobRange(offset, count)) .subscribe( response -> System.out.println("Staging block completed"), error -> System.out.printf("Error when calling stage Block: %s", error)); - // END: com.azure.storage.blob.BlockBlobAsyncClient.stageBlockFromURL#String-URL-BlobRange + // END: com.azure.storage.blob.specialized.BlockBlobAsyncClient.stageBlockFromURL#String-URL-BlobRange } /** * Code snippet for {@link BlockBlobAsyncClient#stageBlockFromURLWithResponse(String, URL, BlobRange, byte[], LeaseAccessConditions, SourceModifiedAccessConditions)} */ public void stageBlockFromURL2() { - // BEGIN: com.azure.storage.blob.BlockBlobAsyncClient.stageBlockFromURLWithResponse#String-URL-BlobRange-byte-LeaseAccessConditions-SourceModifiedAccessConditions + // BEGIN: com.azure.storage.blob.specialized.BlockBlobAsyncClient.stageBlockFromURLWithResponse#String-URL-BlobRange-byte-LeaseAccessConditions-SourceModifiedAccessConditions LeaseAccessConditions leaseAccessConditions = new LeaseAccessConditions().setLeaseId(leaseId); SourceModifiedAccessConditions sourceModifiedAccessConditions = new SourceModifiedAccessConditions() .setSourceIfUnmodifiedSince(OffsetDateTime.now().minusDays(3)); @@ -195,14 +194,14 @@ public void stageBlockFromURL2() { client.stageBlockFromURLWithResponse(base64BlockID, sourceURL, new BlobRange(offset, count), null, leaseAccessConditions, sourceModifiedAccessConditions).subscribe(response -> System.out.printf("Staging block from URL completed with status %d%n", response.getStatusCode())); - // END: com.azure.storage.blob.BlockBlobAsyncClient.stageBlockFromURLWithResponse#String-URL-BlobRange-byte-LeaseAccessConditions-SourceModifiedAccessConditions + // END: com.azure.storage.blob.specialized.BlockBlobAsyncClient.stageBlockFromURLWithResponse#String-URL-BlobRange-byte-LeaseAccessConditions-SourceModifiedAccessConditions } /** * Code snippet for {@link BlockBlobAsyncClient#listBlocks(BlockListType)} */ public void listBlocks() { - // BEGIN: com.azure.storage.blob.BlockBlobAsyncClient.listBlocks#BlockListType + // BEGIN: com.azure.storage.blob.specialized.BlockBlobAsyncClient.listBlocks#BlockListType client.listBlocks(BlockListType.ALL).subscribe(block -> { System.out.println("Committed Blocks:"); block.getCommittedBlocks().forEach(b -> System.out.printf("Name: %s, Size: %d", b.getName(), b.getSize())); @@ -210,14 +209,14 @@ public void listBlocks() { System.out.println("Uncommitted Blocks:"); block.getUncommittedBlocks().forEach(b -> System.out.printf("Name: %s, Size: %d", b.getName(), b.getSize())); }); - // END: com.azure.storage.blob.BlockBlobAsyncClient.listBlocks#BlockListType + // END: com.azure.storage.blob.specialized.BlockBlobAsyncClient.listBlocks#BlockListType } /** * Code snippet for {@link BlockBlobAsyncClient#listBlocksWithResponse(BlockListType, LeaseAccessConditions)} */ public void listBlocks2() { - // BEGIN: com.azure.storage.blob.BlockBlobAsyncClient.listBlocksWithResponse#BlockListType-LeaseAccessConditions + // BEGIN: com.azure.storage.blob.specialized.BlockBlobAsyncClient.listBlocksWithResponse#BlockListType-LeaseAccessConditions LeaseAccessConditions accessConditions = new LeaseAccessConditions().setLeaseId(leaseId); client.listBlocksWithResponse(BlockListType.ALL, accessConditions).subscribe(response -> { @@ -228,24 +227,24 @@ public void listBlocks2() { System.out.println("Uncommitted Blocks:"); block.getUncommittedBlocks().forEach(b -> System.out.printf("Name: %s, Size: %d", b.getName(), b.getSize())); }); - // END: com.azure.storage.blob.BlockBlobAsyncClient.listBlocksWithResponse#BlockListType-LeaseAccessConditions + // END: com.azure.storage.blob.specialized.BlockBlobAsyncClient.listBlocksWithResponse#BlockListType-LeaseAccessConditions } /** * Code snippet for {@link BlockBlobAsyncClient#commitBlockList(List)} */ public void commitBlockList() { - // BEGIN: com.azure.storage.blob.BlockBlobAsyncClient.commitBlockList#List + // BEGIN: com.azure.storage.blob.specialized.BlockBlobAsyncClient.commitBlockList#List client.commitBlockList(Collections.singletonList(base64BlockID)).subscribe(response -> System.out.printf("Committing block list completed. Last modified: %s%n", response.getLastModified())); - // END: com.azure.storage.blob.BlockBlobAsyncClient.commitBlockList#List + // END: com.azure.storage.blob.specialized.BlockBlobAsyncClient.commitBlockList#List } /** * Code snippet for {@link BlockBlobAsyncClient#commitBlockListWithResponse(List, BlobHTTPHeaders, Metadata, AccessTier, BlobAccessConditions)} */ public void commitBlockList2() { - // BEGIN: com.azure.storage.blob.BlockBlobAsyncClient.commitBlockListWithResponse#List-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions + // BEGIN: com.azure.storage.blob.specialized.BlockBlobAsyncClient.commitBlockListWithResponse#List-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions BlobHTTPHeaders headers = new BlobHTTPHeaders() .setBlobContentMD5("data".getBytes(StandardCharsets.UTF_8)) .setBlobContentLanguage("en-US") @@ -259,6 +258,6 @@ public void commitBlockList2() { client.commitBlockListWithResponse(Collections.singletonList(base64BlockID), headers, metadata, AccessTier.HOT, accessConditions).subscribe(response -> System.out.printf("Committing block list completed with status %d%n", response.getStatusCode())); - // END: com.azure.storage.blob.BlockBlobAsyncClient.commitBlockListWithResponse#List-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions + // END: com.azure.storage.blob.specialized.BlockBlobAsyncClient.commitBlockListWithResponse#List-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions } } diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlockBlobClientJavaDocCodeSnippets.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/BlockBlobClientJavaDocCodeSnippets.java similarity index 72% rename from sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlockBlobClientJavaDocCodeSnippets.java rename to sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/BlockBlobClientJavaDocCodeSnippets.java index 2072fd906b0b..22fc4e61b2c5 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlockBlobClientJavaDocCodeSnippets.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/BlockBlobClientJavaDocCodeSnippets.java @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; import com.azure.core.util.Context; import com.azure.storage.blob.models.AccessTier; @@ -19,6 +19,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; +import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.time.Duration; @@ -32,23 +33,21 @@ */ @SuppressWarnings({"unused"}) public class BlockBlobClientJavaDocCodeSnippets { - private BlockBlobClient client = JavaDocCodeSnippetsHelpers.getBlobClient("blobName") - .asBlockBlobClient(); - + private BlockBlobClient client = new SpecializedBlobClientBuilder().buildBlockBlobClient(); private InputStream data = new ByteArrayInputStream("data".getBytes(StandardCharsets.UTF_8)); private long length = 4L; private Duration timeout = Duration.ofSeconds(30); private String leaseId = "leaseId"; private String filePath = "filePath"; private String base64BlockID = "base64BlockID"; - private URL sourceURL = JavaDocCodeSnippetsHelpers.generateURL("https://example.com"); + private URL sourceURL = new URL("https://example.com"); private long offset = 1024L; private long count = length; /** - * + * @throws MalformedURLException Ignore */ - public BlockBlobClientJavaDocCodeSnippets() { + public BlockBlobClientJavaDocCodeSnippets() throws MalformedURLException { } /** @@ -57,19 +56,17 @@ public BlockBlobClientJavaDocCodeSnippets() { * @throws IOException If an I/O error occurs */ public void upload() throws IOException { - // BEGIN: com.azure.storage.blob.BlockBlobClient.upload#InputStream-long + // BEGIN: com.azure.storage.blob.specialized.BlockBlobClient.upload#InputStream-long System.out.printf("Uploaded BlockBlob MD5 is %s%n", Base64.getEncoder().encodeToString(client.upload(data, length).getContentMD5())); - // END: com.azure.storage.blob.BlockBlobClient.upload#InputStream-long + // END: com.azure.storage.blob.specialized.BlockBlobClient.upload#InputStream-long } /** * Code snippet for {@link BlockBlobClient#uploadWithResponse(InputStream, long, BlobHTTPHeaders, Metadata, AccessTier, BlobAccessConditions, Duration, Context)} - * - * @throws IOException If an I/O error occurs */ - public void upload2() throws IOException { - // BEGIN: com.azure.storage.blob.BlockBlobClient.uploadWithResponse#InputStream-long-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration-Context + public void upload2() { + // BEGIN: com.azure.storage.blob.specialized.BlockBlobClient.uploadWithResponse#InputStream-long-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration-Context BlobHTTPHeaders headers = new BlobHTTPHeaders() .setBlobContentMD5("data".getBytes(StandardCharsets.UTF_8)) .setBlobContentLanguage("en-US") @@ -87,7 +84,7 @@ public void upload2() throws IOException { accessConditions, timeout, context) .getValue() .getContentMD5())); - // END: com.azure.storage.blob.BlockBlobClient.uploadWithResponse#InputStream-long-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.BlockBlobClient.uploadWithResponse#InputStream-long-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration-Context } /** @@ -96,14 +93,14 @@ public void upload2() throws IOException { * @throws IOException If an I/O error occurs */ public void uploadFromFile() throws IOException { - // BEGIN: com.azure.storage.blob.BlockBlobClient.uploadFromFile#String + // BEGIN: com.azure.storage.blob.specialized.BlockBlobClient.uploadFromFile#String try { client.uploadFromFile(filePath); System.out.println("Upload from file succeeded"); } catch (UncheckedIOException ex) { System.err.printf("Failed to upload from file %s%n", ex.getMessage()); } - // END: com.azure.storage.blob.BlockBlobClient.uploadFromFile#String + // END: com.azure.storage.blob.specialized.BlockBlobClient.uploadFromFile#String } /** @@ -112,7 +109,7 @@ public void uploadFromFile() throws IOException { * @throws IOException If an I/O error occurs */ public void uploadFromFile2() throws IOException { - // BEGIN: com.azure.storage.blob.BlockBlobClient.uploadFromFile#String-Integer-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration + // BEGIN: com.azure.storage.blob.specialized.BlockBlobClient.uploadFromFile#String-Integer-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration BlobHTTPHeaders headers = new BlobHTTPHeaders() .setBlobContentMD5("data".getBytes(StandardCharsets.UTF_8)) .setBlobContentLanguage("en-US") @@ -132,44 +129,44 @@ public void uploadFromFile2() throws IOException { } catch (UncheckedIOException ex) { System.err.printf("Failed to upload from file %s%n", ex.getMessage()); } - // END: com.azure.storage.blob.BlockBlobClient.uploadFromFile#String-Integer-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration + // END: com.azure.storage.blob.specialized.BlockBlobClient.uploadFromFile#String-Integer-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration } /** * Code snippet for {@link BlockBlobClient#stageBlock(String, InputStream, long)} */ public void stageBlock() { - // BEGIN: com.azure.storage.blob.BlockBlobClient.stageBlock#String-InputStream-long + // BEGIN: com.azure.storage.blob.specialized.BlockBlobClient.stageBlock#String-InputStream-long client.stageBlock(base64BlockID, data, length); - // END: com.azure.storage.blob.BlockBlobClient.stageBlock#String-InputStream-long + // END: com.azure.storage.blob.specialized.BlockBlobClient.stageBlock#String-InputStream-long } /** * Code snippet for {@link BlockBlobClient#stageBlockWithResponse(String, InputStream, long, LeaseAccessConditions, Duration, Context)} */ public void stageBlock2() { - // BEGIN: com.azure.storage.blob.BlockBlobClient.stageBlockWithResponse#String-InputStream-long-LeaseAccessConditions-Duration-Context + // BEGIN: com.azure.storage.blob.specialized.BlockBlobClient.stageBlockWithResponse#String-InputStream-long-LeaseAccessConditions-Duration-Context LeaseAccessConditions accessConditions = new LeaseAccessConditions().setLeaseId(leaseId); Context context = new Context("key", "value"); System.out.printf("Staging block completed with status %d%n", client.stageBlockWithResponse(base64BlockID, data, length, accessConditions, timeout, context).getStatusCode()); - // END: com.azure.storage.blob.BlockBlobClient.stageBlockWithResponse#String-InputStream-long-LeaseAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.BlockBlobClient.stageBlockWithResponse#String-InputStream-long-LeaseAccessConditions-Duration-Context } /** * Code snippet for {@link BlockBlobClient#stageBlockFromURL(String, URL, BlobRange)} */ public void stageBlockFromURL() { - // BEGIN: com.azure.storage.blob.BlockBlobClient.stageBlockFromURL#String-URL-BlobRange + // BEGIN: com.azure.storage.blob.specialized.BlockBlobClient.stageBlockFromURL#String-URL-BlobRange client.stageBlockFromURL(base64BlockID, sourceURL, new BlobRange(offset, count)); - // END: com.azure.storage.blob.BlockBlobClient.stageBlockFromURL#String-URL-BlobRange + // END: com.azure.storage.blob.specialized.BlockBlobClient.stageBlockFromURL#String-URL-BlobRange } /** * Code snippet for {@link BlockBlobClient#stageBlockFromURLWithResponse(String, URL, BlobRange, byte[], LeaseAccessConditions, SourceModifiedAccessConditions, Duration, Context)} */ public void stageBlockFromURL2() { - // BEGIN: com.azure.storage.blob.BlockBlobClient.stageBlockFromURLWithResponse#String-URL-BlobRange-byte-LeaseAccessConditions-SourceModifiedAccessConditions-Duration-Context + // BEGIN: com.azure.storage.blob.specialized.BlockBlobClient.stageBlockFromURLWithResponse#String-URL-BlobRange-byte-LeaseAccessConditions-SourceModifiedAccessConditions-Duration-Context LeaseAccessConditions leaseAccessConditions = new LeaseAccessConditions().setLeaseId(leaseId); SourceModifiedAccessConditions sourceModifiedAccessConditions = new SourceModifiedAccessConditions() .setSourceIfUnmodifiedSince(OffsetDateTime.now().minusDays(3)); @@ -178,14 +175,14 @@ public void stageBlockFromURL2() { System.out.printf("Staging block from URL completed with status %d%n", client.stageBlockFromURLWithResponse(base64BlockID, sourceURL, new BlobRange(offset, count), null, leaseAccessConditions, sourceModifiedAccessConditions, timeout, context).getStatusCode()); - // END: com.azure.storage.blob.BlockBlobClient.stageBlockFromURLWithResponse#String-URL-BlobRange-byte-LeaseAccessConditions-SourceModifiedAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.BlockBlobClient.stageBlockFromURLWithResponse#String-URL-BlobRange-byte-LeaseAccessConditions-SourceModifiedAccessConditions-Duration-Context } /** * Code snippet for {@link BlockBlobClient#listBlocks(BlockListType)} */ public void listBlocks() { - // BEGIN: com.azure.storage.blob.BlockBlobClient.listBlocks#BlockListType + // BEGIN: com.azure.storage.blob.specialized.BlockBlobClient.listBlocks#BlockListType BlockList block = client.listBlocks(BlockListType.ALL); System.out.println("Committed Blocks:"); @@ -193,14 +190,14 @@ public void listBlocks() { System.out.println("Uncommitted Blocks:"); block.getUncommittedBlocks().forEach(b -> System.out.printf("Name: %s, Size: %d", b.getName(), b.getSize())); - // END: com.azure.storage.blob.BlockBlobClient.listBlocks#BlockListType + // END: com.azure.storage.blob.specialized.BlockBlobClient.listBlocks#BlockListType } /** * Code snippet for {@link BlockBlobClient#listBlocksWithResponse(BlockListType, LeaseAccessConditions, Duration, Context)} */ public void listBlocks2() { - // BEGIN: com.azure.storage.blob.BlockBlobClient.listBlocksWithResponse#BlockListType-LeaseAccessConditions-Duration-Context + // BEGIN: com.azure.storage.blob.specialized.BlockBlobClient.listBlocksWithResponse#BlockListType-LeaseAccessConditions-Duration-Context LeaseAccessConditions accessConditions = new LeaseAccessConditions().setLeaseId(leaseId); Context context = new Context("key", "value"); BlockList block = client.listBlocksWithResponse(BlockListType.ALL, accessConditions, timeout, context).getValue(); @@ -210,24 +207,24 @@ public void listBlocks2() { System.out.println("Uncommitted Blocks:"); block.getUncommittedBlocks().forEach(b -> System.out.printf("Name: %s, Size: %d", b.getName(), b.getSize())); - // END: com.azure.storage.blob.BlockBlobClient.listBlocksWithResponse#BlockListType-LeaseAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.BlockBlobClient.listBlocksWithResponse#BlockListType-LeaseAccessConditions-Duration-Context } /** * Code snippet for {@link BlockBlobClient#commitBlockList(List)} */ public void commitBlockList() { - // BEGIN: com.azure.storage.blob.BlockBlobClient.commitBlockList#List + // BEGIN: com.azure.storage.blob.specialized.BlockBlobClient.commitBlockList#List System.out.printf("Committing block list completed. Last modified: %s%n", client.commitBlockList(Collections.singletonList(base64BlockID)).getLastModified()); - // END: com.azure.storage.blob.BlockBlobClient.commitBlockList#List + // END: com.azure.storage.blob.specialized.BlockBlobClient.commitBlockList#List } /** * Code snippet for {@link BlockBlobClient#commitBlockListWithResponse(List, BlobHTTPHeaders, Metadata, AccessTier, BlobAccessConditions, Duration, Context)} */ public void commitBlockList2() { - // BEGIN: com.azure.storage.blob.BlockBlobClient.commitBlockListWithResponse#List-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration-Context + // BEGIN: com.azure.storage.blob.specialized.BlockBlobClient.commitBlockListWithResponse#List-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration-Context BlobHTTPHeaders headers = new BlobHTTPHeaders() .setBlobContentMD5("data".getBytes(StandardCharsets.UTF_8)) .setBlobContentLanguage("en-US") @@ -243,6 +240,6 @@ public void commitBlockList2() { System.out.printf("Committing block list completed with status %d%n", client.commitBlockListWithResponse(Collections.singletonList(base64BlockID), headers, metadata, AccessTier.HOT, accessConditions, timeout, context).getStatusCode()); - // END: com.azure.storage.blob.BlockBlobClient.commitBlockListWithResponse#List-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.BlockBlobClient.commitBlockListWithResponse#List-BlobHTTPHeaders-Metadata-AccessTier-BlobAccessConditions-Duration-Context } } diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/PageBlobAsyncClientJavaDocCodeSnippets.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/PageBlobAsyncClientJavaDocCodeSnippets.java similarity index 74% rename from sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/PageBlobAsyncClientJavaDocCodeSnippets.java rename to sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/PageBlobAsyncClientJavaDocCodeSnippets.java index a80f8102c55a..11f04b8e7b6c 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/PageBlobAsyncClientJavaDocCodeSnippets.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/PageBlobAsyncClientJavaDocCodeSnippets.java @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; import com.azure.storage.blob.models.BlobAccessConditions; import com.azure.storage.blob.models.BlobHTTPHeaders; @@ -18,6 +18,7 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.net.MalformedURLException; import java.net.URL; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -29,7 +30,7 @@ */ @SuppressWarnings("unused") public class PageBlobAsyncClientJavaDocCodeSnippets { - private PageBlobAsyncClient client = JavaDocCodeSnippetsHelpers.getPageBlobAsyncClient("blobName", "containerName"); + private PageBlobAsyncClient client = new SpecializedBlobClientBuilder().buildPageBlobAsyncClient(); private Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); private ByteBuffer[] bufferData = new ByteBuffer[]{ ByteBuffer.wrap(new byte[]{1}), @@ -39,11 +40,17 @@ public class PageBlobAsyncClientJavaDocCodeSnippets { private long size = 1024; private String leaseId = "leaseId"; private long sequenceNumber = 0; - private URL url = JavaDocCodeSnippetsHelpers.generateURL("https://sample.com"); + private URL url = new URL("https://sample.com"); private long sourceOffset = 0; private String data = "data"; private long offset = 0; + /** + * @throws MalformedURLException ignored + */ + public PageBlobAsyncClientJavaDocCodeSnippets() throws MalformedURLException { + } + /** * Code snippets for {@link PageBlobAsyncClient#create(long)} */ @@ -59,7 +66,7 @@ public void setCreateCodeSnippet() { * BlobAccessConditions)} */ public void createWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.createWithResponse#long-Long-BlobHTTPHeaders-Metadata-BlobAccessConditions + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.createWithResponse#long-Long-BlobHTTPHeaders-Metadata-BlobAccessConditions BlobHTTPHeaders headers = new BlobHTTPHeaders() .setBlobContentLanguage("en-US") .setBlobContentType("binary"); @@ -71,28 +78,28 @@ public void createWithResponseCodeSnippet() { .subscribe(response -> System.out.printf( "Created page blob with sequence number %s%n", response.getValue().getBlobSequenceNumber())); - // END: com.azure.storage.blob.PageBlobAsyncClient.createWithResponse#long-Long-BlobHTTPHeaders-Metadata-BlobAccessConditions + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.createWithResponse#long-Long-BlobHTTPHeaders-Metadata-BlobAccessConditions } /** * Code snippets for {@link PageBlobAsyncClient#uploadPages(PageRange, Flux)} */ public void uploadPagesCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.uploadPages#PageRange-Flux + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.uploadPages#PageRange-Flux PageRange pageRange = new PageRange() .setStart(0) .setEnd(511); client.uploadPages(pageRange, body).subscribe(response -> System.out.printf( "Uploaded page blob with sequence number %s%n", response.getBlobSequenceNumber())); - // END: com.azure.storage.blob.PageBlobAsyncClient.uploadPages#PageRange-Flux + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.uploadPages#PageRange-Flux } /** * Code snippets for {@link PageBlobAsyncClient#uploadPagesWithResponse(PageRange, Flux, PageBlobAccessConditions)} */ public void uploadPagesWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.uploadPagesWithResponse#PageRange-Flux-PageBlobAccessConditions + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.uploadPagesWithResponse#PageRange-Flux-PageBlobAccessConditions PageRange pageRange = new PageRange() .setStart(0) .setEnd(511); @@ -102,14 +109,14 @@ public void uploadPagesWithResponseCodeSnippet() { client.uploadPagesWithResponse(pageRange, body, pageBlobAccessConditions) .subscribe(response -> System.out.printf( "Uploaded page blob with sequence number %s%n", response.getValue().getBlobSequenceNumber())); - // END: com.azure.storage.blob.PageBlobAsyncClient.uploadPagesWithResponse#PageRange-Flux-PageBlobAccessConditions + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.uploadPagesWithResponse#PageRange-Flux-PageBlobAccessConditions } /** * Code snippets for {@link PageBlobAsyncClient#uploadPagesFromURL(PageRange, URL, Long)} */ public void uploadPagesFromURLCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.uploadPagesFromURL#PageRange-URL-Long + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.uploadPagesFromURL#PageRange-URL-Long PageRange pageRange = new PageRange() .setStart(0) .setEnd(511); @@ -117,7 +124,7 @@ public void uploadPagesFromURLCodeSnippet() { client.uploadPagesFromURL(pageRange, url, sourceOffset) .subscribe(response -> System.out.printf( "Uploaded page blob from URL with sequence number %s%n", response.getBlobSequenceNumber())); - // END: com.azure.storage.blob.PageBlobAsyncClient.uploadPagesFromURL#PageRange-URL-Long + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.uploadPagesFromURL#PageRange-URL-Long } /** @@ -125,7 +132,7 @@ public void uploadPagesFromURLCodeSnippet() { * PageBlobAccessConditions, SourceModifiedAccessConditions)} */ public void uploadPagesFromURLWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.uploadPagesFromURLWithResponse#PageRange-URL-Long-byte-PageBlobAccessConditions-SourceModifiedAccessConditions + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.uploadPagesFromURLWithResponse#PageRange-URL-Long-byte-PageBlobAccessConditions-SourceModifiedAccessConditions PageRange pageRange = new PageRange() .setStart(0) .setEnd(511); @@ -140,28 +147,28 @@ public void uploadPagesFromURLWithResponseCodeSnippet() { sourceAccessConditions) .subscribe(response -> System.out.printf( "Uploaded page blob from URL with sequence number %s%n", response.getValue().getBlobSequenceNumber())); - // END: com.azure.storage.blob.PageBlobAsyncClient.uploadPagesFromURLWithResponse#PageRange-URL-Long-byte-PageBlobAccessConditions-SourceModifiedAccessConditions + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.uploadPagesFromURLWithResponse#PageRange-URL-Long-byte-PageBlobAccessConditions-SourceModifiedAccessConditions } /** * Code snippets for {@link PageBlobAsyncClient#clearPages(PageRange)} */ public void clearPagesCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.clearPages#PageRange + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.clearPages#PageRange PageRange pageRange = new PageRange() .setStart(0) .setEnd(511); client.clearPages(pageRange).subscribe(response -> System.out.printf( "Cleared page blob with sequence number %s%n", response.getBlobSequenceNumber())); - // END: com.azure.storage.blob.PageBlobAsyncClient.clearPages#PageRange + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.clearPages#PageRange } /** * Code snippets for {@link PageBlobAsyncClient#clearPagesWithResponse(PageRange, PageBlobAccessConditions)} */ public void clearPagesWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.clearPagesWithResponse#PageRange-PageBlobAccessConditions + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.clearPagesWithResponse#PageRange-PageBlobAccessConditions PageRange pageRange = new PageRange() .setStart(0) .setEnd(511); @@ -171,14 +178,14 @@ public void clearPagesWithResponseCodeSnippet() { client.clearPagesWithResponse(pageRange, pageBlobAccessConditions) .subscribe(response -> System.out.printf( "Cleared page blob with sequence number %s%n", response.getValue().getBlobSequenceNumber())); - // END: com.azure.storage.blob.PageBlobAsyncClient.clearPagesWithResponse#PageRange-PageBlobAccessConditions + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.clearPagesWithResponse#PageRange-PageBlobAccessConditions } /** * Code snippets for {@link PageBlobAsyncClient#getPageRanges(BlobRange)} */ public void getPageRangesCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.getPageRanges#BlobRange + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.getPageRanges#BlobRange BlobRange blobRange = new BlobRange(offset); client.getPageRanges(blobRange).subscribe(response -> { @@ -187,14 +194,14 @@ public void getPageRangesCodeSnippet() { System.out.printf("Start: %s, End: %s%n", pageRange.getStart(), pageRange.getEnd()); } }); - // END: com.azure.storage.blob.PageBlobAsyncClient.getPageRanges#BlobRange + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.getPageRanges#BlobRange } /** * Code snippets for {@link PageBlobAsyncClient#getPageRangesWithResponse(BlobRange, BlobAccessConditions)} */ public void getPageRangesWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.getPageRangesWithResponse#BlobRange-BlobAccessConditions + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.getPageRangesWithResponse#BlobRange-BlobAccessConditions BlobRange blobRange = new BlobRange(offset); BlobAccessConditions blobAccessConditions = new BlobAccessConditions().setLeaseAccessConditions( new LeaseAccessConditions().setLeaseId(leaseId)); @@ -206,14 +213,14 @@ public void getPageRangesWithResponseCodeSnippet() { System.out.printf("Start: %s, End: %s%n", pageRange.getStart(), pageRange.getEnd()); } }); - // END: com.azure.storage.blob.PageBlobAsyncClient.getPageRangesWithResponse#BlobRange-BlobAccessConditions + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.getPageRangesWithResponse#BlobRange-BlobAccessConditions } /** * Code snippets for {@link PageBlobAsyncClient#getPageRangesDiff(BlobRange, String)} */ public void getPageRangesDiffCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.getPageRangesDiff#BlobRange-String + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.getPageRangesDiff#BlobRange-String BlobRange blobRange = new BlobRange(offset); final String prevSnapshot = "previous snapshot"; @@ -223,7 +230,7 @@ public void getPageRangesDiffCodeSnippet() { System.out.printf("Start: %s, End: %s%n", pageRange.getStart(), pageRange.getEnd()); } }); - // END: com.azure.storage.blob.PageBlobAsyncClient.getPageRangesDiff#BlobRange-String + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.getPageRangesDiff#BlobRange-String } /** @@ -231,7 +238,7 @@ public void getPageRangesDiffCodeSnippet() { * BlobAccessConditions)} */ public void getPageRangesDiffWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.getPageRangesDiffWithResponse#BlobRange-String-BlobAccessConditions + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.getPageRangesDiffWithResponse#BlobRange-String-BlobAccessConditions BlobRange blobRange = new BlobRange(offset); final String prevSnapshot = "previous snapshot"; BlobAccessConditions blobAccessConditions = new BlobAccessConditions().setLeaseAccessConditions( @@ -244,42 +251,42 @@ public void getPageRangesDiffWithResponseCodeSnippet() { System.out.printf("Start: %s, End: %s%n", pageRange.getStart(), pageRange.getEnd()); } }); - // END: com.azure.storage.blob.PageBlobAsyncClient.getPageRangesDiffWithResponse#BlobRange-String-BlobAccessConditions + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.getPageRangesDiffWithResponse#BlobRange-String-BlobAccessConditions } /** * Code snippets for {@link PageBlobAsyncClient#resize(long)} */ public void resizeCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.resize#long + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.resize#long client.resize(size).subscribe(response -> System.out.printf( "Page blob resized with sequence number %s%n", response.getBlobSequenceNumber())); - // END: com.azure.storage.blob.PageBlobAsyncClient.resize#long + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.resize#long } /** * Code snippets for {@link PageBlobAsyncClient#resizeWithResponse(long, BlobAccessConditions)} */ public void resizeWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.resizeWithResponse#long-BlobAccessConditions + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.resizeWithResponse#long-BlobAccessConditions BlobAccessConditions blobAccessConditions = new BlobAccessConditions().setLeaseAccessConditions( new LeaseAccessConditions().setLeaseId(leaseId)); client.resizeWithResponse(size, blobAccessConditions) .subscribe(response -> System.out.printf( "Page blob resized with sequence number %s%n", response.getValue().getBlobSequenceNumber())); - // END: com.azure.storage.blob.PageBlobAsyncClient.resizeWithResponse#long-BlobAccessConditions + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.resizeWithResponse#long-BlobAccessConditions } /** * Code snippets for {@link PageBlobAsyncClient#updateSequenceNumber(SequenceNumberActionType, Long)} */ public void updateSequenceNumberCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.updateSequenceNumber#SequenceNumberActionType-Long + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.updateSequenceNumber#SequenceNumberActionType-Long client.updateSequenceNumber(SequenceNumberActionType.INCREMENT, size) .subscribe(response -> System.out.printf( "Page blob updated to sequence number %s%n", response.getBlobSequenceNumber())); - // END: com.azure.storage.blob.PageBlobAsyncClient.updateSequenceNumber#SequenceNumberActionType-Long + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.updateSequenceNumber#SequenceNumberActionType-Long } /** @@ -287,21 +294,21 @@ public void updateSequenceNumberCodeSnippet() { * BlobAccessConditions)} */ public void updateSequenceNumberWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.updateSequenceNumberWithResponse#SequenceNumberActionType-Long-BlobAccessConditions + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.updateSequenceNumberWithResponse#SequenceNumberActionType-Long-BlobAccessConditions BlobAccessConditions blobAccessConditions = new BlobAccessConditions().setLeaseAccessConditions( new LeaseAccessConditions().setLeaseId(leaseId)); client.updateSequenceNumberWithResponse(SequenceNumberActionType.INCREMENT, size, blobAccessConditions) .subscribe(response -> System.out.printf( "Page blob updated to sequence number %s%n", response.getValue().getBlobSequenceNumber())); - // END: com.azure.storage.blob.PageBlobAsyncClient.updateSequenceNumberWithResponse#SequenceNumberActionType-Long-BlobAccessConditions + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.updateSequenceNumberWithResponse#SequenceNumberActionType-Long-BlobAccessConditions } /** * Code snippets for {@link PageBlobAsyncClient#copyIncremental(URL, String)} */ public void copyIncrementalCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.copyIncremental#URL-String + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.copyIncremental#URL-String final String snapshot = "copy snapshot"; client.copyIncremental(url, snapshot).subscribe(response -> { if (CopyStatusType.SUCCESS == response) { @@ -314,14 +321,14 @@ public void copyIncrementalCodeSnippet() { System.out.println("Page blob copied pending"); } }); - // END: com.azure.storage.blob.PageBlobAsyncClient.copyIncremental#URL-String + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.copyIncremental#URL-String } /** * Code snippets for {@link PageBlobAsyncClient#copyIncrementalWithResponse(URL, String, ModifiedAccessConditions)} */ public void copyIncrementalWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobAsyncClient.copyIncrementalWithResponse#URL-String-ModifiedAccessConditions + // BEGIN: com.azure.storage.blob.specialized.PageBlobAsyncClient.copyIncrementalWithResponse#URL-String-ModifiedAccessConditions final String snapshot = "copy snapshot"; ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() .setIfNoneMatch("snapshotMatch"); @@ -340,7 +347,7 @@ public void copyIncrementalWithResponseCodeSnippet() { System.out.println("Page blob copied pending"); } }); - // END: com.azure.storage.blob.PageBlobAsyncClient.copyIncrementalWithResponse#URL-String-ModifiedAccessConditions + // END: com.azure.storage.blob.specialized.PageBlobAsyncClient.copyIncrementalWithResponse#URL-String-ModifiedAccessConditions } } diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/PageBlobClientJavaDocCodeSnippets.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/PageBlobClientJavaDocCodeSnippets.java similarity index 74% rename from sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/PageBlobClientJavaDocCodeSnippets.java rename to sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/PageBlobClientJavaDocCodeSnippets.java index a0b2cbe03b42..a0dc3dc34f43 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/PageBlobClientJavaDocCodeSnippets.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/specialized/PageBlobClientJavaDocCodeSnippets.java @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; import com.azure.core.util.Context; import com.azure.storage.blob.models.BlobAccessConditions; @@ -20,6 +20,7 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.time.Duration; @@ -31,7 +32,7 @@ */ @SuppressWarnings("unused") public class PageBlobClientJavaDocCodeSnippets { - private PageBlobClient client = JavaDocCodeSnippetsHelpers.getPageBlobClient("blobName", "containerName"); + private PageBlobClient client = new SpecializedBlobClientBuilder().buildPageBlobClient(); private Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); private String leaseId = "leaseId"; private Duration timeout = Duration.ofSeconds(30); @@ -42,12 +43,18 @@ public class PageBlobClientJavaDocCodeSnippets { private String key = "key"; private String value = "value"; private String data = "data"; - private URL url = JavaDocCodeSnippetsHelpers.generateURL("https://sample.com"); + private URL url = new URL("https://sample.com"); + + /** + * @throws MalformedURLException ignored + */ + public PageBlobClientJavaDocCodeSnippets() throws MalformedURLException { + } /** * Code snippets for {@link PageBlobClient#create(long)} */ - public void setCreateCodeSnippet() { + public void createCodeSnippet() { // BEGIN: com.azure.storage.blob.PageBlobClient.create#long PageBlobItem pageBlob = client.create(size); System.out.printf("Created page blob with sequence number %s%n", pageBlob.getBlobSequenceNumber()); @@ -59,7 +66,7 @@ public void setCreateCodeSnippet() { * BlobAccessConditions, Duration, Context)} */ public void createWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.createWithResponse#long-Long-BlobHTTPHeaders-Metadata-BlobAccessConditions-Duration-Context + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.createWithResponse#long-Long-BlobHTTPHeaders-Metadata-BlobAccessConditions-Duration-Context BlobHTTPHeaders headers = new BlobHTTPHeaders() .setBlobContentLanguage("en-US") .setBlobContentType("binary"); @@ -72,14 +79,14 @@ public void createWithResponseCodeSnippet() { .getValue(); System.out.printf("Created page blob with sequence number %s%n", pageBlob.getBlobSequenceNumber()); - // END: com.azure.storage.blob.PageBlobClient.createWithResponse#long-Long-BlobHTTPHeaders-Metadata-BlobAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.PageBlobClient.createWithResponse#long-Long-BlobHTTPHeaders-Metadata-BlobAccessConditions-Duration-Context } /** * Code snippets for {@link PageBlobClient#uploadPages(PageRange, InputStream)} */ public void uploadPagesCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.uploadPages#PageRange-InputStream + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.uploadPages#PageRange-InputStream PageRange pageRange = new PageRange() .setStart(0) .setEnd(511); @@ -87,7 +94,7 @@ public void uploadPagesCodeSnippet() { PageBlobItem pageBlob = client.uploadPages(pageRange, dataStream); System.out.printf("Uploaded page blob with sequence number %s%n", pageBlob.getBlobSequenceNumber()); - // END: com.azure.storage.blob.PageBlobClient.uploadPages#PageRange-InputStream + // END: com.azure.storage.blob.specialized.PageBlobClient.uploadPages#PageRange-InputStream } /** @@ -95,7 +102,7 @@ public void uploadPagesCodeSnippet() { * Duration, Context)} */ public void uploadPagesWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.uploadPagesWithResponse#PageRange-InputStream-PageBlobAccessConditions-Duration-Context + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.uploadPagesWithResponse#PageRange-InputStream-PageBlobAccessConditions-Duration-Context PageRange pageRange = new PageRange() .setStart(0) .setEnd(511); @@ -108,14 +115,14 @@ public void uploadPagesWithResponseCodeSnippet() { .uploadPagesWithResponse(pageRange, dataStream, pageBlobAccessConditions, timeout, context).getValue(); System.out.printf("Uploaded page blob with sequence number %s%n", pageBlob.getBlobSequenceNumber()); - // END: com.azure.storage.blob.PageBlobClient.uploadPagesWithResponse#PageRange-InputStream-PageBlobAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.PageBlobClient.uploadPagesWithResponse#PageRange-InputStream-PageBlobAccessConditions-Duration-Context } /** * Code snippets for {@link PageBlobClient#uploadPagesFromURL(PageRange, URL, Long)} */ public void uploadPagesFromURLCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.uploadPagesFromURL#PageRange-URL-Long + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.uploadPagesFromURL#PageRange-URL-Long PageRange pageRange = new PageRange() .setStart(0) .setEnd(511); @@ -123,7 +130,7 @@ public void uploadPagesFromURLCodeSnippet() { PageBlobItem pageBlob = client.uploadPagesFromURL(pageRange, url, sourceOffset); System.out.printf("Uploaded page blob from URL with sequence number %s%n", pageBlob.getBlobSequenceNumber()); - // END: com.azure.storage.blob.PageBlobClient.uploadPagesFromURL#PageRange-URL-Long + // END: com.azure.storage.blob.specialized.PageBlobClient.uploadPagesFromURL#PageRange-URL-Long } /** @@ -131,7 +138,7 @@ public void uploadPagesFromURLCodeSnippet() { * PageBlobAccessConditions, SourceModifiedAccessConditions, Duration, Context)} */ public void uploadPagesFromURLWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.uploadPagesFromURLWithResponse#PageRange-URL-Long-byte-PageBlobAccessConditions-SourceModifiedAccessConditions-Duration-Context + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.uploadPagesFromURLWithResponse#PageRange-URL-Long-byte-PageBlobAccessConditions-SourceModifiedAccessConditions-Duration-Context PageRange pageRange = new PageRange() .setStart(0) .setEnd(511); @@ -148,14 +155,14 @@ public void uploadPagesFromURLWithResponseCodeSnippet() { sourceAccessConditions, timeout, context).getValue(); System.out.printf("Uploaded page blob from URL with sequence number %s%n", pageBlob.getBlobSequenceNumber()); - // END: com.azure.storage.blob.PageBlobClient.uploadPagesFromURLWithResponse#PageRange-URL-Long-byte-PageBlobAccessConditions-SourceModifiedAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.PageBlobClient.uploadPagesFromURLWithResponse#PageRange-URL-Long-byte-PageBlobAccessConditions-SourceModifiedAccessConditions-Duration-Context } /** * Code snippets for {@link PageBlobClient#clearPages(PageRange)} */ public void clearPagesCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.clearPages#PageRange + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.clearPages#PageRange PageRange pageRange = new PageRange() .setStart(0) .setEnd(511); @@ -163,7 +170,7 @@ public void clearPagesCodeSnippet() { PageBlobItem pageBlob = client.clearPages(pageRange); System.out.printf("Cleared page blob with sequence number %s%n", pageBlob.getBlobSequenceNumber()); - // END: com.azure.storage.blob.PageBlobClient.clearPages#PageRange + // END: com.azure.storage.blob.specialized.PageBlobClient.clearPages#PageRange } /** @@ -171,7 +178,7 @@ public void clearPagesCodeSnippet() { * Context)} */ public void clearPagesWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.clearPagesWithResponse#PageRange-PageBlobAccessConditions-Duration-Context + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.clearPagesWithResponse#PageRange-PageBlobAccessConditions-Duration-Context PageRange pageRange = new PageRange() .setStart(0) .setEnd(511); @@ -183,14 +190,14 @@ public void clearPagesWithResponseCodeSnippet() { .clearPagesWithResponse(pageRange, pageBlobAccessConditions, timeout, context).getValue(); System.out.printf("Cleared page blob with sequence number %s%n", pageBlob.getBlobSequenceNumber()); - // END: com.azure.storage.blob.PageBlobClient.clearPagesWithResponse#PageRange-PageBlobAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.PageBlobClient.clearPagesWithResponse#PageRange-PageBlobAccessConditions-Duration-Context } /** * Code snippets for {@link PageBlobClient#getPageRanges(BlobRange)} */ public void getPageRangesCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.getPageRanges#BlobRange + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.getPageRanges#BlobRange BlobRange blobRange = new BlobRange(offset); PageList pageList = client.getPageRanges(blobRange); @@ -198,7 +205,7 @@ public void getPageRangesCodeSnippet() { for (PageRange pageRange : pageList.getPageRange()) { System.out.printf("Start: %s, End: %s%n", pageRange.getStart(), pageRange.getEnd()); } - // END: com.azure.storage.blob.PageBlobClient.getPageRanges#BlobRange + // END: com.azure.storage.blob.specialized.PageBlobClient.getPageRanges#BlobRange } /** @@ -206,7 +213,7 @@ public void getPageRangesCodeSnippet() { * Context)} */ public void getPageRangesWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.getPageRangesWithResponse#BlobRange-BlobAccessConditions-Duration-Context + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.getPageRangesWithResponse#BlobRange-BlobAccessConditions-Duration-Context BlobRange blobRange = new BlobRange(offset); BlobAccessConditions blobAccessConditions = new BlobAccessConditions().setLeaseAccessConditions( new LeaseAccessConditions().setLeaseId(leaseId)); @@ -219,14 +226,14 @@ public void getPageRangesWithResponseCodeSnippet() { for (PageRange pageRange : pageList.getPageRange()) { System.out.printf("Start: %s, End: %s%n", pageRange.getStart(), pageRange.getEnd()); } - // END: com.azure.storage.blob.PageBlobClient.getPageRangesWithResponse#BlobRange-BlobAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.PageBlobClient.getPageRangesWithResponse#BlobRange-BlobAccessConditions-Duration-Context } /** * Code snippets for {@link PageBlobClient#getPageRangesDiff(BlobRange, String)} */ public void getPageRangesDiffCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.getPageRangesDiff#BlobRange-String + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.getPageRangesDiff#BlobRange-String BlobRange blobRange = new BlobRange(offset); final String prevSnapshot = "previous snapshot"; PageList pageList = client.getPageRangesDiff(blobRange, prevSnapshot); @@ -235,7 +242,7 @@ public void getPageRangesDiffCodeSnippet() { for (PageRange pageRange : pageList.getPageRange()) { System.out.printf("Start: %s, End: %s%n", pageRange.getStart(), pageRange.getEnd()); } - // END: com.azure.storage.blob.PageBlobClient.getPageRangesDiff#BlobRange-String + // END: com.azure.storage.blob.specialized.PageBlobClient.getPageRangesDiff#BlobRange-String } /** @@ -243,7 +250,7 @@ public void getPageRangesDiffCodeSnippet() { * Duration, Context)} */ public void getPageRangesDiffWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.getPageRangesDiffWithResponse#BlobRange-String-BlobAccessConditions-Duration-Context + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.getPageRangesDiffWithResponse#BlobRange-String-BlobAccessConditions-Duration-Context BlobRange blobRange = new BlobRange(offset); final String prevSnapshot = "previous snapshot"; BlobAccessConditions blobAccessConditions = new BlobAccessConditions().setLeaseAccessConditions( @@ -257,24 +264,24 @@ public void getPageRangesDiffWithResponseCodeSnippet() { for (PageRange pageRange : pageList.getPageRange()) { System.out.printf("Start: %s, End: %s%n", pageRange.getStart(), pageRange.getEnd()); } - // END: com.azure.storage.blob.PageBlobClient.getPageRangesDiffWithResponse#BlobRange-String-BlobAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.PageBlobClient.getPageRangesDiffWithResponse#BlobRange-String-BlobAccessConditions-Duration-Context } /** * Code snippets for {@link PageBlobClient#resize(long)} */ public void resizeCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.resize#long + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.resize#long PageBlobItem pageBlob = client.resize(size); System.out.printf("Page blob resized with sequence number %s%n", pageBlob.getBlobSequenceNumber()); - // END: com.azure.storage.blob.PageBlobClient.resize#long + // END: com.azure.storage.blob.specialized.PageBlobClient.resize#long } /** * Code snippets for {@link PageBlobClient#resizeWithResponse(long, BlobAccessConditions, Duration, Context)} */ public void resizeWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.resizeWithResponse#long-BlobAccessConditions-Duration-Context + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.resizeWithResponse#long-BlobAccessConditions-Duration-Context BlobAccessConditions blobAccessConditions = new BlobAccessConditions().setLeaseAccessConditions( new LeaseAccessConditions().setLeaseId(leaseId)); Context context = new Context(key, value); @@ -282,18 +289,18 @@ public void resizeWithResponseCodeSnippet() { PageBlobItem pageBlob = client .resizeWithResponse(size, blobAccessConditions, timeout, context).getValue(); System.out.printf("Page blob resized with sequence number %s%n", pageBlob.getBlobSequenceNumber()); - // END: com.azure.storage.blob.PageBlobClient.resizeWithResponse#long-BlobAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.PageBlobClient.resizeWithResponse#long-BlobAccessConditions-Duration-Context } /** * Code snippets for {@link PageBlobClient#updateSequenceNumber(SequenceNumberActionType, Long)} */ public void updateSequenceNumberCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.updateSequenceNumber#SequenceNumberActionType-Long + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.updateSequenceNumber#SequenceNumberActionType-Long PageBlobItem pageBlob = client.updateSequenceNumber(SequenceNumberActionType.INCREMENT, size); System.out.printf("Page blob updated to sequence number %s%n", pageBlob.getBlobSequenceNumber()); - // END: com.azure.storage.blob.PageBlobClient.updateSequenceNumber#SequenceNumberActionType-Long + // END: com.azure.storage.blob.specialized.PageBlobClient.updateSequenceNumber#SequenceNumberActionType-Long } /** @@ -301,7 +308,7 @@ public void updateSequenceNumberCodeSnippet() { * BlobAccessConditions, Duration, Context)} */ public void updateSequenceNumberWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.updateSequenceNumberWithResponse#SequenceNumberActionType-Long-BlobAccessConditions-Duration-Context + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.updateSequenceNumberWithResponse#SequenceNumberActionType-Long-BlobAccessConditions-Duration-Context BlobAccessConditions blobAccessConditions = new BlobAccessConditions().setLeaseAccessConditions( new LeaseAccessConditions().setLeaseId(leaseId)); Context context = new Context(key, value); @@ -310,14 +317,14 @@ public void updateSequenceNumberWithResponseCodeSnippet() { SequenceNumberActionType.INCREMENT, size, blobAccessConditions, timeout, context).getValue(); System.out.printf("Page blob updated to sequence number %s%n", pageBlob.getBlobSequenceNumber()); - // END: com.azure.storage.blob.PageBlobClient.updateSequenceNumberWithResponse#SequenceNumberActionType-Long-BlobAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.PageBlobClient.updateSequenceNumberWithResponse#SequenceNumberActionType-Long-BlobAccessConditions-Duration-Context } /** * Code snippets for {@link PageBlobClient#copyIncremental(URL, String)} */ public void copyIncrementalCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.copyIncremental#URL-String + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.copyIncremental#URL-String final String snapshot = "copy snapshot"; CopyStatusType statusType = client.copyIncremental(url, snapshot); @@ -330,7 +337,7 @@ public void copyIncrementalCodeSnippet() { } else if (CopyStatusType.PENDING == statusType) { System.out.println("Page blob copied pending"); } - // END: com.azure.storage.blob.PageBlobClient.copyIncremental#URL-String + // END: com.azure.storage.blob.specialized.PageBlobClient.copyIncremental#URL-String } /** @@ -338,7 +345,7 @@ public void copyIncrementalCodeSnippet() { * Duration, Context)} */ public void copyIncrementalWithResponseCodeSnippet() { - // BEGIN: com.azure.storage.blob.PageBlobClient.copyIncrementalWithResponse#URL-String-ModifiedAccessConditions-Duration-Context + // BEGIN: com.azure.storage.blob.specialized.PageBlobClient.copyIncrementalWithResponse#URL-String-ModifiedAccessConditions-Duration-Context final String snapshot = "copy snapshot"; ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() .setIfNoneMatch("snapshotMatch"); @@ -356,7 +363,7 @@ public void copyIncrementalWithResponseCodeSnippet() { } else if (CopyStatusType.PENDING == statusType) { System.out.println("Page blob copied pending"); } - // END: com.azure.storage.blob.PageBlobClient.copyIncrementalWithResponse#URL-String-ModifiedAccessConditions-Duration-Context + // END: com.azure.storage.blob.specialized.PageBlobClient.copyIncrementalWithResponse#URL-String-ModifiedAccessConditions-Duration-Context } } diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/APISpec.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/APISpec.groovy index 9546d6963f22..1d5986f1a77d 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/APISpec.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/APISpec.groovy @@ -28,6 +28,8 @@ import com.azure.storage.blob.models.LeaseStateType import com.azure.storage.blob.models.ListContainersOptions import com.azure.storage.blob.models.RetentionPolicy import com.azure.storage.blob.models.StorageServiceProperties +import com.azure.storage.blob.specialized.BlobAsyncClientBase +import com.azure.storage.blob.specialized.BlobClientBase import com.azure.storage.blob.specialized.LeaseClient import com.azure.storage.blob.specialized.LeaseClientBuilder import com.azure.storage.common.BaseClientBuilder @@ -112,7 +114,7 @@ class APISpec extends Specification { static def BLOB_STORAGE = "BLOB_STORAGE_" static def PREMIUM_STORAGE = "PREMIUM_STORAGE_" - static SharedKeyCredential primaryCredential + protected static SharedKeyCredential primaryCredential static SharedKeyCredential alternateCredential static SharedKeyCredential blobCredential static SharedKeyCredential premiumCredential @@ -409,11 +411,11 @@ class APISpec extends Specification { } } - static LeaseClient createLeaseClient(BlobClient blobClient) { + static LeaseClient createLeaseClient(BlobClientBase blobClient) { return createLeaseClient(blobClient, null) } - static LeaseClient createLeaseClient(BlobClient blobClient, String leaseId) { + static LeaseClient createLeaseClient(BlobClientBase blobClient, String leaseId) { return new LeaseClientBuilder() .blobClient(blobClient) .leaseId(leaseId) @@ -483,7 +485,7 @@ class APISpec extends Specification { * @return * The appropriate etag value to run the current test. */ - def setupBlobMatchCondition(BlobClient bc, String match) { + def setupBlobMatchCondition(BlobClientBase bc, String match) { if (match == receivedEtag) { return bc.getProperties().getETag() } else { @@ -491,7 +493,7 @@ class APISpec extends Specification { } } - def setupBlobMatchCondition(BlobAsyncClient bac, String match) { + def setupBlobMatchCondition(BlobAsyncClientBase bac, String match) { if (match == receivedEtag) { return bac.getProperties().block().getETag() } else { @@ -513,7 +515,7 @@ class APISpec extends Specification { * The actual leaseAccessConditions of the blob if recievedLeaseID is passed, otherwise whatever was passed will be * returned. */ - def setupBlobLeaseCondition(BlobClient bc, String leaseID) { + def setupBlobLeaseCondition(BlobClientBase bc, String leaseID) { String responseLeaseId = null if (leaseID == receivedLeaseID || leaseID == garbageLeaseID) { responseLeaseId = createLeaseClient(bc).acquireLease(-1) @@ -525,7 +527,7 @@ class APISpec extends Specification { } } - def setupBlobLeaseCondition(BlobAsyncClient bac, String leaseID) { + def setupBlobLeaseCondition(BlobAsyncClientBase bac, String leaseID) { String responseLeaseId = null if (leaseID == receivedLeaseID || leaseID == garbageLeaseID) { responseLeaseId = new LeaseClientBuilder() diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobAPITest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobAPITest.groovy index da79e76a0f48..ae42ef95e1fb 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobAPITest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobAPITest.groovy @@ -3,8 +3,6 @@ package com.azure.storage.blob -import com.azure.core.http.HttpHeaders -import com.azure.core.http.rest.Response import com.azure.core.implementation.util.ImplUtils import com.azure.storage.blob.models.AccessTier @@ -23,10 +21,11 @@ import com.azure.storage.blob.models.ModifiedAccessConditions import com.azure.storage.blob.models.PublicAccessType import com.azure.storage.blob.models.RehydratePriority import com.azure.storage.blob.models.ReliableDownloadOptions -import com.azure.storage.blob.models.StorageAccountInfo import com.azure.storage.blob.models.StorageErrorCode import com.azure.storage.blob.models.StorageException import com.azure.storage.blob.models.SyncCopyStatusType +import com.azure.storage.blob.specialized.BlobClientBase +import com.azure.storage.blob.specialized.SpecializedBlobClientBuilder import spock.lang.Unroll import java.nio.ByteBuffer @@ -35,12 +34,12 @@ import java.security.MessageDigest import java.time.OffsetDateTime class BlobAPITest extends APISpec { - BlobClient bc + BlobClientBase bc String blobName def setup() { blobName = generateBlobName() - bc = cc.getBlockBlobClient(blobName) + bc = cc.getBlobClient(blobName).asBlockBlobClient() bc.upload(defaultInputStream.get(), defaultDataSize) } @@ -81,7 +80,7 @@ class BlobAPITest extends APISpec { def "Download empty file"() { setup: - bc = cc.getAppendBlobClient("emptyAppendBlob") + bc = cc.getBlobClient("emptyAppendBlob").asAppendBlobClient() bc.create() when: @@ -108,11 +107,11 @@ class BlobAPITest extends APISpec { constructed in BlobClient.download(). */ setup: - BlobClient bu2 = getBlobClient(primaryCredential, bc.getBlobUrl().toString(), new MockRetryRangeResponsePolicy()) + def bu2 = getBlobClient(primaryCredential, bc.getBlobUrl().toString(), new MockRetryRangeResponsePolicy()) when: - BlobRange range = new BlobRange(2, 5L) - ReliableDownloadOptions options = new ReliableDownloadOptions().maxRetryRequests(3) + def range = new BlobRange(2, 5L) + def options = new ReliableDownloadOptions().maxRetryRequests(3) bu2.downloadWithResponse(new ByteArrayOutputStream(), range, options, null, false, null, null) then: @@ -128,7 +127,7 @@ class BlobAPITest extends APISpec { when: def outStream = new ByteArrayOutputStream() bc.download(outStream) - byte[] result = outStream.toByteArray() + def result = outStream.toByteArray() then: result == defaultData.array() @@ -137,7 +136,7 @@ class BlobAPITest extends APISpec { @Unroll def "Download range"() { setup: - BlobRange range = (count == null) ? new BlobRange(offset) : new BlobRange(offset, count) + def range = (count == null) ? new BlobRange(offset) : new BlobRange(offset, count) when: def outStream = new ByteArrayOutputStream() @@ -159,7 +158,7 @@ class BlobAPITest extends APISpec { setup: match = setupBlobMatchCondition(bc, match) leaseID = setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions().setIfModifiedSince(modified) .setIfUnmodifiedSince(unmodified) @@ -186,7 +185,7 @@ class BlobAPITest extends APISpec { def "Download AC fail"() { setup: setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -211,8 +210,8 @@ class BlobAPITest extends APISpec { def "Download md5"() { when: - Response response = bc.downloadWithResponse(new ByteArrayOutputStream(), new BlobRange(0, 3), null, null, true, null, null) - byte[] contentMD5 = response.getHeaders().getValue("content-md5").getBytes() + def response = bc.downloadWithResponse(new ByteArrayOutputStream(), new BlobRange(0, 3), null, null, true, null, null) + def contentMD5 = response.getHeaders().getValue("content-md5").getBytes() then: contentMD5 == Base64.getEncoder().encode(MessageDigest.getInstance("MD5").digest(defaultText.substring(0, 3).getBytes())) @@ -220,7 +219,7 @@ class BlobAPITest extends APISpec { def "Download error"() { setup: - bc = cc.getBlockBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: bc.download(null) @@ -231,14 +230,17 @@ class BlobAPITest extends APISpec { def "Download snapshot"() { when: - ByteArrayOutputStream originalStream = new ByteArrayOutputStream() + def originalStream = new ByteArrayOutputStream() bc.download(originalStream) def bc2 = bc.createSnapshot() - bc.asBlockBlobClient().upload(new ByteArrayInputStream("ABC".getBytes()), 3) + new SpecializedBlobClientBuilder() + .blobClient(bc) + .buildBlockBlobClient() + .upload(new ByteArrayInputStream("ABC".getBytes()), 3) then: - ByteArrayOutputStream snapshotStream = new ByteArrayOutputStream() + def snapshotStream = new ByteArrayOutputStream() bc2.download(snapshotStream) snapshotStream.toByteArray() == originalStream.toByteArray() } @@ -325,7 +327,7 @@ class BlobAPITest extends APISpec { @Unroll def "Get properties AC"() { setup: - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(setupBlobLeaseCondition(bc, leaseID))) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -349,7 +351,7 @@ class BlobAPITest extends APISpec { @Unroll def "Get properties AC fail"() { setup: - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(setupBlobLeaseCondition(bc, leaseID))) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -374,7 +376,7 @@ class BlobAPITest extends APISpec { def "Get properties error"() { setup: - bc = cc.getBlockBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: bc.getProperties() @@ -385,7 +387,7 @@ class BlobAPITest extends APISpec { def "Set HTTP headers null"() { setup: - Response response = bc.setHTTPHeadersWithResponse(null, null, null, null) + def response = bc.setHTTPHeadersWithResponse(null, null, null, null) expect: response.getStatusCode() == 200 @@ -394,8 +396,8 @@ class BlobAPITest extends APISpec { def "Set HTTP headers min"() { setup: - BlobProperties properties = bc.getProperties() - BlobHTTPHeaders headers = new BlobHTTPHeaders() + def properties = bc.getProperties() + def headers = new BlobHTTPHeaders() .setBlobContentEncoding(properties.getContentEncoding()) .setBlobContentDisposition(properties.getContentDisposition()) .setBlobContentType("type") @@ -412,7 +414,7 @@ class BlobAPITest extends APISpec { @Unroll def "Set HTTP headers headers"() { setup: - BlobHTTPHeaders putHeaders = new BlobHTTPHeaders().setBlobCacheControl(cacheControl) + def putHeaders = new BlobHTTPHeaders().setBlobCacheControl(cacheControl) .setBlobContentDisposition(contentDisposition) .setBlobContentEncoding(contentEncoding) .setBlobContentLanguage(contentLanguage) @@ -438,7 +440,7 @@ class BlobAPITest extends APISpec { setup: match = setupBlobMatchCondition(bc, match) leaseID = setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -464,7 +466,7 @@ class BlobAPITest extends APISpec { setup: noneMatch = setupBlobMatchCondition(bc, noneMatch) setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -489,7 +491,7 @@ class BlobAPITest extends APISpec { def "Set HTTP headers error"() { setup: - bc = cc.getBlockBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: bc.setHTTPHeaders(null) @@ -524,7 +526,7 @@ class BlobAPITest extends APISpec { @Unroll def "Set metadata metadata"() { setup: - Metadata metadata = new Metadata() + def metadata = new Metadata() if (key1 != null && value1 != null) { metadata.put(key1, value1) } @@ -547,7 +549,7 @@ class BlobAPITest extends APISpec { setup: match = setupBlobMatchCondition(bc, match) leaseID = setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -574,7 +576,7 @@ class BlobAPITest extends APISpec { noneMatch = setupBlobMatchCondition(bc, noneMatch) setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -599,7 +601,7 @@ class BlobAPITest extends APISpec { def "Set metadata error"() { setup: - bc = cc.getBlockBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: bc.setMetadata(null) @@ -624,7 +626,7 @@ class BlobAPITest extends APISpec { @Unroll def "Snapshot metadata"() { setup: - Metadata metadata = new Metadata() + def metadata = new Metadata() if (key1 != null && value1 != null) { metadata.put(key1, value1) } @@ -650,7 +652,7 @@ class BlobAPITest extends APISpec { setup: match = setupBlobMatchCondition(bc, match) leaseID = setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -676,7 +678,7 @@ class BlobAPITest extends APISpec { setup: noneMatch = setupBlobMatchCondition(bc, noneMatch) setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -702,7 +704,7 @@ class BlobAPITest extends APISpec { def "Snapshot error"() { setup: - bc = cc.getBlockBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: bc.createSnapshot() @@ -713,7 +715,7 @@ class BlobAPITest extends APISpec { def "Copy"() { setup: - def copyDestBlob = cc.getBlockBlobClient(generateBlobName()) + def copyDestBlob = cc.getBlobClient(generateBlobName()).asBlockBlobClient() def headers = copyDestBlob.startCopyFromURLWithResponse(bc.getBlobUrl(), null, null, null, null, null, null, null).getHeaders() @@ -740,8 +742,8 @@ class BlobAPITest extends APISpec { @Unroll def "Copy metadata"() { setup: - BlobClient bu2 = cc.getBlockBlobClient(generateBlobName()) - Metadata metadata = new Metadata() + def bu2 = cc.getBlobClient(generateBlobName()).asBlockBlobClient() + def metadata = new Metadata() if (key1 != null && value1 != null) { metadata.put(key1, value1) } @@ -752,11 +754,11 @@ class BlobAPITest extends APISpec { def status = bu2.startCopyFromURLWithResponse(bc.getBlobUrl(), metadata, null, null, null, null, null, null) .getHeaders().getValue("x-ms-copy-status") - OffsetDateTime start = OffsetDateTime.now() + def start = OffsetDateTime.now() while (status != CopyStatusType.SUCCESS.toString()) { sleepIfRecord(1000) status = bu2.getPropertiesWithResponse(null, null, null).getHeaders().getValue("x-ms-copy-status") - OffsetDateTime currentTime = OffsetDateTime.now() + def currentTime = OffsetDateTime.now() if (status == CopyStatusType.FAILED.toString() || currentTime.minusMinutes(1) == start) { throw new Exception("Copy failed or took too long") } @@ -774,7 +776,7 @@ class BlobAPITest extends APISpec { @Unroll def "Copy source AC"() { setup: - BlobClient copyDestBlob = cc.getBlockBlobClient(generateBlobName()) + def copyDestBlob = cc.getBlobClient(generateBlobName()).asBlockBlobClient() match = setupBlobMatchCondition(bc, match) def mac = new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -797,7 +799,7 @@ class BlobAPITest extends APISpec { @Unroll def "Copy source AC fail"() { setup: - BlobClient bu2 = cc.getBlockBlobClient(generateBlobName()) + def bu2 = cc.getBlobClient(generateBlobName()).asBlockBlobClient() noneMatch = setupBlobMatchCondition(bc, noneMatch) def mac = new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -822,11 +824,11 @@ class BlobAPITest extends APISpec { @Unroll def "Copy dest AC"() { setup: - BlobClient bu2 = cc.getBlockBlobClient(generateBlobName()) + def bu2 = cc.getBlobClient(generateBlobName()).asBlockBlobClient() bu2.upload(defaultInputStream.get(), defaultDataSize) match = setupBlobMatchCondition(bu2, match) leaseID = setupBlobLeaseCondition(bu2, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -851,11 +853,11 @@ class BlobAPITest extends APISpec { @Unroll def "Copy dest AC fail"() { setup: - BlobClient bu2 = cc.getBlockBlobClient(generateBlobName()) + def bu2 = cc.getBlobClient(generateBlobName()).asBlockBlobClient() bu2.upload(defaultInputStream.get(), defaultDataSize) noneMatch = setupBlobMatchCondition(bu2, noneMatch) setupBlobLeaseCondition(bu2, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -881,21 +883,22 @@ class BlobAPITest extends APISpec { def "Abort copy lease fail"() { setup: // Data has to be large enough and copied between accounts to give us enough time to abort - bc.asBlockBlobClient() + new SpecializedBlobClientBuilder() + .blobClient(bc) + .buildBlockBlobClient() .upload(new ByteArrayInputStream(getRandomByteArray(8 * 1024 * 1024)), 8 * 1024 * 1024) // So we don't have to create a SAS. cc.setAccessPolicy(PublicAccessType.BLOB, null) - ContainerClient cu2 = alternateBlobServiceClient.getContainerClient(generateBlobName()) + def cu2 = alternateBlobServiceClient.getContainerClient(generateBlobName()) cu2.create() - BlockBlobClient bu2 = cu2.getBlockBlobClient(generateBlobName()) + def bu2 = cu2.getBlobClient(generateBlobName()).asBlockBlobClient() bu2.upload(defaultInputStream.get(), defaultDataSize) - String leaseID = setupBlobLeaseCondition(bu2, receivedLeaseID) + def leaseID = setupBlobLeaseCondition(bu2, receivedLeaseID) when: - String copyID = - bu2.startCopyFromURLWithResponse(bc.getBlobUrl(), null, null, null, null, - new BlobAccessConditions().setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)), null, null).getValue() + def copyID = bu2.startCopyFromURLWithResponse(bc.getBlobUrl(), null, null, null, null, + new BlobAccessConditions().setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)), null, null).getValue() bu2.abortCopyFromURLWithResponse(copyID, new LeaseAccessConditions().setLeaseId(garbageLeaseID), null, null) then: @@ -909,18 +912,20 @@ class BlobAPITest extends APISpec { def "Abort copy"() { setup: // Data has to be large enough and copied between accounts to give us enough time to abort - bc.asBlockBlobClient().upload(new ByteArrayInputStream(getRandomByteArray(8 * 1024 * 1024)), 8 * 1024 * 1024) + new SpecializedBlobClientBuilder().blobClient(bc) + .buildBlockBlobClient() + .upload(new ByteArrayInputStream(getRandomByteArray(8 * 1024 * 1024)), 8 * 1024 * 1024) // So we don't have to create a SAS. cc.setAccessPolicy(PublicAccessType.BLOB, null) - ContainerClient cu2 = alternateBlobServiceClient.getContainerClient(generateBlobName()) + def cu2 = alternateBlobServiceClient.getContainerClient(generateBlobName()) cu2.create() - BlobClient bu2 = cu2.getBlobClient(generateBlobName()) + def bu2 = cu2.getBlobClient(generateBlobName()) when: - String copyID = bu2.startCopyFromURLWithResponse(bc.getBlobUrl(), null, null, null, null, null, null, null).getValue() - Response response = bu2.abortCopyFromURLWithResponse(copyID, null, null, null) - HttpHeaders headers = response.getHeaders() + def copyID = bu2.startCopyFromURLWithResponse(bc.getBlobUrl(), null, null, null, null, null, null, null).getValue() + def response = bu2.abortCopyFromURLWithResponse(copyID, null, null, null) + def headers = response.getHeaders() then: response.getStatusCode() == 204 @@ -934,16 +939,18 @@ class BlobAPITest extends APISpec { def "Abort copy min"() { setup: // Data has to be large enough and copied between accounts to give us enough time to abort - bc.asBlockBlobClient().upload(new ByteArrayInputStream(getRandomByteArray(8 * 1024 * 1024)), 8 * 1024 * 1024) + new SpecializedBlobClientBuilder().blobClient(bc) + .buildBlockBlobClient() + .upload(new ByteArrayInputStream(getRandomByteArray(8 * 1024 * 1024)), 8 * 1024 * 1024) // So we don't have to create a SAS. cc.setAccessPolicy(PublicAccessType.BLOB, null) - ContainerClient cu2 = alternateBlobServiceClient.getContainerClient(generateBlobName()) + def cu2 = alternateBlobServiceClient.getContainerClient(generateBlobName()) cu2.create() - BlobClient bu2 = cu2.getBlobClient(generateBlobName()) + def bu2 = cu2.getBlobClient(generateBlobName()) when: - String copyID = bu2.startCopyFromURL(bc.getBlobUrl()) + def copyID = bu2.startCopyFromURL(bc.getBlobUrl()) then: bu2.abortCopyFromURLWithResponse(copyID, null, null, null).getStatusCode() == 204 @@ -952,18 +959,20 @@ class BlobAPITest extends APISpec { def "Abort copy lease"() { setup: // Data has to be large enough and copied between accounts to give us enough time to abort - bc.asBlockBlobClient().upload(new ByteArrayInputStream(getRandomByteArray(8 * 1024 * 1024)), 8 * 1024 * 1024) + new SpecializedBlobClientBuilder().blobClient(bc) + .buildBlockBlobClient() + .upload(new ByteArrayInputStream(getRandomByteArray(8 * 1024 * 1024)), 8 * 1024 * 1024) // So we don't have to create a SAS. cc.setAccessPolicy(PublicAccessType.BLOB, null) - ContainerClient cu2 = alternateBlobServiceClient.getContainerClient(generateContainerName()) + def cu2 = alternateBlobServiceClient.getContainerClient(generateContainerName()) cu2.create() - BlockBlobClient bu2 = cu2.getBlockBlobClient(generateBlobName()) + def bu2 = cu2.getBlobClient(generateBlobName()).asBlockBlobClient() bu2.upload(defaultInputStream.get(), defaultDataSize) - String leaseID = setupBlobLeaseCondition(bu2, receivedLeaseID) + def leaseID = setupBlobLeaseCondition(bu2, receivedLeaseID) when: - String copyID = + def copyID = bu2.startCopyFromURLWithResponse(bc.getBlobUrl(), null, null, null, null, new BlobAccessConditions().setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)), null, null).getValue() @@ -975,7 +984,7 @@ class BlobAPITest extends APISpec { def "Copy error"() { setup: - bc = cc.getBlockBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: bc.startCopyFromURL(new URL("http://www.error.com")) @@ -986,7 +995,7 @@ class BlobAPITest extends APISpec { def "Abort copy error"() { setup: - bc = cc.getBlockBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: bc.abortCopyFromURL("id") @@ -999,10 +1008,10 @@ class BlobAPITest extends APISpec { setup: // Sync copy is a deep copy, which requires either sas or public access. cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - BlobClient bu2 = cc.getBlockBlobClient(generateBlobName()) + def bu2 = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: - HttpHeaders headers = bu2.copyFromURLWithResponse(bc.getBlobUrl(), null, null, null, null, null, null).getHeaders() + def headers = bu2.copyFromURLWithResponse(bc.getBlobUrl(), null, null, null, null, null, null).getHeaders() then: headers.getValue("x-ms-copy-status") == SyncCopyStatusType.SUCCESS.toString() @@ -1013,7 +1022,7 @@ class BlobAPITest extends APISpec { def "Sync copy min"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - BlobClient bu2 = cc.getBlockBlobClient(generateBlobName()) + def bu2 = cc.getBlobClient(generateBlobName()).asBlockBlobClient() expect: bu2.copyFromURLWithResponse(bc.getBlobUrl(), null, null, null, null, null, null).getStatusCode() == 202 @@ -1023,8 +1032,8 @@ class BlobAPITest extends APISpec { def "Sync copy metadata"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - BlobClient bu2 = cc.getBlockBlobClient(generateBlobName()) - Metadata metadata = new Metadata() + def bu2 = cc.getBlobClient(generateBlobName()).asBlockBlobClient() + def metadata = new Metadata() if (key1 != null && value1 != null) { metadata.put(key1, value1) } @@ -1048,7 +1057,7 @@ class BlobAPITest extends APISpec { def "Sync copy source AC"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - BlobClient bu2 = cc.getBlockBlobClient(generateBlobName()) + def bu2 = cc.getBlobClient(generateBlobName()).asBlockBlobClient() match = setupBlobMatchCondition(bc, match) def mac = new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -1072,7 +1081,7 @@ class BlobAPITest extends APISpec { def "Sync copy source AC fail"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - BlobClient bu2 = cc.getBlockBlobClient(generateBlobName()) + def bu2 = cc.getBlobClient(generateBlobName()).asBlockBlobClient() noneMatch = setupBlobMatchCondition(bc, noneMatch) def mac = new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -1098,11 +1107,11 @@ class BlobAPITest extends APISpec { def "Sync copy dest AC"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - BlobClient bu2 = cc.getBlockBlobClient(generateBlobName()) + def bu2 = cc.getBlobClient(generateBlobName()).asBlockBlobClient() bu2.upload(defaultInputStream.get(), defaultDataSize) match = setupBlobMatchCondition(bu2, match) leaseID = setupBlobLeaseCondition(bu2, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -1127,11 +1136,11 @@ class BlobAPITest extends APISpec { def "Sync copy dest AC fail"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - BlobClient bu2 = cc.getBlockBlobClient(generateBlobName()) + def bu2 = cc.getBlobClient(generateBlobName()).asBlockBlobClient() bu2.upload(defaultInputStream.get(), defaultDataSize) noneMatch = setupBlobMatchCondition(bu2, noneMatch) setupBlobLeaseCondition(bu2, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -1156,7 +1165,7 @@ class BlobAPITest extends APISpec { def "Sync copy error"() { setup: - def bu2 = cc.getBlockBlobClient(generateBlobName()) + def bu2 = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: bu2.copyFromURL(bc.getBlobUrl()) @@ -1167,8 +1176,8 @@ class BlobAPITest extends APISpec { def "Delete"() { when: - Response response = bc.deleteWithResponse(null, null, null, null) - HttpHeaders headers = response.getHeaders() + def response = bc.deleteWithResponse(null, null, null, null) + def headers = response.getHeaders() then: response.getStatusCode() == 202 @@ -1187,7 +1196,7 @@ class BlobAPITest extends APISpec { setup: bc.createSnapshot() // Create an extra blob so the list isn't empty (null) when we delete base blob, too - BlockBlobClient bu2 = cc.getBlockBlobClient(generateBlobName()) + def bu2 = cc.getBlobClient(generateBlobName()).asBlockBlobClient() bu2.upload(defaultInputStream.get(), defaultDataSize) when: @@ -1207,7 +1216,7 @@ class BlobAPITest extends APISpec { setup: match = setupBlobMatchCondition(bc, match) leaseID = setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -1233,7 +1242,7 @@ class BlobAPITest extends APISpec { setup: noneMatch = setupBlobMatchCondition(bc, noneMatch) setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -1258,7 +1267,7 @@ class BlobAPITest extends APISpec { def "Blob delete error"() { setup: - bc = cc.getBlockBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: bc.delete() @@ -1270,13 +1279,13 @@ class BlobAPITest extends APISpec { @Unroll def "Set tier block blob"() { setup: - ContainerClient cc = blobServiceClient.createContainer(generateContainerName()) - BlockBlobClient bc = cc.getBlockBlobClient(generateBlobName()) + def cc = blobServiceClient.createContainer(generateContainerName()) + def bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() bc.upload(defaultInputStream.get(), defaultData.remaining()) when: - Response initialResponse = bc.setTierWithResponse(tier, null, null, null, null) - HttpHeaders headers = initialResponse.getHeaders() + def initialResponse = bc.setTierWithResponse(tier, null, null, null, null) + def headers = initialResponse.getHeaders() then: initialResponse.getStatusCode() == 200 || initialResponse.getStatusCode() == 202 @@ -1298,9 +1307,9 @@ class BlobAPITest extends APISpec { @Unroll def "Set tier page blob"() { setup: - ContainerClient cc = premiumBlobServiceClient.createContainer(generateContainerName()) + def cc = premiumBlobServiceClient.createContainer(generateContainerName()) - def bc = cc.getPageBlobClient(generateBlobName()) + def bc = cc.getBlobClient(generateBlobName()).asPageBlobClient() bc.create(512) when: @@ -1326,12 +1335,12 @@ class BlobAPITest extends APISpec { def "Set tier min"() { setup: - ContainerClient cc = blobServiceClient.createContainer(generateContainerName()) - BlockBlobClient bu = cc.getBlockBlobClient(generateBlobName()) + def cc = blobServiceClient.createContainer(generateContainerName()) + def bu = cc.getBlobClient(generateBlobName()).asBlockBlobClient() bu.upload(defaultInputStream.get(), defaultData.remaining()) when: - int statusCode = bc.setTierWithResponse(AccessTier.HOT, null, null, null, null).getStatusCode() + def statusCode = bc.setTierWithResponse(AccessTier.HOT, null, null, null, null).getStatusCode() then: statusCode == 200 || statusCode == 202 @@ -1343,17 +1352,17 @@ class BlobAPITest extends APISpec { def "Set tier inferred"() { setup: def cc = blobServiceClient.createContainer(generateBlobName()) - def bc = cc.getBlockBlobClient(generateBlobName()) + def bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() bc.upload(defaultInputStream.get(), defaultDataSize) when: - boolean inferred1 = bc.getProperties().isAccessTierInferred() - Boolean inferredList1 = cc.listBlobsFlat().iterator().next().getProperties().isAccessTierInferred() + def inferred1 = bc.getProperties().isAccessTierInferred() + def inferredList1 = cc.listBlobsFlat().iterator().next().getProperties().isAccessTierInferred() bc.setTier(AccessTier.HOT) - boolean inferred2 = bc.getProperties().isAccessTierInferred() - Boolean inferredList2 = cc.listBlobsFlat().iterator().next().getProperties().isAccessTierInferred() + def inferred2 = bc.getProperties().isAccessTierInferred() + def inferredList2 = cc.listBlobsFlat().iterator().next().getProperties().isAccessTierInferred() then: inferred1 @@ -1366,7 +1375,7 @@ class BlobAPITest extends APISpec { def "Set tier archive status"() { setup: def cc = blobServiceClient.createContainer(generateBlobName()) - def bc = cc.getBlockBlobClient(generateBlobName()) + def bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() bc.upload(defaultInputStream.get(), defaultDataSize) when: @@ -1387,7 +1396,7 @@ class BlobAPITest extends APISpec { def "Set tier error"() { setup: def cc = blobServiceClient.createContainer(generateContainerName()) - def bc = cc.getBlockBlobClient(generateBlobName()) + def bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() bc.upload(defaultInputStream.get(), defaultDataSize) when: @@ -1413,7 +1422,7 @@ class BlobAPITest extends APISpec { setup: def cc = blobServiceClient.createContainer(generateContainerName()) - def bc = cc.getBlockBlobClient(generateBlobName()) + def bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() bc.upload(defaultInputStream.get(), defaultDataSize) def leaseID = setupBlobLeaseCondition(bc, receivedLeaseID) @@ -1430,7 +1439,7 @@ class BlobAPITest extends APISpec { def "Set tier lease fail"() { setup: def cc = blobServiceClient.createContainer(generateContainerName()) - def bc = cc.getBlockBlobClient(generateBlobName()) + def bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() bc.upload(defaultInputStream.get(), defaultDataSize) when: @@ -1443,9 +1452,9 @@ class BlobAPITest extends APISpec { @Unroll def "Copy with tier"() { setup: - def bc = cc.getBlockBlobClient(generateBlobName()) + def bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() bc.uploadWithResponse(defaultInputStream.get(), defaultDataSize, null, null, tier1, null, null, null) - def bcCopy = cc.getBlockBlobClient(generateBlobName()) + def bcCopy = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: bcCopy.copyFromURLWithResponse(new URL(bc.getBlobUrl().toString() + "?" + bc.generateSAS(OffsetDateTime.now().plusHours(1), new BlobSASPermission().setReadPermission(true))), null, tier2, null, null, null, null) @@ -1487,7 +1496,7 @@ class BlobAPITest extends APISpec { } def "Undelete error"() { - bc = cc.getBlockBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: bc.undelete() @@ -1498,7 +1507,7 @@ class BlobAPITest extends APISpec { def "Get account info"() { when: - Response response = primaryBlobServiceClient.getAccountInfoWithResponse(null, null) + def response = primaryBlobServiceClient.getAccountInfoWithResponse(null, null) then: response.getHeaders().getValue("Date") != null @@ -1515,7 +1524,7 @@ class BlobAPITest extends APISpec { def "Get account info error"() { when: - BlobServiceClient serviceURL = getServiceClient(primaryBlobServiceClient.getAccountUrl().toString()) + def serviceURL = getServiceClient(primaryBlobServiceClient.getAccountUrl().toString()) serviceURL.getContainerClient(generateContainerName()).getBlobClient(generateBlobName()).getAccountInfo() diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobOutputStreamTest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobOutputStreamTest.groovy index 67e59863b4f1..8969c7080bdc 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobOutputStreamTest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobOutputStreamTest.groovy @@ -1,19 +1,21 @@ package com.azure.storage.blob + import com.azure.storage.common.Constants import spock.lang.Ignore +import spock.lang.Requires class BlobOutputStreamTest extends APISpec { private static int FOUR_MB = 4 * Constants.MB - @Ignore + @Requires({ liveMode() }) def "BlockBlob output stream"() { setup: - byte[] data = getRandomByteArray(100 * Constants.MB) - BlockBlobClient blockBlobClient = cc.getBlockBlobClient(generateBlobName()) + def data = getRandomByteArray(10 * Constants.MB) + def blockBlobClient = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: - BlobOutputStream outputStream = blockBlobClient.getBlobOutputStream() + def outputStream = blockBlobClient.getBlobOutputStream() outputStream.write(data) outputStream.close() @@ -22,16 +24,16 @@ class BlobOutputStreamTest extends APISpec { convertInputStreamToByteArray(blockBlobClient.openInputStream()) == data } - @Ignore + @Requires({ liveMode() }) def "PageBlob output stream"() { setup: - byte[] data = getRandomByteArray(1024 * Constants.MB - 512) - PageBlobClient pageBlobClient = cc.getPageBlobClient(generateBlobName()) + def data = getRandomByteArray(16 * Constants.MB - 512) + def pageBlobClient = cc.getBlobClient(generateBlobName()).asPageBlobClient() pageBlobClient.create(data.length) when: - BlobOutputStream outputStream = pageBlobClient.getBlobOutputStream(data.length) + def outputStream = pageBlobClient.getBlobOutputStream(data.length) outputStream.write(data) outputStream.close() @@ -42,13 +44,13 @@ class BlobOutputStreamTest extends APISpec { @Ignore def "AppendBlob output stream"() { setup: - byte[] data = getRandomByteArray(64 * FOUR_MB) - AppendBlobClient appendBlobClient = cc.getAppendBlobClient(generateBlobName()) + def data = getRandomByteArray(4 * FOUR_MB) + def appendBlobClient = cc.getBlobClient(generateBlobName()).asAppendBlobClient() appendBlobClient.create() when: - BlobOutputStream outputStream = appendBlobClient.getBlobOutputStream() - for (int i = 0; i != 64; i++) { + def outputStream = appendBlobClient.getBlobOutputStream() + for (int i = 0; i != 4; i++) { outputStream.write(Arrays.copyOfRange(data, i * FOUR_MB, ((i + 1) * FOUR_MB) - 1)) } outputStream.close() @@ -58,7 +60,7 @@ class BlobOutputStreamTest extends APISpec { convertInputStreamToByteArray(appendBlobClient.openInputStream()) == data } - private static byte[] convertInputStreamToByteArray(InputStream inputStream) { + def convertInputStreamToByteArray(InputStream inputStream) { int b ByteArrayOutputStream outputStream = new ByteArrayOutputStream() try { diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlockBlobInputOutputStreamTest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlockBlobInputOutputStreamTest.groovy index a11adbd4d104..b2883020e4c3 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlockBlobInputOutputStreamTest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlockBlobInputOutputStreamTest.groovy @@ -1,5 +1,7 @@ package com.azure.storage.blob + +import com.azure.storage.blob.specialized.BlockBlobClient import com.azure.storage.common.Constants import spock.lang.Requires @@ -7,24 +9,24 @@ class BlockBlobInputOutputStreamTest extends APISpec { BlockBlobClient bc def setup() { - bc = cc.getBlockBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() } // Only run this test in live mode as BlobOutputStream dynamically assigns blocks - @Requires({ APISpec.liveMode() }) + @Requires({ liveMode() }) def "Upload download"() { when: - int length = 30 * Constants.MB - byte[] randomBytes = getRandomByteArray(length) + def length = 30 * Constants.MB + def randomBytes = getRandomByteArray(length) - BlobOutputStream outStream = bc.getBlobOutputStream() + def outStream = bc.getBlobOutputStream() outStream.write(randomBytes) outStream.close() then: - BlobInputStream inputStream = bc.openInputStream() + def inputStream = bc.openInputStream() int b - ByteArrayOutputStream outputStream = new ByteArrayOutputStream() + def outputStream = new ByteArrayOutputStream() try { while ((b = inputStream.read()) != -1) { outputStream.write(b) @@ -32,7 +34,6 @@ class BlockBlobInputOutputStreamTest extends APISpec { } catch (IOException ex) { throw new UncheckedIOException(ex) } - byte[] randomBytes2 = outputStream.toByteArray() - assert randomBytes2 == randomBytes + assert outputStream.toByteArray() == randomBytes } } diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/CPKTest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/CPKTest.groovy index 7faedabb54a2..a3f6050006bc 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/CPKTest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/CPKTest.groovy @@ -4,6 +4,10 @@ import com.azure.core.http.policy.HttpLogDetailLevel import com.azure.storage.blob.models.CustomerProvidedKey import com.azure.storage.blob.models.Metadata import com.azure.storage.blob.models.PageRange +import com.azure.storage.blob.specialized.AppendBlobClient +import com.azure.storage.blob.specialized.BlobClientBase +import com.azure.storage.blob.specialized.BlockBlobClient +import com.azure.storage.blob.specialized.PageBlobClient import com.azure.storage.common.Constants import java.time.OffsetDateTime @@ -15,7 +19,7 @@ class CPKTest extends APISpec { BlockBlobClient cpkBlockBlob PageBlobClient cpkPageBlob AppendBlobClient cpkAppendBlob - BlobClient cpkExistingBlob + BlobClientBase cpkExistingBlob def setup() { key = new CustomerProvidedKey(getRandomKey()) @@ -29,11 +33,11 @@ class CPKTest extends APISpec { addOptionalRecording(builder) cpkContainer = builder.buildClient() - cpkBlockBlob = cpkContainer.getBlockBlobClient(generateBlobName()) - cpkPageBlob = cpkContainer.getPageBlobClient(generateBlobName()) - cpkAppendBlob = cpkContainer.getAppendBlobClient(generateBlobName()) + cpkBlockBlob = cpkContainer.getBlobClient(generateBlobName()).asBlockBlobClient() + cpkPageBlob = cpkContainer.getBlobClient(generateBlobName()).asPageBlobClient() + cpkAppendBlob = cpkContainer.getBlobClient(generateBlobName()).asAppendBlobClient() - def existingBlobSetup = cpkContainer.getBlockBlobClient(generateBlobName()) + def existingBlobSetup = cpkContainer.getBlobClient(generateBlobName()).asBlockBlobClient() existingBlobSetup.upload(defaultInputStream.get(), defaultDataSize) cpkExistingBlob = existingBlobSetup } @@ -84,7 +88,7 @@ class CPKTest extends APISpec { def "Put block from URL with CPK"() { setup: - def sourceBlob = cc.getBlockBlobClient(generateBlobName()) + def sourceBlob = cc.getBlobClient(generateBlobName()).asBlockBlobClient() sourceBlob.upload(defaultInputStream.get(), defaultDataSize) when: @@ -129,7 +133,7 @@ class CPKTest extends APISpec { def "Put page from URL wih CPK"() { setup: - def sourceBlob = cc.getPageBlobClient(generateBlobName()) + def sourceBlob = cc.getBlobClient(generateBlobName()).asPageBlobClient() sourceBlob.create(PageBlobClient.PAGE_BYTES) sourceBlob.uploadPagesWithResponse(new PageRange().setStart(0).setEnd(PageBlobClient.PAGE_BYTES - 1), new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES)), null, null, null) @@ -178,7 +182,7 @@ class CPKTest extends APISpec { def "Append block from URL with CPK"() { setup: cpkAppendBlob.create() - def sourceBlob = cc.getBlockBlobClient(generateBlobName()) + def sourceBlob = cc.getBlobClient(generateBlobName()).asBlockBlobClient() sourceBlob.upload(defaultInputStream.get(), defaultDataSize) when: diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy index 11bb676ccad6..df52eaddd3df 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy @@ -4,15 +4,11 @@ package com.azure.storage.blob import com.azure.core.http.rest.Response - import com.azure.storage.blob.models.AccessPolicy import com.azure.storage.blob.models.AccessTier -import com.azure.storage.blob.models.AppendBlobItem -import com.azure.storage.blob.models.BlobItem import com.azure.storage.blob.models.BlobListDetails import com.azure.storage.blob.models.BlobType import com.azure.storage.blob.models.ContainerAccessConditions -import com.azure.storage.blob.models.ContainerAccessPolicies import com.azure.storage.blob.models.CopyStatusType import com.azure.storage.blob.models.LeaseAccessConditions import com.azure.storage.blob.models.LeaseStateType @@ -24,6 +20,7 @@ import com.azure.storage.blob.models.PublicAccessType import com.azure.storage.blob.models.SignedIdentifier import com.azure.storage.blob.models.StorageErrorCode import com.azure.storage.blob.models.StorageException +import com.azure.storage.blob.specialized.BlobClientBase import spock.lang.Unroll import java.time.Duration @@ -132,7 +129,7 @@ class ContainerAPITest extends APISpec { def "Get properties lease"() { setup: - String leaseID = setupContainerLeaseCondition(cc, receivedLeaseID) + def leaseID = setupContainerLeaseCondition(cc, receivedLeaseID) expect: cc.getPropertiesWithResponse(new LeaseAccessConditions().setLeaseId(leaseID), null, null).getStatusCode() == 200 @@ -160,7 +157,7 @@ class ContainerAPITest extends APISpec { def "Set metadata"() { setup: cc = primaryBlobServiceClient.getContainerClient(generateContainerName()) - Metadata metadata = new Metadata() + def metadata = new Metadata() metadata.put("key", "value") cc.createWithResponse(metadata, null, null, null) @@ -210,7 +207,7 @@ class ContainerAPITest extends APISpec { def "Set metadata AC"() { setup: leaseID = setupContainerLeaseCondition(cc, leaseID) - ContainerAccessConditions cac = new ContainerAccessConditions() + def cac = new ContainerAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified)) @@ -228,7 +225,7 @@ class ContainerAPITest extends APISpec { @Unroll def "Set metadata AC fail"() { setup: - ContainerAccessConditions cac = new ContainerAccessConditions() + def cac = new ContainerAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified)) @@ -248,7 +245,7 @@ class ContainerAPITest extends APISpec { @Unroll def "Set metadata AC illegal"() { setup: - ModifiedAccessConditions mac = new ModifiedAccessConditions() + def mac = new ModifiedAccessConditions() .setIfUnmodifiedSince(unmodified) .setIfMatch(match) .setIfNoneMatch(noneMatch) @@ -303,7 +300,7 @@ class ContainerAPITest extends APISpec { def "Set access policy min ids"() { setup: - SignedIdentifier identifier = new SignedIdentifier() + def identifier = new SignedIdentifier() .setId("0000") .setAccessPolicy(new AccessPolicy() .setStart(OffsetDateTime.now().atZoneSameInstant(ZoneId.of("UTC")).toOffsetDateTime()) @@ -311,8 +308,7 @@ class ContainerAPITest extends APISpec { .plusDays(1)) .setPermission("r")) - def ids = [] - ids.push(identifier) + def ids = [ identifier ] as List when: cc.setAccessPolicy(null, ids) @@ -323,21 +319,19 @@ class ContainerAPITest extends APISpec { def "Set access policy ids"() { setup: - SignedIdentifier identifier = new SignedIdentifier() + def identifier = new SignedIdentifier() .setId("0000") .setAccessPolicy(new AccessPolicy() .setStart(getUTCNow()) .setExpiry(getUTCNow().plusDays(1)) .setPermission("r")) - SignedIdentifier identifier2 = new SignedIdentifier() + def identifier2 = new SignedIdentifier() .setId("0001") .setAccessPolicy(new AccessPolicy() .setStart(getUTCNow()) .setExpiry(getUTCNow().plusDays(2)) .setPermission("w")) - List ids = new ArrayList<>() - ids.add(identifier) - ids.add(identifier2) + def ids = [ identifier, identifier2 ] as List when: def response = cc.setAccessPolicyWithResponse(null, ids, null, null, null) @@ -358,7 +352,7 @@ class ContainerAPITest extends APISpec { def "Set access policy AC"() { setup: leaseID = setupContainerLeaseCondition(cc, leaseID) - ContainerAccessConditions cac = new ContainerAccessConditions() + def cac = new ContainerAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -378,7 +372,7 @@ class ContainerAPITest extends APISpec { @Unroll def "Set access policy AC fail"() { setup: - ContainerAccessConditions cac = new ContainerAccessConditions() + def cac = new ContainerAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -400,7 +394,7 @@ class ContainerAPITest extends APISpec { @Unroll def "Set access policy AC illegal"() { setup: - ModifiedAccessConditions mac = new ModifiedAccessConditions().setIfMatch(match).setIfNoneMatch(noneMatch) + def mac = new ModifiedAccessConditions().setIfMatch(match).setIfNoneMatch(noneMatch) when: cc.setAccessPolicyWithResponse(null, null, new ContainerAccessConditions().setModifiedAccessConditions(mac), null, null) @@ -427,16 +421,15 @@ class ContainerAPITest extends APISpec { def "Get access policy"() { setup: - SignedIdentifier identifier = new SignedIdentifier() + def identifier = new SignedIdentifier() .setId("0000") .setAccessPolicy(new AccessPolicy() .setStart(getUTCNow()) .setExpiry(getUTCNow().plusDays(1)) .setPermission("r")) - List ids = new ArrayList<>() - ids.push(identifier) + def ids = [ identifier ] as List cc.setAccessPolicy(PublicAccessType.BLOB, ids) - Response response = cc.getAccessPolicyWithResponse(null, null, null) + def response = cc.getAccessPolicyWithResponse(null, null, null) expect: response.getStatusCode() == 200 @@ -449,7 +442,7 @@ class ContainerAPITest extends APISpec { def "Get access policy lease"() { setup: - String leaseID = setupContainerLeaseCondition(cc, receivedLeaseID) + def leaseID = setupContainerLeaseCondition(cc, receivedLeaseID) expect: cc.getAccessPolicyWithResponse(new LeaseAccessConditions().setLeaseId(leaseID), null, null).getStatusCode() == 200 @@ -476,7 +469,7 @@ class ContainerAPITest extends APISpec { def "Delete"() { when: - Response response = cc.deleteWithResponse(null, null, null) + def response = cc.deleteWithResponse(null, null, null) then: response.getStatusCode() == 202 @@ -497,7 +490,7 @@ class ContainerAPITest extends APISpec { def "Delete AC"() { setup: leaseID = setupContainerLeaseCondition(cc, leaseID) - ContainerAccessConditions cac = new ContainerAccessConditions() + def cac = new ContainerAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -517,7 +510,7 @@ class ContainerAPITest extends APISpec { @Unroll def "Delete AC fail"() { setup: - ContainerAccessConditions cac = new ContainerAccessConditions() + def cac = new ContainerAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -539,7 +532,7 @@ class ContainerAPITest extends APISpec { @Unroll def "Delete AC illegal"() { setup: - ModifiedAccessConditions mac = new ModifiedAccessConditions().setIfMatch(match).setIfNoneMatch(noneMatch) + def mac = new ModifiedAccessConditions().setIfMatch(match).setIfNoneMatch(noneMatch) when: cc.deleteWithResponse(new ContainerAccessConditions().setModifiedAccessConditions(mac), null, null) @@ -566,12 +559,12 @@ class ContainerAPITest extends APISpec { def "List blobs flat"() { setup: - String name = generateBlobName() - PageBlobClient bu = cc.getPageBlobClient(name) + def name = generateBlobName() + def bu = cc.getBlobClient(name).asPageBlobClient() bu.create(512) when: - Iterator blobs = cc.listBlobsFlat().iterator() + def blobs = cc.listBlobsFlat().iterator() //ContainerListBlobFlatSegmentHeaders headers = response.headers() //List blobs = responseiterator()() @@ -582,7 +575,7 @@ class ContainerAPITest extends APISpec { // headers.requestId() != null // headers.getVersion() != null // headers.date() != null - BlobItem blob = blobs.next() + def blob = blobs.next() !blobs.hasNext() blob.getName() == name blob.getProperties().getBlobType() == BlobType.PAGE_BLOB @@ -621,10 +614,10 @@ class ContainerAPITest extends APISpec { } def setupListBlobsTest(String normalName, String copyName, String metadataName, String uncommittedName) { - def normal = cc.getPageBlobClient(normalName) + def normal = cc.getBlobClient(normalName).asPageBlobClient() normal.create(512) - def copyBlob = cc.getPageBlobClient(copyName) + def copyBlob = cc.getBlobClient(copyName).asPageBlobClient() copyBlob.startCopyFromURL(normal.getBlobUrl()) def start = OffsetDateTime.now() @@ -638,40 +631,31 @@ class ContainerAPITest extends APISpec { sleepIfRecord(1000) } - def metadataBlob = cc.getPageBlobClient(metadataName) + def metadataBlob = cc.getBlobClient(metadataName).asPageBlobClient() def values = new Metadata() values.put("foo", "bar") metadataBlob.createWithResponse(512, null, null, values, null, null, null) def snapshotTime = normal.createSnapshot().getSnapshotId() - def uncommittedBlob = cc.getBlockBlobClient(uncommittedName) + def uncommittedBlob = cc.getBlobClient(uncommittedName).asBlockBlobClient() uncommittedBlob.stageBlock("0000", defaultInputStream.get(), defaultData.remaining()) return snapshotTime } - def blobListResponseToList(Iterator blobs) { - ArrayList blobQueue = new ArrayList<>() - while (blobs.hasNext()) { - blobQueue.add(blobs.next()) - } - - return blobQueue - } - def "List blobs flat options copy"() { setup: - ListBlobsOptions options = new ListBlobsOptions().setDetails(new BlobListDetails().setCopy(true)) - String normalName = "a" + generateBlobName() - String copyName = "c" + generateBlobName() - String metadataName = "m" + generateBlobName() - String uncommittedName = "u" + generateBlobName() + def options = new ListBlobsOptions().setDetails(new BlobListDetails().setCopy(true)) + def normalName = "a" + generateBlobName() + def copyName = "c" + generateBlobName() + def metadataName = "m" + generateBlobName() + def uncommittedName = "u" + generateBlobName() setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) when: - List blobs = blobListResponseToList(cc.listBlobsFlat(options, null).iterator()) + def blobs = cc.listBlobsFlat(options, null).stream().collect(Collectors.toList()) then: blobs.get(0).getName() == normalName @@ -687,15 +671,15 @@ class ContainerAPITest extends APISpec { def "List blobs flat options metadata"() { setup: - ListBlobsOptions options = new ListBlobsOptions().setDetails(new BlobListDetails().setMetadata(true)) - String normalName = "a" + generateBlobName() - String copyName = "c" + generateBlobName() - String metadataName = "m" + generateBlobName() - String uncommittedName = "u" + generateBlobName() + def options = new ListBlobsOptions().setDetails(new BlobListDetails().setMetadata(true)) + def normalName = "a" + generateBlobName() + def copyName = "c" + generateBlobName() + def metadataName = "m" + generateBlobName() + def uncommittedName = "u" + generateBlobName() setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) when: - List blobs = blobListResponseToList(cc.listBlobsFlat(options, null).iterator()) + def blobs = cc.listBlobsFlat(options, null).stream().collect(Collectors.toList()) then: blobs.get(0).getName() == normalName @@ -708,15 +692,15 @@ class ContainerAPITest extends APISpec { def "List blobs flat options snapshots"() { setup: - ListBlobsOptions options = new ListBlobsOptions().setDetails(new BlobListDetails().setSnapshots(true)) - String normalName = "a" + generateBlobName() - String copyName = "c" + generateBlobName() - String metadataName = "m" + generateBlobName() - String uncommittedName = "u" + generateBlobName() - String snapshotTime = setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) + def options = new ListBlobsOptions().setDetails(new BlobListDetails().setSnapshots(true)) + def normalName = "a" + generateBlobName() + def copyName = "c" + generateBlobName() + def metadataName = "m" + generateBlobName() + def uncommittedName = "u" + generateBlobName() + def snapshotTime = setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) when: - List blobs = blobListResponseToList(cc.listBlobsFlat(options, null).iterator()) + def blobs = cc.listBlobsFlat(options, null).stream().collect(Collectors.toList()) then: blobs.get(0).getName() == normalName @@ -727,15 +711,15 @@ class ContainerAPITest extends APISpec { def "List blobs flat options uncommitted"() { setup: - ListBlobsOptions options = new ListBlobsOptions().setDetails(new BlobListDetails().setUncommittedBlobs(true)) - String normalName = "a" + generateBlobName() - String copyName = "c" + generateBlobName() - String metadataName = "m" + generateBlobName() - String uncommittedName = "u" + generateBlobName() + def options = new ListBlobsOptions().setDetails(new BlobListDetails().setUncommittedBlobs(true)) + def normalName = "a" + generateBlobName() + def copyName = "c" + generateBlobName() + def metadataName = "m" + generateBlobName() + def uncommittedName = "u" + generateBlobName() setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) when: - List blobs = blobListResponseToList(cc.listBlobsFlat(options, null).iterator()) + def blobs = cc.listBlobsFlat(options, null).stream().collect(Collectors.toList()) then: blobs.get(0).getName() == normalName @@ -746,14 +730,14 @@ class ContainerAPITest extends APISpec { def "List blobs flat options deleted"() { setup: enableSoftDelete() - String name = generateBlobName() - AppendBlobClient bu = cc.getAppendBlobClient(name) + def name = generateBlobName() + def bu = cc.getBlobClient(name).asAppendBlobClient() bu.create() bu.delete() when: - ListBlobsOptions options = new ListBlobsOptions().setDetails(new BlobListDetails().setDeletedBlobs(true)) - Iterator blobs = cc.listBlobsFlat(options, null).iterator() + def options = new ListBlobsOptions().setDetails(new BlobListDetails().setDeletedBlobs(true)) + def blobs = cc.listBlobsFlat(options, null).iterator() then: blobs.next().getName() == name @@ -764,15 +748,15 @@ class ContainerAPITest extends APISpec { def "List blobs flat options prefix"() { setup: - ListBlobsOptions options = new ListBlobsOptions().setPrefix("a") - String normalName = "a" + generateBlobName() - String copyName = "c" + generateBlobName() - String metadataName = "m" + generateBlobName() - String uncommittedName = "u" + generateBlobName() + def options = new ListBlobsOptions().setPrefix("a") + def normalName = "a" + generateBlobName() + def copyName = "c" + generateBlobName() + def metadataName = "m" + generateBlobName() + def uncommittedName = "u" + generateBlobName() setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) when: - Iterator blobs = cc.listBlobsFlat(options, null).iterator() + def blobs = cc.listBlobsFlat(options, null).iterator() then: blobs.next().getName() == normalName @@ -808,7 +792,7 @@ class ContainerAPITest extends APISpec { def NUM_BLOBS = 10 def PAGE_SIZE = 6 for (int i = 0; i < NUM_BLOBS ; i++) { - PageBlobClient bc = cc.getPageBlobClient(generateBlobName()) + def bc = cc.getBlobClient(generateBlobName()).asPageBlobClient() bc.create(512) } @@ -850,9 +834,9 @@ class ContainerAPITest extends APISpec { def NUM_BLOBS = 5 def PAGE_RESULTS = 3 - def blobs = [] as Collection + def blobs = [] as Collection for (i in (1..NUM_BLOBS)) { - def blob = cc.getBlockBlobClient(generateBlobName()) + def blob = cc.getBlobClient(generateBlobName()).asBlockBlobClient() blob.upload(defaultInputStream.get(), defaultDataSize) blobs << blob } @@ -869,9 +853,9 @@ class ContainerAPITest extends APISpec { def NUM_BLOBS = 5 def PAGE_RESULTS = 3 - def blobs = [] as Collection + def blobs = [] as Collection for (i in (1..NUM_BLOBS)) { - def blob = cc.getBlockBlobClient(generateBlobName()) + def blob = cc.getBlobClient(generateBlobName()).asBlockBlobClient() blob.upload(defaultInputStream.get(), defaultDataSize) blobs << blob } @@ -885,12 +869,12 @@ class ContainerAPITest extends APISpec { def "List blobs hierarchy"() { setup: - String name = generateBlobName() - PageBlobClient bu = cc.getPageBlobClient(name) + def name = generateBlobName() + def bu = cc.getBlobClient(name).asPageBlobClient() bu.create(512) when: - Iterator blobs = cc.listBlobsHierarchy(null).iterator() + def blobs = cc.listBlobsHierarchy(null).iterator() then: // response.getStatusCode() == 200 @@ -912,15 +896,15 @@ class ContainerAPITest extends APISpec { def "List blobs hier options copy"() { setup: - ListBlobsOptions options = new ListBlobsOptions().setDetails(new BlobListDetails().setCopy(true)) - String normalName = "a" + generateBlobName() - String copyName = "c" + generateBlobName() - String metadataName = "m" + generateBlobName() - String uncommittedName = "u" + generateBlobName() + def options = new ListBlobsOptions().setDetails(new BlobListDetails().setCopy(true)) + def normalName = "a" + generateBlobName() + def copyName = "c" + generateBlobName() + def metadataName = "m" + generateBlobName() + def uncommittedName = "u" + generateBlobName() setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) when: - List blobs = blobListResponseToList(cc.listBlobsHierarchy("", options, null).iterator()) + def blobs = cc.listBlobsHierarchy("", options, null).stream().collect(Collectors.toList()) then: blobs.get(0).getName() == normalName @@ -936,15 +920,15 @@ class ContainerAPITest extends APISpec { def "List blobs hier options metadata"() { setup: - ListBlobsOptions options = new ListBlobsOptions().setDetails(new BlobListDetails().setMetadata(true)) - String normalName = "a" + generateBlobName() - String copyName = "c" + generateBlobName() - String metadataName = "m" + generateBlobName() - String uncommittedName = "u" + generateBlobName() + def options = new ListBlobsOptions().setDetails(new BlobListDetails().setMetadata(true)) + def normalName = "a" + generateBlobName() + def copyName = "c" + generateBlobName() + def metadataName = "m" + generateBlobName() + def uncommittedName = "u" + generateBlobName() setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) when: - List blobs = blobListResponseToList(cc.listBlobsHierarchy("", options, null).iterator()) + def blobs = cc.listBlobsHierarchy("", options, null).stream().collect(Collectors.toList()) then: blobs.get(0).getName() == normalName @@ -957,15 +941,15 @@ class ContainerAPITest extends APISpec { def "List blobs hier options uncommitted"() { setup: - ListBlobsOptions options = new ListBlobsOptions().setDetails(new BlobListDetails().setUncommittedBlobs(true)) - String normalName = "a" + generateBlobName() - String copyName = "c" + generateBlobName() - String metadataName = "m" + generateBlobName() - String uncommittedName = "u" + generateBlobName() + def options = new ListBlobsOptions().setDetails(new BlobListDetails().setUncommittedBlobs(true)) + def normalName = "a" + generateBlobName() + def copyName = "c" + generateBlobName() + def metadataName = "m" + generateBlobName() + def uncommittedName = "u" + generateBlobName() setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) when: - List blobs = blobListResponseToList(cc.listBlobsHierarchy("", options, null).iterator()) + def blobs = cc.listBlobsHierarchy("", options, null).stream().collect(Collectors.toList()) then: blobs.get(0).getName() == normalName @@ -977,7 +961,7 @@ class ContainerAPITest extends APISpec { setup: enableSoftDelete() def name = generateBlobName() - def bc = cc.getAppendBlobClient(name) + def bc = cc.getBlobClient(name).asAppendBlobClient() bc.create() bc.delete() @@ -994,15 +978,15 @@ class ContainerAPITest extends APISpec { def "List blobs hier options prefix"() { setup: - ListBlobsOptions options = new ListBlobsOptions().setPrefix("a") - String normalName = "a" + generateBlobName() - String copyName = "c" + generateBlobName() - String metadataName = "m" + generateBlobName() - String uncommittedName = "u" + generateBlobName() + def options = new ListBlobsOptions().setPrefix("a") + def normalName = "a" + generateBlobName() + def copyName = "c" + generateBlobName() + def metadataName = "m" + generateBlobName() + def uncommittedName = "u" + generateBlobName() setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) when: - Iterator blobs = cc.listBlobsHierarchy("", options, null).iterator() + def blobs = cc.listBlobsHierarchy("", options, null).iterator() then: blobs.next().getName() == normalName @@ -1048,7 +1032,7 @@ class ContainerAPITest extends APISpec { setup: def blobNames = ["a", "b/a", "c", "d/a", "e", "f", "g/a"] for (def blobName : blobNames) { - def bu = cc.getAppendBlobClient(blobName) + def bu = cc.getBlobClient(blobName).asAppendBlobClient() bu.create() } @@ -1079,7 +1063,7 @@ class ContainerAPITest extends APISpec { def NUM_BLOBS = 10 def PAGE_SIZE = 6 for (int i = 0; i < NUM_BLOBS; i++) { - PageBlobClient bc = cc.getPageBlobClient(generateBlobName()) + def bc = cc.getBlobClient(generateBlobName()).asPageBlobClient() bc.create(512) } @@ -1105,7 +1089,7 @@ class ContainerAPITest extends APISpec { def NUM_BLOBS = 10 def PAGE_SIZE = 3 for (int i = 0; i < NUM_BLOBS; i++) { - def bc = cc.getPageBlobClient(generateBlobName()) + def bc = cc.getBlobClient(generateBlobName()).asPageBlobClient() bc.create(512) } @@ -1128,10 +1112,10 @@ class ContainerAPITest extends APISpec { def "Create URL special chars"() { // This test checks that we encode special characters in blob names correctly. setup: - AppendBlobClient bu2 = cc.getAppendBlobClient(name) - PageBlobClient bu3 = cc.getPageBlobClient(name + "2") - BlockBlobClient bu4 = cc.getBlockBlobClient(name + "3") - BlockBlobClient bu5 = cc.getBlockBlobClient(name) + def bu2 = cc.getBlobClient(name).asAppendBlobClient() + def bu3 = cc.getBlobClient(name + "2").asPageBlobClient() + def bu4 = cc.getBlobClient(name + "3").asBlockBlobClient() + def bu5 = cc.getBlobClient(name).asBlockBlobClient() expect: bu2.createWithResponse(null, null, null, null, null).getStatusCode() == 201 @@ -1140,7 +1124,7 @@ class ContainerAPITest extends APISpec { bu4.uploadWithResponse(defaultInputStream.get(), defaultDataSize, null, null, null, null, null, null).getStatusCode() == 201 when: - Iterator blobs = cc.listBlobsFlat().iterator() + def blobs = cc.listBlobsFlat().iterator() then: blobs.next().getName() == name @@ -1165,7 +1149,7 @@ class ContainerAPITest extends APISpec { cc.create() } - AppendBlobClient bu = cc.getAppendBlobClient("rootblob") + def bu = cc.getBlobClient("rootblob").asAppendBlobClient() expect: bu.createWithResponse(null, null, null, null, null).getStatusCode() == 201 @@ -1179,12 +1163,11 @@ class ContainerAPITest extends APISpec { cc.create() } - AppendBlobClient bu = cc.getAppendBlobClient("rootblob") + def bu = cc.getBlobClient("rootblob").asAppendBlobClient() when: - Response createResponse = bu.createWithResponse(null, null, null, null, null) - - Response propsResponse = bu.getPropertiesWithResponse(null, null, null) + def createResponse = bu.createWithResponse(null, null, null, null, null) + def propsResponse = bu.getPropertiesWithResponse(null, null, null) then: createResponse.getStatusCode() == 201 @@ -1260,7 +1243,7 @@ class ContainerAPITest extends APISpec { def "Get account info error"() { when: - BlobServiceClient serviceURL = getServiceClient(primaryBlobServiceClient.getAccountUrl().toString()) + def serviceURL = getServiceClient(primaryBlobServiceClient.getAccountUrl().toString()) serviceURL.getContainerClient(generateContainerName()).getAccountInfo() diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ProgressReporterTest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ProgressReporterTest.groovy index 3363d431ca82..39da1d348935 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ProgressReporterTest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ProgressReporterTest.groovy @@ -3,7 +3,7 @@ package com.azure.storage.blob - +import com.azure.storage.blob.specialized.BlockBlobAsyncClient import reactor.core.publisher.Flux import spock.lang.Requires @@ -35,7 +35,7 @@ class ProgressReporterTest extends APISpec { 0 * mockReceiver.reportProgress({ it > 30 }) } - @Requires({ APISpec.liveMode() }) + @Requires({ liveMode() }) def "Report progress sequential network test"() { setup: IProgressReceiver mockReceiver = Mock(IProgressReceiver) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/RequestRetryTestFactory.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/RequestRetryTestFactory.java index de5faefc8982..88495a5ac477 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/RequestRetryTestFactory.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/RequestRetryTestFactory.java @@ -55,7 +55,7 @@ class RequestRetryTestFactory { static final String RETRY_TEST_PRIMARY_HOST = "PrimaryDC"; static final String RETRY_TEST_SECONDARY_HOST = "SecondaryDC"; - static final ByteBuffer RETRY_TEST_DEFAULT_DATA = ByteBuffer.wrap("Default data".getBytes()); + private static final ByteBuffer RETRY_TEST_DEFAULT_DATA = ByteBuffer.wrap("Default data".getBytes()); private static final String RETRY_TEST_HEADER = "TestHeader"; private static final String RETRY_TEST_QUERY_PARAM = "TestQueryParam"; private static final Mono RETRY_TEST_OK_RESPONSE = Mono.just(new RetryTestResponse(200)); diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SASTest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SASTest.groovy index cad711a45f78..e8018e3cca4f 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SASTest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SASTest.groovy @@ -8,6 +8,8 @@ import com.azure.storage.blob.models.BlobRange import com.azure.storage.blob.models.SignedIdentifier import com.azure.storage.blob.models.StorageException import com.azure.storage.blob.models.UserDelegationKey +import com.azure.storage.blob.specialized.BlobServiceSASSignatureValues +import com.azure.storage.blob.specialized.SpecializedBlobClientBuilder import com.azure.storage.common.AccountSASPermission import com.azure.storage.common.AccountSASResourceType import com.azure.storage.common.AccountSASService @@ -62,12 +64,12 @@ class SASTest extends APISpec { setup: def data = "test".getBytes() def blobName = generateBlobName() - def bu = cc.getBlockBlobClient(blobName) + def bu = cc.getBlobClient(blobName).asBlockBlobClient() bu.upload(new ByteArrayInputStream(data), data.length) def snapshotId = bu.createSnapshot().getSnapshotId() when: - def snapshotBlob = cc.getBlockBlobClient(blobName, snapshotId) + def snapshotBlob = cc.getBlobClient(blobName, snapshotId).asBlockBlobClient() then: snapshotBlob.getSnapshotId() == snapshotId @@ -78,12 +80,12 @@ class SASTest extends APISpec { setup: def data = "test".getBytes() def blobName = generateBlobName() - def bu = cc.getBlockBlobClient(blobName) + def bu = cc.getBlobClient(blobName).asBlockBlobClient() bu.upload(new ByteArrayInputStream(data), data.length) def snapshotId = bu.createSnapshot().getSnapshotId() when: - def snapshotBlob = cc.getBlockBlobClient(blobName, snapshotId) + def snapshotBlob = cc.getBlobClient(blobName, snapshotId).asBlockBlobClient() then: snapshotBlob.isSnapshot() @@ -102,7 +104,7 @@ class SASTest extends APISpec { .setReadPermission(true) .setWritePermission(true) .setCreatePermission(true) - .getDeletePermission(true) + .setDeletePermission(true) .setAddPermission(true) def startTime = getUTCNow().minusDays(1) def expiryTime = getUTCNow().plusDays(1) @@ -141,15 +143,15 @@ class SASTest extends APISpec { def blobName = generateBlobName() def bu = getBlobClient(primaryCredential, cc.getContainerUrl().toString(), blobName).asBlockBlobClient() bu.upload(new ByteArrayInputStream(data), data.length) - String snapshotId = bu.createSnapshot().getSnapshotId() + def snapshotId = bu.createSnapshot().getSnapshotId() - def snapshotBlob = cc.getBlockBlobClient(blobName, snapshotId) + def snapshotBlob = cc.getBlobClient(blobName, snapshotId).asBlockBlobClient() def permissions = new BlobSASPermission() .setReadPermission(true) .setWritePermission(true) .setCreatePermission(true) - .getDeletePermission(true) + .setDeletePermission(true) .setAddPermission(true) def startTime = getUTCNow().minusDays(1) def expiryTime = getUTCNow().plusDays(1) @@ -189,7 +191,7 @@ class SASTest extends APISpec { cc.setAccessPolicy(null, Arrays.asList(identifier)) // Check containerSASPermissions - ContainerSASPermission permissions = new ContainerSASPermission() + def permissions = new ContainerSASPermission() .setRead(true) .setWrite(true) .setList(true) @@ -198,18 +200,18 @@ class SASTest extends APISpec { .setAdd(true) .setList(true) - OffsetDateTime expiryTime = getUTCNow().plusDays(1) + def expiryTime = getUTCNow().plusDays(1) when: - String sasWithId = cc.generateSAS(identifier.getId()) + def sasWithId = cc.generateSAS(identifier.getId()) - ContainerClient client1 = getContainerClient(SASTokenCredential.fromSASTokenString(sasWithId), cc.getContainerUrl().toString()) + def client1 = getContainerClient(SASTokenCredential.fromSASTokenString(sasWithId), cc.getContainerUrl().toString()) client1.listBlobsFlat().iterator().hasNext() - String sasWithPermissions = cc.generateSAS(permissions, expiryTime) + def sasWithPermissions = cc.generateSAS(permissions, expiryTime) - ContainerClient client2 = getContainerClient(SASTokenCredential.fromSASTokenString(sasWithPermissions), cc.getContainerUrl().toString()) + def client2 = getContainerClient(SASTokenCredential.fromSASTokenString(sasWithPermissions), cc.getContainerUrl().toString()) client2.listBlobsFlat().iterator().hasNext() @@ -221,46 +223,46 @@ class SASTest extends APISpec { @Ignore def "serviceSASSignatureValues network test blob user delegation"() { setup: - byte[] data = "test".getBytes() - String blobName = generateBlobName() - BlockBlobClient bu = cc.getBlockBlobClient(blobName) + def data = "test".getBytes() + def blobName = generateBlobName() + def bu = cc.getBlobClient(blobName).asBlockBlobClient() bu.upload(new ByteArrayInputStream(data), data.length) - BlobSASPermission permissions = new BlobSASPermission() + def permissions = new BlobSASPermission() .setReadPermission(true) .setWritePermission(true) .setCreatePermission(true) - .getDeletePermission(true) + .setDeletePermission(true) .setAddPermission(true) - OffsetDateTime startTime = getUTCNow().minusDays(1) - OffsetDateTime expiryTime = getUTCNow().plusDays(1) + def startTime = getUTCNow().minusDays(1) + def expiryTime = getUTCNow().plusDays(1) - IPRange ipRange = new IPRange() + def ipRange = new IPRange() .setIpMin("0.0.0.0") .setIpMax("255.255.255.255") - SASProtocol sasProtocol = SASProtocol.HTTPS_HTTP - String cacheControl = "cache" - String contentDisposition = "disposition" - String contentEncoding = "encoding" - String contentLanguage = "language" - String contentType = "type" + def sasProtocol = SASProtocol.HTTPS_HTTP + def cacheControl = "cache" + def contentDisposition = "disposition" + def contentEncoding = "encoding" + def contentLanguage = "language" + def contentType = "type" - UserDelegationKey key = getOAuthServiceClient().getUserDelegationKey(null, expiryTime) + def key = getOAuthServiceClient().getUserDelegationKey(null, expiryTime) when: - String sas = bu.generateUserDelegationSAS(key, primaryCredential.getAccountName(), permissions, expiryTime, startTime, key.getSignedVersion(), sasProtocol, ipRange, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType) + def sas = bu.generateUserDelegationSAS(key, primaryCredential.getAccountName(), permissions, expiryTime, startTime, key.getSignedVersion(), sasProtocol, ipRange, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType) then: sas != null when: - BlockBlobClient client = getBlobClient(SASTokenCredential.fromSASTokenString(sas), cc.getContainerUrl().toString(), blobName).asBlockBlobClient() + def client = getBlobClient(SASTokenCredential.fromSASTokenString(sas), cc.getContainerUrl().toString(), blobName).asBlockBlobClient() - OutputStream os = new ByteArrayOutputStream() + def os = new ByteArrayOutputStream() client.download(os) - BlobProperties properties = client.getProperties() + def properties = client.getProperties() then: os.toString() == new String(data) @@ -273,37 +275,37 @@ class SASTest extends APISpec { def "BlobServiceSAS network test blob snapshot"() { setup: - String containerName = generateContainerName() - String blobName = generateBlobName() - ContainerClient containerClient = primaryBlobServiceClient.createContainer(containerName) - BlockBlobClient blobClient = containerClient.getBlockBlobClient(blobName) + def containerName = generateContainerName() + def blobName = generateBlobName() + def containerClient = primaryBlobServiceClient.createContainer(containerName) + def blobClient = containerClient.getBlobClient(blobName).asBlockBlobClient() blobClient.upload(defaultInputStream.get(), defaultDataSize) // need something to snapshot - BlockBlobClient snapshotBlob = blobClient.createSnapshot().asBlockBlobClient() - String snapshotId = snapshotBlob.getSnapshotId() + def snapshotBlob = new SpecializedBlobClientBuilder().blobClient(blobClient.createSnapshot()).buildBlockBlobClient() + def snapshotId = snapshotBlob.getSnapshotId() - BlobSASPermission permissions = new BlobSASPermission() + def permissions = new BlobSASPermission() .setReadPermission(true) .setWritePermission(true) .setCreatePermission(true) - .getDeletePermission(true) + .setDeletePermission(true) .setAddPermission(true) - OffsetDateTime startTime = getUTCNow().minusDays(1) - OffsetDateTime expiryTime = getUTCNow().plusDays(1) - IPRange ipRange = new IPRange() + def startTime = getUTCNow().minusDays(1) + def expiryTime = getUTCNow().plusDays(1) + def ipRange = new IPRange() .setIpMin("0.0.0.0") .setIpMax("255.255.255.255") - SASProtocol sasProtocol = SASProtocol.HTTPS_HTTP - String cacheControl = "cache" - String contentDisposition = "disposition" - String contentEncoding = "encoding" - String contentLanguage = "language" - String contentType = "type" + def sasProtocol = SASProtocol.HTTPS_HTTP + def cacheControl = "cache" + def contentDisposition = "disposition" + def contentEncoding = "encoding" + def contentLanguage = "language" + def contentType = "type" when: - String sas = snapshotBlob.generateSAS(null, permissions, expiryTime, startTime, null, sasProtocol, ipRange, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType) + def sas = snapshotBlob.generateSAS(null, permissions, expiryTime, startTime, null, sasProtocol, ipRange, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType) and: - AppendBlobClient client = getBlobClient(SASTokenCredential.fromSASTokenString(sas), containerClient.getContainerUrl().toString(), blobName).asAppendBlobClient() + def client = getBlobClient(SASTokenCredential.fromSASTokenString(sas), containerClient.getContainerUrl().toString(), blobName).asAppendBlobClient() client.download(new ByteArrayOutputStream()) @@ -311,9 +313,9 @@ class SASTest extends APISpec { thrown(StorageException) when: - AppendBlobClient snapClient = getBlobClient(SASTokenCredential.fromSASTokenString(sas), containerClient.getContainerUrl().toString(), blobName, snapshotId).asAppendBlobClient() + def snapClient = getBlobClient(SASTokenCredential.fromSASTokenString(sas), containerClient.getContainerUrl().toString(), blobName, snapshotId).asAppendBlobClient() - ByteArrayOutputStream data = new ByteArrayOutputStream() + def data = new ByteArrayOutputStream() snapClient.download(data) then: @@ -321,7 +323,7 @@ class SASTest extends APISpec { data.toByteArray() == defaultData.array() and: - BlobProperties properties = snapClient.getProperties() + def properties = snapClient.getProperties() then: properties.getCacheControl() == "cache" @@ -334,41 +336,41 @@ class SASTest extends APISpec { @Ignore def "serviceSASSignatureValues network test blob snapshot user delegation"() { setup: - byte[] data = "test".getBytes() - String blobName = generateBlobName() - BlockBlobClient bu = cc.getBlockBlobClient(blobName) + def data = "test".getBytes() + def blobName = generateBlobName() + def bu = cc.getBlobClient(blobName).asBlockBlobClient() bu.upload(new ByteArrayInputStream(data), data.length) - BlockBlobClient snapshotBlob = bu.createSnapshot().asBlockBlobClient() - String snapshotId = snapshotBlob.getSnapshotId() + def snapshotBlob = new SpecializedBlobClientBuilder().blobClient(bu.createSnapshot()).buildBlockBlobClient() + def snapshotId = snapshotBlob.getSnapshotId() - BlobSASPermission permissions = new BlobSASPermission() + def permissions = new BlobSASPermission() .setReadPermission(true) .setWritePermission(true) .setCreatePermission(true) - .getDeletePermission(true) + .setDeletePermission(true) .setAddPermission(true) - OffsetDateTime startTime = getUTCNow().minusDays(1) - OffsetDateTime expiryTime = getUTCNow().plusDays(1) + def startTime = getUTCNow().minusDays(1) + def expiryTime = getUTCNow().plusDays(1) - IPRange ipRange = new IPRange() + def ipRange = new IPRange() .setIpMin("0.0.0.0") .setIpMax("255.255.255.255") - SASProtocol sasProtocol = SASProtocol.HTTPS_HTTP - String cacheControl = "cache" - String contentDisposition = "disposition" - String contentEncoding = "encoding" - String contentLanguage = "language" - String contentType = "type" + def sasProtocol = SASProtocol.HTTPS_HTTP + def cacheControl = "cache" + def contentDisposition = "disposition" + def contentEncoding = "encoding" + def contentLanguage = "language" + def contentType = "type" - UserDelegationKey key = getOAuthServiceClient().getUserDelegationKey(startTime, expiryTime) + def key = getOAuthServiceClient().getUserDelegationKey(startTime, expiryTime) when: - String sas = snapshotBlob.generateUserDelegationSAS(key, primaryCredential.getAccountName(), permissions, expiryTime, startTime, key.getSignedVersion(), sasProtocol, ipRange, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType) + def sas = snapshotBlob.generateUserDelegationSAS(key, primaryCredential.getAccountName(), permissions, expiryTime, startTime, key.getSignedVersion(), sasProtocol, ipRange, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType) // base blob with snapshot SAS - BlockBlobClient client1 = getBlobClient(SASTokenCredential.fromSASTokenString(sas), cc.getContainerUrl().toString(), blobName).asBlockBlobClient() + def client1 = getBlobClient(SASTokenCredential.fromSASTokenString(sas), cc.getContainerUrl().toString(), blobName).asBlockBlobClient() client1.download(new ByteArrayOutputStream()) then: @@ -377,8 +379,8 @@ class SASTest extends APISpec { when: // blob snapshot with snapshot SAS - BlockBlobClient client2 = getBlobClient(SASTokenCredential.fromSASTokenString(sas), cc.getContainerUrl().toString(), blobName, snapshotId).asBlockBlobClient() - OutputStream os = new ByteArrayOutputStream() + def client2 = getBlobClient(SASTokenCredential.fromSASTokenString(sas), cc.getContainerUrl().toString(), blobName, snapshotId).asBlockBlobClient() + def os = new ByteArrayOutputStream() client2.download(os) then: @@ -398,7 +400,7 @@ class SASTest extends APISpec { @Ignore def "serviceSASSignatureValues network test container user delegation"() { setup: - ContainerSASPermission permissions = new ContainerSASPermission() + def permissions = new ContainerSASPermission() .setRead(true) .setWrite(true) .setCreate(true) @@ -406,14 +408,14 @@ class SASTest extends APISpec { .setAdd(true) .setList(true) - OffsetDateTime expiryTime = getUTCNow().plusDays(1) + def expiryTime = getUTCNow().plusDays(1) - UserDelegationKey key = getOAuthServiceClient().getUserDelegationKey(null, expiryTime) + def key = getOAuthServiceClient().getUserDelegationKey(null, expiryTime) when: - String sasWithPermissions = cc.generateUserDelegationSAS(key, primaryCredential.getAccountName(), permissions, expiryTime) + def sasWithPermissions = cc.generateUserDelegationSAS(key, primaryCredential.getAccountName(), permissions, expiryTime) - ContainerClient client = getContainerClient(SASTokenCredential.fromSASTokenString(sasWithPermissions), cc.getContainerUrl().toString()) + def client = getContainerClient(SASTokenCredential.fromSASTokenString(sasWithPermissions), cc.getContainerUrl().toString()) client.listBlobsFlat().iterator().hasNext() then: @@ -424,7 +426,7 @@ class SASTest extends APISpec { setup: def data = "test".getBytes() def blobName = generateBlobName() - def bu = cc.getBlockBlobClient(blobName) + def bu = cc.getBlobClient(blobName).asBlockBlobClient() bu.upload(new ByteArrayInputStream(data), data.length) def service = new AccountSASService() @@ -452,7 +454,7 @@ class SASTest extends APISpec { setup: def data = "test".getBytes() def blobName = generateBlobName() - def bu = cc.getBlockBlobClient(blobName) + def bu = cc.getBlobClient(blobName).asBlockBlobClient() bu.upload(new ByteArrayInputStream(data), data.length) def service = new AccountSASService() @@ -530,7 +532,7 @@ class SASTest extends APISpec { @Unroll def "serviceSasSignatures string to sign"() { when: - BlobServiceSASSignatureValues v = new BlobServiceSASSignatureValues() + def v = new BlobServiceSASSignatureValues() def p = new BlobSASPermission() p.setReadPermission(true) v.setPermissions(p.toString()) @@ -641,19 +643,6 @@ class SASTest extends APISpec { null | null | null | null | null | null | null | "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=" | null | null | null | null | null | null | null | "type" || "r\n\n" + Utility.ISO_8601_UTC_DATE_FORMATTER.format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\ncontainerName/blobName\n\n\n\n\n\n\n\n\n" + Constants.HeaderConstants.TARGET_STORAGE_VERSION + "\nbs\n\n\n\n\n\ntype" } - def "serviceSASSignatureValues canonicalizedResource"() { - setup: - def blobName = generateBlobName() - def accountName = "account" - def bu = cc.getBlockBlobClient(blobName) - - when: - def serviceSASSignatureValues = bu.blockBlobAsyncClient.configureServiceSASSignatureValues(new BlobServiceSASSignatureValues(), accountName) - - then: - serviceSASSignatureValues.getCanonicalName() == "/blob/" + accountName + cc.containerUrl.path + "/" + blobName - } - @Unroll def "serviceSasSignatureValues IA"() { setup: @@ -680,7 +669,7 @@ class SASTest extends APISpec { def perms = new BlobSASPermission() .setReadPermission(read) .setWritePermission(write) - .getDeletePermission(delete) + .setDeletePermission(delete) .setCreatePermission(create) .setAddPermission(add) @@ -833,14 +822,14 @@ class SASTest extends APISpec { @Unroll def "ServiceSASSignatureValues assertGenerateOk"() { when: - BlobServiceSASSignatureValues serviceSASSignatureValues = new BlobServiceSASSignatureValues() - serviceSASSignatureValues.setVersion(version) - serviceSASSignatureValues.setCanonicalName(canonicalName) - serviceSASSignatureValues.setExpiryTime(expiryTime) - serviceSASSignatureValues.setPermissions(permissions) - serviceSASSignatureValues.setIdentifier(identifier) - serviceSASSignatureValues.setResource(resource) - serviceSASSignatureValues.setSnapshotId(snapshotId) + def serviceSASSignatureValues = new BlobServiceSASSignatureValues() + .setVersion(version) + .setCanonicalName(canonicalName) + .setExpiryTime(expiryTime) + .setPermissions(permissions) + .setIdentifier(identifier) + .setResource(resource) + .setSnapshotId(snapshotId) if (usingUserDelegation) { serviceSASSignatureValues.generateSASQueryParameters(new UserDelegationKey()) @@ -1067,7 +1056,7 @@ class SASTest extends APISpec { def "URLParser"() { when: - def parts = URLParser.parse(new URL("http://host/container/blob?snapshot=snapshot&sv=" + Constants.HeaderConstants.TARGET_STORAGE_VERSION + "&sr=c&sp=r&sig=Ee%2BSodSXamKSzivSdRTqYGh7AeMVEk3wEoRZ1yzkpSc%3D")) + def parts = BlobURLParts.parse(new URL("http://host/container/blob?snapshot=snapshot&sv=" + Constants.HeaderConstants.TARGET_STORAGE_VERSION + "&sr=c&sp=r&sig=Ee%2BSodSXamKSzivSdRTqYGh7AeMVEk3wEoRZ1yzkpSc%3D")) then: parts.getScheme() == "http" diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/Sample.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/Sample.java index 07f653a09522..b7b149f29f67 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/Sample.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/Sample.java @@ -6,6 +6,8 @@ import com.azure.core.http.HttpClient; import com.azure.storage.blob.models.BlobItem; import com.azure.storage.blob.models.ContainerItem; +import com.azure.storage.blob.specialized.BlockBlobAsyncClient; +import com.azure.storage.blob.specialized.BlockBlobClient; import com.azure.storage.common.credentials.SharedKeyCredential; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -52,7 +54,7 @@ public void sample() throws IOException { // in the last container, create 5 blobs for (int i = 0; i < 5; i++) { - BlockBlobClient blobClient = containerClient.getBlockBlobClient("testblob-" + i); + BlockBlobClient blobClient = containerClient.getBlobClient("testblob-" + i).asBlockBlobClient(); ByteArrayInputStream testdata = new ByteArrayInputStream(("test data" + i).getBytes(StandardCharsets.UTF_8)); blobClient.upload(testdata, testdata.available()); @@ -78,7 +80,7 @@ public void sample() throws IOException { } //@Test - public void asyncSample() throws IOException { + public void asyncSample() { // get service client BlobServiceAsyncClient serviceClient = new BlobServiceClientBuilder().endpoint(ACCOUNT_ENDPOINT) .credential(new SharedKeyCredential(ACCOUNT_NAME, ACCOUNT_KEY)) @@ -113,7 +115,7 @@ public void asyncSample() throws IOException { .then(Mono.defer(() -> { Mono finished = Mono.empty(); for (int i = 0; i < 5; i++) { - BlockBlobAsyncClient blobClient = finalContainerClient.getBlockBlobAsyncClient("testblob-" + i); + BlockBlobAsyncClient blobClient = finalContainerClient.getBlobAsyncClient("testblob-" + i).asBlockBlobAsyncClient(); byte[] message = ("test data" + i).getBytes(StandardCharsets.UTF_8); Flux testdata = Flux.just(ByteBuffer.wrap(message)); @@ -169,7 +171,7 @@ public void uploadDownloadFromFile() throws IOException { containerClient.create(); // upload data - BlockBlobClient blobClient = containerClient.getBlockBlobClient("testblob_" + UUID.randomUUID()); + BlockBlobClient blobClient = containerClient.getBlobClient("testblob_" + UUID.randomUUID()).asBlockBlobClient(); blobClient.uploadFromFile(startFile.getAbsolutePath()); // download data @@ -200,7 +202,7 @@ public void uploadDownloadFromFileAsync() throws IOException { // upload data .then(Mono.defer(() -> { - BlockBlobAsyncClient blobClient = containerClient.getBlockBlobAsyncClient("testblob_" + UUID.randomUUID()); + BlockBlobAsyncClient blobClient = containerClient.getBlobAsyncClient("testblob_" + UUID.randomUUID()).asBlockBlobAsyncClient(); return blobClient.uploadFromFile(startFile.getAbsolutePath()) .then(Mono.just(blobClient)); })) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/AppendBlobAPITest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/AppendBlobAPITest.groovy similarity index 90% rename from sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/AppendBlobAPITest.groovy rename to sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/AppendBlobAPITest.groovy index b2180f89d302..cd7b3db5ede8 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/AppendBlobAPITest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/AppendBlobAPITest.groovy @@ -1,13 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob +package com.azure.storage.blob.specialized import com.azure.core.exception.UnexpectedLengthException -import com.azure.core.http.rest.Response import com.azure.core.util.Context +import com.azure.storage.blob.APISpec import com.azure.storage.blob.models.AppendBlobAccessConditions -import com.azure.storage.blob.models.AppendBlobItem import com.azure.storage.blob.models.AppendPositionAccessConditions import com.azure.storage.blob.models.BlobAccessConditions import com.azure.storage.blob.models.BlobHTTPHeaders @@ -28,13 +27,13 @@ class AppendBlobAPITest extends APISpec { def setup() { blobName = generateBlobName() - bc = cc.getAppendBlobClient(blobName) + bc = cc.getBlobClient(blobName).asAppendBlobClient() bc.create() } def "Create defaults"() { when: - Response createResponse = bc.createWithResponse(null, null, null, null, null) + def createResponse = bc.createWithResponse(null, null, null, null, null) then: createResponse.getStatusCode() == 201 @@ -60,7 +59,7 @@ class AppendBlobAPITest extends APISpec { @Unroll def "Create headers"() { setup: - BlobHTTPHeaders headers = new BlobHTTPHeaders().setBlobCacheControl(cacheControl) + def headers = new BlobHTTPHeaders().setBlobCacheControl(cacheControl) .setBlobContentDisposition(contentDisposition) .setBlobContentEncoding(contentEncoding) .setBlobContentLanguage(contentLanguage) @@ -69,7 +68,7 @@ class AppendBlobAPITest extends APISpec { when: bc.createWithResponse(headers, null, null, null, null) - Response response = bc.getPropertiesWithResponse(null, null, null) + def response = bc.getPropertiesWithResponse(null, null, null) // If the value isn't set the service will automatically set it contentType = (contentType == null) ? "application/octet-stream" : contentType @@ -112,7 +111,7 @@ class AppendBlobAPITest extends APISpec { setup: match = setupBlobMatchCondition(bc, match) leaseID = setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions().setIfModifiedSince(modified) .setIfUnmodifiedSince(unmodified) @@ -138,7 +137,7 @@ class AppendBlobAPITest extends APISpec { setup: noneMatch = setupBlobMatchCondition(bc, noneMatch) setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions().setIfModifiedSince(modified) .setIfUnmodifiedSince(unmodified) @@ -162,10 +161,10 @@ class AppendBlobAPITest extends APISpec { def "Append block defaults"() { setup: - Response appendResponse = bc.appendBlockWithResponse(defaultInputStream.get(), defaultDataSize, null, null, null) + def appendResponse = bc.appendBlockWithResponse(defaultInputStream.get(), defaultDataSize, null, null, null) when: - ByteArrayOutputStream downloadStream = new ByteArrayOutputStream() + def downloadStream = new ByteArrayOutputStream() bc.download(downloadStream) then: @@ -219,7 +218,7 @@ class AppendBlobAPITest extends APISpec { setup: match = setupBlobMatchCondition(bc, match) leaseID = setupBlobLeaseCondition(bc, leaseID) - AppendBlobAccessConditions bac = new AppendBlobAccessConditions() + def bac = new AppendBlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setAppendPositionAccessConditions(new AppendPositionAccessConditions() .setAppendPosition(appendPosE) @@ -252,7 +251,7 @@ class AppendBlobAPITest extends APISpec { noneMatch = setupBlobMatchCondition(bc, noneMatch) setupBlobLeaseCondition(bc, leaseID) - AppendBlobAccessConditions bac = new AppendBlobAccessConditions() + def bac = new AppendBlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setAppendPositionAccessConditions(new AppendPositionAccessConditions() .setAppendPosition(appendPosE) @@ -286,7 +285,7 @@ class AppendBlobAPITest extends APISpec { def "Append block error"() { setup: - bc = cc.getAppendBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asAppendBlobClient() when: bc.appendBlock(defaultInputStream.get(), defaultDataSize) @@ -298,16 +297,16 @@ class AppendBlobAPITest extends APISpec { def "Append block from URL min"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - byte[] data = getRandomByteArray(1024) + def data = getRandomByteArray(1024) bc.appendBlock(new ByteArrayInputStream(data), data.length) - AppendBlobClient destURL = cc.getAppendBlobClient(generateBlobName()) + def destURL = cc.getBlobClient(generateBlobName()).asAppendBlobClient() destURL.create() - BlobRange blobRange = new BlobRange(0, (long) PageBlobClient.PAGE_BYTES) + def blobRange = new BlobRange(0, (long) PageBlobClient.PAGE_BYTES) when: - Response response = destURL.appendBlockFromUrlWithResponse(bc.getBlobUrl(), blobRange, null, null, null, null, null) + def response = destURL.appendBlockFromUrlWithResponse(bc.getBlobUrl(), blobRange, null, null, null, null, null) then: response.getStatusCode() == 201 @@ -317,17 +316,17 @@ class AppendBlobAPITest extends APISpec { def "Append block from URL range"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - byte[] data = getRandomByteArray(4 * 1024) + def data = getRandomByteArray(4 * 1024) bc.appendBlock(new ByteArrayInputStream(data), data.length) - AppendBlobClient destURL = cc.getAppendBlobClient(generateBlobName()) + def destURL = cc.getBlobClient(generateBlobName()).asAppendBlobClient() destURL.create() when: destURL.appendBlockFromUrl(bc.getBlobUrl(), new BlobRange(2 * 1024, 1024)) then: - ByteArrayOutputStream downloadStream = new ByteArrayOutputStream(1024) + def downloadStream = new ByteArrayOutputStream(1024) destURL.download(downloadStream) downloadStream.toByteArray() == Arrays.copyOfRange(data, 2 * 1024, 3 * 1024) } @@ -335,10 +334,10 @@ class AppendBlobAPITest extends APISpec { def "Append block from URL MD5"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - byte[] data = getRandomByteArray(1024) + def data = getRandomByteArray(1024) bc.appendBlock(new ByteArrayInputStream(data), data.length) - AppendBlobClient destURL = cc.getAppendBlobClient(generateBlobName()) + def destURL = cc.getBlobClient(generateBlobName()).asAppendBlobClient() destURL.create() when: @@ -352,10 +351,10 @@ class AppendBlobAPITest extends APISpec { def "Append block from URL MD5 fail"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - byte[] data = getRandomByteArray(1024) + def data = getRandomByteArray(1024) bc.appendBlock(new ByteArrayInputStream(data), data.length) - def destURL = cc.getAppendBlobClient(generateBlobName()) + def destURL = cc.getBlobClient(generateBlobName()).asAppendBlobClient() destURL.create() when: @@ -383,7 +382,7 @@ class AppendBlobAPITest extends APISpec { .setIfMatch(match) .setIfNoneMatch(noneMatch)) - def sourceURL = cc.getAppendBlobClient(generateBlobName()) + def sourceURL = cc.getBlobClient(generateBlobName()).asAppendBlobClient() sourceURL.create() sourceURL.appendBlockWithResponse(defaultInputStream.get(), defaultDataSize, null, null, null).getStatusCode() @@ -420,7 +419,7 @@ class AppendBlobAPITest extends APISpec { .setIfMatch(match) .setIfNoneMatch(noneMatch)) - def sourceURL = cc.getAppendBlobClient(generateBlobName()) + def sourceURL = cc.getBlobClient(generateBlobName()).asAppendBlobClient() sourceURL.create() sourceURL.appendBlockWithResponse(defaultInputStream.get(), defaultDataSize, null, null, null).getStatusCode() @@ -446,7 +445,7 @@ class AppendBlobAPITest extends APISpec { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - def sourceURL = cc.getAppendBlobClient(generateBlobName()) + def sourceURL = cc.getBlobClient(generateBlobName()).asAppendBlobClient() sourceURL.create() sourceURL.appendBlockWithResponse(defaultInputStream.get(), defaultDataSize, null, null, null).getStatusCode() @@ -473,7 +472,7 @@ class AppendBlobAPITest extends APISpec { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - def sourceURL = cc.getAppendBlobClient(generateBlobName()) + def sourceURL = cc.getBlobClient(generateBlobName()).asAppendBlobClient() sourceURL.create() sourceURL.appendBlockWithResponse(defaultInputStream.get(), defaultDataSize, null, null, null).getStatusCode() diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlockBlobAPITest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/BlockBlobAPITest.groovy similarity index 90% rename from sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlockBlobAPITest.groovy rename to sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/BlockBlobAPITest.groovy index 5fea49611a33..a819ee5084d5 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlockBlobAPITest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/BlockBlobAPITest.groovy @@ -1,18 +1,18 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob +package com.azure.storage.blob.specialized import com.azure.core.exception.UnexpectedLengthException -import com.azure.core.http.HttpHeaders import com.azure.core.http.HttpMethod import com.azure.core.http.HttpPipelineCallContext import com.azure.core.http.HttpPipelineNextPolicy import com.azure.core.http.HttpRequest import com.azure.core.http.policy.HttpLogDetailLevel import com.azure.core.http.policy.HttpPipelinePolicy -import com.azure.core.http.rest.Response import com.azure.core.util.Context +import com.azure.storage.blob.APISpec +import com.azure.storage.blob.BlobServiceClientBuilder import com.azure.storage.blob.models.AccessTier import com.azure.storage.blob.models.BlobAccessConditions import com.azure.storage.blob.models.BlobHTTPHeaders @@ -44,16 +44,16 @@ class BlockBlobAPITest extends APISpec { def setup() { blobName = generateBlobName() - bc = cc.getBlockBlobClient(blobName) + bc = cc.getBlobClient(blobName).asBlockBlobClient() bc.upload(defaultInputStream.get(), defaultDataSize) - bac = ccAsync.getBlockBlobAsyncClient(generateBlobName()) + bac = ccAsync.getBlobAsyncClient(generateBlobName()).asBlockBlobAsyncClient() bac.upload(defaultFlux, defaultDataSize) } def "Stage block"() { setup: def response = bc.stageBlockWithResponse(getBlockID(), defaultInputStream.get(), defaultDataSize, null, null, null) - HttpHeaders headers = response.getHeaders() + def headers = response.getHeaders() expect: response.getStatusCode() == 201 @@ -75,18 +75,18 @@ class BlockBlobAPITest extends APISpec { @Unroll def "Stage block illegal arguments"() { when: - String blockID = (getBlockId) ? getBlockID() : null + def blockID = (getBlockId) ? getBlockID() : null bc.stageBlock(blockID, data == null ? null : data.get(), dataSize) then: thrown(exceptionType) where: - getBlockId | data | dataSize | exceptionType - false | defaultInputStream | defaultDataSize | StorageException - true | null | defaultDataSize | NullPointerException - true | defaultInputStream | defaultDataSize + 1 | UnexpectedLengthException - true | defaultInputStream | defaultDataSize - 1 | UnexpectedLengthException + getBlockId | data | dataSize | exceptionType + false | defaultInputStream | defaultDataSize | StorageException + true | null | defaultDataSize | NullPointerException + true | defaultInputStream | defaultDataSize + 1 | UnexpectedLengthException + true | defaultInputStream | defaultDataSize - 1 | UnexpectedLengthException } def "Stage block empty body"() { @@ -107,7 +107,7 @@ class BlockBlobAPITest extends APISpec { def "Stage block lease"() { setup: - String leaseID = setupBlobLeaseCondition(bc, receivedLeaseID) + def leaseID = setupBlobLeaseCondition(bc, receivedLeaseID) expect: bc.stageBlockWithResponse(getBlockID(), defaultInputStream.get(), defaultDataSize, new LeaseAccessConditions().setLeaseId(leaseID), @@ -129,7 +129,7 @@ class BlockBlobAPITest extends APISpec { def "Stage block error"() { setup: - bc = cc.getBlockBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: bc.stageBlock("id", defaultInputStream.get(), defaultDataSize) @@ -141,7 +141,7 @@ class BlockBlobAPITest extends APISpec { def "Stage block from url"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - def bu2 = cc.getBlockBlobClient(generateBlobName()) + def bu2 = cc.getBlobClient(generateBlobName()).asBlockBlobClient() def blockID = getBlockID() when: @@ -170,7 +170,7 @@ class BlockBlobAPITest extends APISpec { def "Stage block from url min"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - def bu2 = cc.getBlockBlobClient(generateBlobName()) + def bu2 = cc.getBlobClient(generateBlobName()).asBlockBlobClient() def blockID = getBlockID() expect: @@ -180,7 +180,7 @@ class BlockBlobAPITest extends APISpec { @Unroll def "Stage block from URL IA"() { when: - String blockID = (getBlockId) ? getBlockID() : null + def blockID = (getBlockId) ? getBlockID() : null bc.stageBlockFromURL(blockID, sourceURL, null) then: @@ -195,7 +195,7 @@ class BlockBlobAPITest extends APISpec { def "Stage block from URL range"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - def destURL = cc.getBlockBlobClient(generateBlobName()) + def destURL = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: destURL.stageBlockFromURL(getBlockID(), bc.getBlobUrl(), new BlobRange(2, 3)) @@ -210,7 +210,7 @@ class BlockBlobAPITest extends APISpec { def "Stage block from URL MD5"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - def destURL = cc.getBlockBlobClient(generateBlobName()) + def destURL = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: destURL.stageBlockFromURLWithResponse(getBlockID(), bc.getBlobUrl(), null, @@ -223,7 +223,7 @@ class BlockBlobAPITest extends APISpec { def "Stage block from URL MD5 fail"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - def destURL = cc.getBlockBlobClient(generateBlobName()) + def destURL = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: destURL.stageBlockFromURLWithResponse(getBlockID(), bc.getBlobUrl(), null, "garbage".getBytes(), @@ -259,7 +259,9 @@ class BlockBlobAPITest extends APISpec { def "Stage block from URL error"() { setup: - bc = primaryBlobServiceClient.getContainerClient(generateContainerName()).getBlockBlobClient(generateBlobName()) + bc = primaryBlobServiceClient.getContainerClient(generateContainerName()) + .getBlobClient(generateBlobName()) + .asBlockBlobClient() when: bc.stageBlockFromURL(getBlockID(), bc.getBlobUrl(), null) @@ -274,7 +276,7 @@ class BlockBlobAPITest extends APISpec { cc.setAccessPolicy(PublicAccessType.CONTAINER, null) def blockID = getBlockID() - def sourceURL = cc.getBlockBlobClient(generateBlobName()) + def sourceURL = cc.getBlobClient(generateBlobName()).asBlockBlobClient() sourceURL.upload(defaultInputStream.get(), defaultDataSize) sourceIfMatch = setupBlobMatchCondition(sourceURL, sourceIfMatch) @@ -302,7 +304,7 @@ class BlockBlobAPITest extends APISpec { cc.setAccessPolicy(PublicAccessType.CONTAINER, null) def blockID = getBlockID() - def sourceURL = cc.getBlockBlobClient(generateBlobName()) + def sourceURL = cc.getBlobClient(generateBlobName()).asBlockBlobClient() sourceURL.upload(defaultInputStream.get(), defaultDataSize) def smac = new SourceModifiedAccessConditions() @@ -327,10 +329,9 @@ class BlockBlobAPITest extends APISpec { def "Commit block list"() { setup: - String blockID = getBlockID() + def blockID = getBlockID() bc.stageBlock(blockID, defaultInputStream.get(), defaultDataSize) - ArrayList ids = new ArrayList<>() - ids.add(blockID) + def ids = [ blockID ] as List when: def response = bc.commitBlockListWithResponse(ids, null, null, null, null, null, null) @@ -345,10 +346,9 @@ class BlockBlobAPITest extends APISpec { def "Commit block list min"() { setup: - String blockID = getBlockID() + def blockID = getBlockID() bc.stageBlock(blockID, defaultInputStream.get(), defaultDataSize) - ArrayList ids = new ArrayList<>() - ids.add(blockID) + def ids = [ blockID ] as List expect: bc.commitBlockList(ids) != null @@ -362,11 +362,10 @@ class BlockBlobAPITest extends APISpec { @Unroll def "Commit block list headers"() { setup: - String blockID = getBlockID() + def blockID = getBlockID() bc.stageBlock(blockID, defaultInputStream.get(), defaultDataSize) - ArrayList ids = new ArrayList<>() - ids.add(blockID) - BlobHTTPHeaders headers = new BlobHTTPHeaders().setBlobCacheControl(cacheControl) + def ids = [ blockID ] as List + def headers = new BlobHTTPHeaders().setBlobCacheControl(cacheControl) .setBlobContentDisposition(contentDisposition) .setBlobContentEncoding(contentEncoding) .setBlobContentLanguage(contentLanguage) @@ -392,7 +391,7 @@ class BlockBlobAPITest extends APISpec { @Unroll def "Commit block list metadata"() { setup: - Metadata metadata = new Metadata() + def metadata = new Metadata() if (key1 != null) { metadata.put(key1, value1) } @@ -419,7 +418,7 @@ class BlockBlobAPITest extends APISpec { setup: match = setupBlobMatchCondition(bc, match) leaseID = setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -446,7 +445,7 @@ class BlockBlobAPITest extends APISpec { setup: noneMatch = setupBlobMatchCondition(bc, noneMatch) setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -472,7 +471,7 @@ class BlockBlobAPITest extends APISpec { def "Commit block list error"() { setup: - bc = cc.getBlockBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: bc.commitBlockListWithResponse(new ArrayList(), null, null, null, @@ -545,7 +544,7 @@ class BlockBlobAPITest extends APISpec { def "Get block list lease"() { setup: - String leaseID = setupBlobLeaseCondition(bc, receivedLeaseID) + def leaseID = setupBlobLeaseCondition(bc, receivedLeaseID) when: bc.listBlocksWithResponse(BlockListType.ALL, new LeaseAccessConditions().setLeaseId(leaseID), null, Context.NONE) @@ -568,7 +567,7 @@ class BlockBlobAPITest extends APISpec { def "Get block list error"() { setup: - bc = cc.getBlockBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: bc.listBlocks(BlockListType.ALL).iterator().hasNext() @@ -594,38 +593,34 @@ class BlockBlobAPITest extends APISpec { /* Upload From File Tests: Need to run on liveMode only since blockBlob wil generate a `UUID.randomUUID()` for getBlockID that will change every time test is run */ - @Requires({ APISpec.liveMode() }) + @Requires({ liveMode() }) def "Upload from file"() { given: - URL resource = this.getClass().getResource( '/testfiles/uploadFromFileTestData.txt') - String file = resource.path - String content = resource.text + def file = new File(this.getClass().getResource("/testfiles/uploadFromFileTestData.txt").getPath()) def outStream = new ByteArrayOutputStream() when: - bc.uploadFromFile(file) + bc.uploadFromFile(file.getAbsolutePath()) then: bc.download(outStream) - outStream.toByteArray() == content.getBytes(StandardCharsets.UTF_8) + outStream.toByteArray() == new Scanner(file).useDelimiter("\\z").next().getBytes(StandardCharsets.UTF_8) } - @Requires({ APISpec.liveMode() }) + @Requires({ liveMode() }) def "Upload from file with metadata"() { given: - Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); - URL resource = this.getClass().getResource( '/testfiles/uploadFromFileTestData.txt') - String file = resource.path - String content = resource.text + Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")) + def file = new File(this.getClass().getResource("/testfiles/uploadFromFileTestData.txt").getPath()) def outStream = new ByteArrayOutputStream() when: - bc.uploadFromFile(file, null, metadata, null, null, null); + bc.uploadFromFile(file.getAbsolutePath(), null, null, metadata, null, null, null) then: - BlobProperties properties = bc.getProperties() - Metadata returnedMetadata = properties.metadata; - metadata.equals(returnedMetadata); + metadata == bc.getProperties().getMetadata() + bc.download(outStream) + outStream.toByteArray() == new Scanner(file).useDelimiter("\\z").next().getBytes(StandardCharsets.UTF_8) } def "Upload min"() { @@ -669,7 +664,7 @@ class BlockBlobAPITest extends APISpec { @Unroll def "Upload headers"() { setup: - BlobHTTPHeaders headers = new BlobHTTPHeaders().setBlobCacheControl(cacheControl) + def headers = new BlobHTTPHeaders().setBlobCacheControl(cacheControl) .setBlobContentDisposition(contentDisposition) .setBlobContentEncoding(contentEncoding) .setBlobContentLanguage(contentLanguage) @@ -696,7 +691,7 @@ class BlockBlobAPITest extends APISpec { @Unroll def "Upload metadata"() { setup: - Metadata metadata = new Metadata() + def metadata = new Metadata() if (key1 != null) { metadata.put(key1, value1) } @@ -723,7 +718,7 @@ class BlockBlobAPITest extends APISpec { setup: match = setupBlobMatchCondition(bc, match) leaseID = setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -750,7 +745,7 @@ class BlockBlobAPITest extends APISpec { setup: noneMatch = setupBlobMatchCondition(bc, noneMatch) setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -777,7 +772,7 @@ class BlockBlobAPITest extends APISpec { def "Upload error"() { setup: - bc = cc.getBlockBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: bc.uploadWithResponse(defaultInputStream.get(), defaultDataSize, null, null, null, @@ -790,7 +785,7 @@ class BlockBlobAPITest extends APISpec { def "Upload with tier"() { setup: - def bc = cc.getBlockBlobClient(generateBlobName()) + def bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: bc.uploadWithResponse(defaultInputStream.get(), defaultDataSize, null, null, AccessTier.COOL, null, null, null) @@ -801,7 +796,7 @@ class BlockBlobAPITest extends APISpec { // Only run these tests in live mode as they use variables that can't be captured. @Unroll - @Requires({ APISpec.liveMode() }) + @Requires({ liveMode() }) def "Async buffered upload"() { when: def data = getRandomData(dataSize) @@ -842,14 +837,14 @@ class BlockBlobAPITest extends APISpec { // Only run these tests in live mode as they use variables that can't be captured. @Unroll - @Requires({ APISpec.liveMode() }) + @Requires({ liveMode() }) def "Buffered upload chunked source"() { /* This test should validate that the upload should work regardless of what format the passed data is in because it will be chunked appropriately. */ setup: - List dataList = new ArrayList<>() + def dataList = [] as List dataSizeList.each { size -> dataList.add(getRandomData(size)) } bac.upload(Flux.fromIterable(dataList), bufferSize, numBuffers).block() @@ -891,7 +886,7 @@ class BlockBlobAPITest extends APISpec { // Only run these tests in live mode as they use variables that can't be captured. @Unroll - @Requires({ APISpec.liveMode() }) + @Requires({ liveMode() }) def "Buffered upload headers"() { when: bac.uploadWithResponse(defaultFlux, 10, 2, new BlobHTTPHeaders().setBlobCacheControl(cacheControl) @@ -916,10 +911,10 @@ class BlockBlobAPITest extends APISpec { // Only run these tests in live mode as they use variables that can't be captured. @Unroll - @Requires({ APISpec.liveMode() }) + @Requires({ liveMode() }) def "Buffered upload metadata"() { setup: - Metadata metadata = new Metadata() + def metadata = new Metadata() if (key1 != null) { metadata.put(key1, value1) } @@ -929,7 +924,7 @@ class BlockBlobAPITest extends APISpec { when: bac.uploadWithResponse(Flux.just(getRandomData(10)), 10, 10, null, metadata, null, null).block() - Response response = bac.getPropertiesWithResponse(null).block() + def response = bac.getPropertiesWithResponse(null).block() then: response.getStatusCode() == 200 @@ -943,7 +938,7 @@ class BlockBlobAPITest extends APISpec { // Only run these tests in live mode as they use variables that can't be captured. @Unroll - @Requires({ APISpec.liveMode() }) + @Requires({ liveMode() }) def "Buffered upload AC"() { setup: bac.upload(defaultFlux, defaultDataSize).block() @@ -960,8 +955,8 @@ class BlockBlobAPITest extends APISpec { where: modified | unmodified | match | noneMatch | leaseID null | null | null | null | null - oldDate | null | null | null | null null | newDate | null | null | null + oldDate | null | null | null | null null | null | receivedEtag | null | null null | null | null | garbageEtag | null null | null | null | null | receivedLeaseID @@ -969,13 +964,13 @@ class BlockBlobAPITest extends APISpec { // Only run these tests in live mode as they use variables that can't be captured. @Unroll - @Requires({ APISpec.liveMode() }) + @Requires({ liveMode() }) def "Buffered upload AC fail"() { setup: bac.upload(defaultFlux, defaultDataSize).block() noneMatch = setupBlobMatchCondition(bac, noneMatch) leaseID = setupBlobLeaseCondition(bac, leaseID) - BlobAccessConditions accessConditions = new BlobAccessConditions().setModifiedAccessConditions( + def accessConditions = new BlobAccessConditions().setModifiedAccessConditions( new ModifiedAccessConditions().setIfModifiedSince(modified).setIfUnmodifiedSince(unmodified) .setIfMatch(match).setIfNoneMatch(noneMatch)) .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) @@ -1068,7 +1063,7 @@ class BlockBlobAPITest extends APISpec { .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) .retryOptions(new RequestRetryOptions(null, 3, null, 500, 1500, null)) .addPolicy(mockPolicy).buildAsyncClient() - .getContainerAsyncClient(generateContainerName()).getBlockBlobAsyncClient(generateBlobName()) + .getContainerAsyncClient(generateContainerName()).getBlobAsyncClient(generateBlobName()).asBlockBlobAsyncClient() when: // Try to upload the flowable, which will hit a retry. A normal upload would throw, but buffering prevents that. diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/DownloadResponseMockFlux.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/DownloadResponseMockFlux.java similarity index 98% rename from sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/DownloadResponseMockFlux.java rename to sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/DownloadResponseMockFlux.java index 925e8654cd96..547263cdb83d 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/DownloadResponseMockFlux.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/DownloadResponseMockFlux.java @@ -1,10 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob; +package com.azure.storage.blob.specialized; import com.azure.core.http.HttpHeaders; import com.azure.core.http.HttpResponse; +import com.azure.storage.blob.APISpec; +import com.azure.storage.blob.HTTPGetterInfo; import com.azure.storage.blob.models.BlobDownloadHeaders; import com.azure.storage.blob.models.BlobsDownloadResponse; import com.azure.storage.blob.models.StorageErrorException; diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/DownloadResponseTest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/DownloadResponseTest.groovy similarity index 90% rename from sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/DownloadResponseTest.groovy rename to sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/DownloadResponseTest.groovy index c6fd7f8e4843..b2c3929d3266 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/DownloadResponseTest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/DownloadResponseTest.groovy @@ -1,19 +1,24 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob +package com.azure.storage.blob.specialized import com.azure.core.implementation.util.FluxUtil +import com.azure.storage.blob.APISpec +import com.azure.storage.blob.HTTPGetterInfo import com.azure.storage.blob.models.ReliableDownloadOptions import com.azure.storage.blob.models.StorageErrorException +import com.azure.storage.blob.specialized.BlockBlobClient +import com.azure.storage.blob.specialized.DownloadAsyncResponse +import com.azure.storage.blob.specialized.DownloadResponseMockFlux import spock.lang.Unroll class DownloadResponseTest extends APISpec { BlockBlobClient bu def setup() { - bu = cc.getBlockBlobClient(generateBlobName()) + bu = cc.getBlobClient(generateBlobName()).asBlockBlobClient() bu.upload(defaultInputStream.get(), defaultText.length()) } @@ -98,9 +103,9 @@ class DownloadResponseTest extends APISpec { thrown(IllegalArgumentException) where: - info | _ - null | _ - new HTTPGetterInfo().setETag(null) | _ + info | _ + null | _ + new HTTPGetterInfo().setETag(null) | _ } def "Options IA"() { diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/HelperTest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/HelperTest.groovy similarity index 98% rename from sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/HelperTest.groovy rename to sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/HelperTest.groovy index 12446553ed42..c6ae13570638 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/HelperTest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/HelperTest.groovy @@ -1,8 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob +package com.azure.storage.blob.specialized +import com.azure.storage.blob.APISpec +import com.azure.storage.blob.BlobSASPermission +import com.azure.storage.blob.BlobURLParts +import com.azure.storage.blob.ContainerSASPermission import com.azure.storage.blob.models.BlobRange import com.azure.storage.blob.models.UserDelegationKey @@ -296,7 +300,7 @@ class HelperTest extends APISpec { BlobSASPermission perms = new BlobSASPermission() .setReadPermission(read) .setWritePermission(write) - .getDeletePermission(delete) + .setDeletePermission(delete) .setCreatePermission(create) .setAddPermission(add) @@ -627,7 +631,7 @@ class HelperTest extends APISpec { .setHost("host") .setContainerName("container") .setBlobName("blob") - .setSnapshot("snapshot") + .setSnapshot "snapshot" BlobServiceSASSignatureValues sasValues = new BlobServiceSASSignatureValues() .setExpiryTime(OffsetDateTime.now(ZoneOffset.UTC).plusDays(1)) @@ -651,7 +655,7 @@ class HelperTest extends APISpec { def "URLParser"() { when: - BlobURLParts parts = URLParser.parse(new URL("http://host/container/blob?snapshot=snapshot&sv=" + Constants.HeaderConstants.TARGET_STORAGE_VERSION + "&sr=c&sp=r&sig=Ee%2BSodSXamKSzivSdRTqYGh7AeMVEk3wEoRZ1yzkpSc%3D")) + BlobURLParts parts = BlobURLParts.parse(new URL("http://host/container/blob?snapshot=snapshot&sv=" + Constants.HeaderConstants.TARGET_STORAGE_VERSION + "&sr=c&sp=r&sig=Ee%2BSodSXamKSzivSdRTqYGh7AeMVEk3wEoRZ1yzkpSc%3D")) then: parts.getScheme() == "http" diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/LeaseAPITest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/LeaseAPITest.groovy similarity index 79% rename from sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/LeaseAPITest.groovy rename to sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/LeaseAPITest.groovy index 163ef5ff5f1c..757380c79201 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/LeaseAPITest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/LeaseAPITest.groovy @@ -1,17 +1,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob +package com.azure.storage.blob.specialized +import com.azure.storage.blob.APISpec import com.azure.storage.blob.models.LeaseDurationType import com.azure.storage.blob.models.LeaseStateType import com.azure.storage.blob.models.ModifiedAccessConditions import com.azure.storage.blob.models.StorageException +import com.azure.storage.blob.specialized.BlobClientBase import spock.lang.Unroll class LeaseAPITest extends APISpec { - private BlobClient createBlobClient() { - def bc = cc.getBlockBlobClient(generateBlobName()) + private BlobClientBase createBlobClient() { + def bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() bc.upload(defaultInputStream.get(), defaultDataSize) return bc @@ -88,12 +90,12 @@ class LeaseAPITest extends APISpec { .getStatusCode() == 201 where: - modified | unmodified | match | noneMatch - null | null | null | null - oldDate | null | null | null - null | newDate | null | null - null | null | receivedEtag | null - null | null | null | garbageEtag + modified | unmodified | match | noneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag } @Unroll @@ -114,16 +116,16 @@ class LeaseAPITest extends APISpec { thrown(StorageException) where: - modified | unmodified | match | noneMatch - newDate | null | null | null - null | oldDate | null | null - null | null | garbageEtag | null - null | null | null | receivedEtag + modified | unmodified | match | noneMatch + newDate | null | null | null + null | oldDate | null | null + null | null | garbageEtag | null + null | null | null | receivedEtag } def "Acquire blob lease error"() { setup: - def bc = cc.getBlockBlobClient(generateBlobName()) + def bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: createLeaseClient(bc).acquireLease(20) @@ -176,12 +178,12 @@ class LeaseAPITest extends APISpec { .getStatusCode() == 200 where: - modified | unmodified | match | noneMatch - null | null | null | null - oldDate | null | null | null - null | newDate | null | null - null | null | receivedEtag | null - null | null | null | garbageEtag + modified | unmodified | match | noneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag } @Unroll @@ -203,16 +205,16 @@ class LeaseAPITest extends APISpec { thrown(StorageException) where: - modified | unmodified | match | noneMatch - newDate | null | null | null - null | oldDate | null | null - null | null | garbageEtag | null - null | null | null | receivedEtag + modified | unmodified | match | noneMatch + newDate | null | null | null + null | oldDate | null | null + null | null | garbageEtag | null + null | null | null | receivedEtag } def "Renew blob lease error"() { setup: - def bc = cc.getBlockBlobClient(generateBlobName()) + def bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: createLeaseClient(bc, "id").renewLease() @@ -257,12 +259,12 @@ class LeaseAPITest extends APISpec { createLeaseClient(bc, leaseID).releaseLeaseWithResponse(mac, null, null).getStatusCode() == 200 where: - modified | unmodified | match | noneMatch - null | null | null | null - oldDate | null | null | null - null | newDate | null | null - null | null | receivedEtag | null - null | null | null | garbageEtag + modified | unmodified | match | noneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag } @Unroll @@ -284,16 +286,16 @@ class LeaseAPITest extends APISpec { thrown(StorageException) where: - modified | unmodified | match | noneMatch - newDate | null | null | null - null | oldDate | null | null - null | null | garbageEtag | null - null | null | null | receivedEtag + modified | unmodified | match | noneMatch + newDate | null | null | null + null | oldDate | null | null + null | null | garbageEtag | null + null | null | null | receivedEtag } def "Release blob lease error"() { setup: - def bc = cc.getBlockBlobClient(generateBlobName()) + def bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: createLeaseClient(bc, "id").releaseLease() @@ -350,12 +352,12 @@ class LeaseAPITest extends APISpec { createLeaseClient(bc).breakLeaseWithResponse(null, mac, null, null).getStatusCode() == 202 where: - modified | unmodified | match | noneMatch - null | null | null | null - oldDate | null | null | null - null | newDate | null | null - null | null | receivedEtag | null - null | null | null | garbageEtag + modified | unmodified | match | noneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag } @Unroll @@ -377,11 +379,11 @@ class LeaseAPITest extends APISpec { thrown(StorageException) where: - modified | unmodified | match | noneMatch - newDate | null | null | null - null | oldDate | null | null - null | null | garbageEtag | null - null | null | null | receivedEtag + modified | unmodified | match | noneMatch + newDate | null | null | null + null | oldDate | null | null + null | null | garbageEtag | null + null | null | null | receivedEtag } def "Break blob lease error"() { @@ -433,12 +435,12 @@ class LeaseAPITest extends APISpec { createLeaseClient(bc, leaseID).changeLeaseWithResponse(getRandomUUID(), mac, null, null).getStatusCode() == 200 where: - modified | unmodified | match | noneMatch - null | null | null | null - oldDate | null | null | null - null | newDate | null | null - null | null | receivedEtag | null - null | null | null | garbageEtag + modified | unmodified | match | noneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag } @Unroll @@ -460,16 +462,16 @@ class LeaseAPITest extends APISpec { thrown(StorageException) where: - modified | unmodified | match | noneMatch - newDate | null | null | null - null | oldDate | null | null - null | null | garbageEtag | null - null | null | null | receivedEtag + modified | unmodified | match | noneMatch + newDate | null | null | null + null | oldDate | null | null + null | null | garbageEtag | null + null | null | null | receivedEtag } def "Change blob lease error"() { setup: - def bc = cc.getBlockBlobClient(generateBlobName()) + def bc = cc.getBlobClient(generateBlobName()).asBlockBlobClient() when: createLeaseClient(bc, "id").changeLease("id") @@ -547,12 +549,12 @@ class LeaseAPITest extends APISpec { createLeaseClient(cc).acquireLeaseWithResponse( -1, mac, null, null).getStatusCode() == 201 where: - modified | unmodified | match | noneMatch - null | null | null | null - oldDate | null | null | null - null | newDate | null | null - null | null | receivedEtag | null - null | null | null | garbageEtag + modified | unmodified | match | noneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag } @Unroll @@ -567,9 +569,9 @@ class LeaseAPITest extends APISpec { thrown(StorageException) where: - modified | unmodified - newDate | null - null | oldDate + modified | unmodified + newDate | null + null | oldDate } def "Acquire container lease error"() { @@ -614,10 +616,10 @@ class LeaseAPITest extends APISpec { createLeaseClient(cc, leaseID).renewLeaseWithResponse(mac, null, null).getStatusCode() == 200 where: - modified | unmodified - null | null - oldDate | null - null | newDate + modified | unmodified + null | null + oldDate | null + null | newDate } @Unroll @@ -633,9 +635,9 @@ class LeaseAPITest extends APISpec { thrown(StorageException) where: - modified | unmodified - newDate | null - null | oldDate + modified | unmodified + newDate | null + null | oldDate } @Unroll @@ -650,9 +652,9 @@ class LeaseAPITest extends APISpec { thrown(StorageException) where: - match | noneMatch + match | noneMatch receivedEtag | null - null | garbageEtag + null | garbageEtag } def "Renew container lease error"() { @@ -695,10 +697,10 @@ class LeaseAPITest extends APISpec { createLeaseClient(cc, leaseID).releaseLeaseWithResponse(mac, null, null).getStatusCode() == 200 where: - modified | unmodified - null | null - oldDate | null - null | newDate + modified | unmodified + null | null + oldDate | null + null | newDate } @Unroll @@ -714,9 +716,9 @@ class LeaseAPITest extends APISpec { thrown(StorageException) where: - modified | unmodified - newDate | null - null | oldDate + modified | unmodified + newDate | null + null | oldDate } @Unroll @@ -731,9 +733,9 @@ class LeaseAPITest extends APISpec { thrown(StorageException) where: - match | noneMatch + match | noneMatch receivedEtag | null - null | garbageEtag + null | garbageEtag } def "Release container lease error"() { @@ -791,10 +793,10 @@ class LeaseAPITest extends APISpec { createLeaseClient(cc).breakLeaseWithResponse(null, mac, null, null).getStatusCode() == 202 where: - modified | unmodified - null | null - oldDate | null - null | newDate + modified | unmodified + null | null + oldDate | null + null | newDate } @Unroll @@ -810,9 +812,9 @@ class LeaseAPITest extends APISpec { thrown(StorageException) where: - modified | unmodified - newDate | null - null | oldDate + modified | unmodified + newDate | null + null | oldDate } @Unroll @@ -827,9 +829,9 @@ class LeaseAPITest extends APISpec { thrown(StorageException) where: - match | noneMatch + match | noneMatch receivedEtag | null - null | garbageEtag + null | garbageEtag } def "Break container lease error"() { @@ -873,10 +875,10 @@ class LeaseAPITest extends APISpec { createLeaseClient(cc, leaseID).changeLeaseWithResponse(getRandomUUID(), mac, null, null).getStatusCode() == 200 where: - modified | unmodified - null | null - oldDate | null - null | newDate + modified | unmodified + null | null + oldDate | null + null | newDate } @Unroll @@ -892,9 +894,9 @@ class LeaseAPITest extends APISpec { thrown(StorageException) where: - modified | unmodified - newDate | null - null | oldDate + modified | unmodified + newDate | null + null | oldDate } @Unroll @@ -909,9 +911,9 @@ class LeaseAPITest extends APISpec { thrown(StorageException) where: - match | noneMatch + match | noneMatch receivedEtag | null - null | garbageEtag + null | garbageEtag } def "Change container lease error"() { diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/PageBlobAPITest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/PageBlobAPITest.groovy similarity index 93% rename from sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/PageBlobAPITest.groovy rename to sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/PageBlobAPITest.groovy index 0f97a468f0e9..7f564f33efec 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/PageBlobAPITest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/PageBlobAPITest.groovy @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.storage.blob +package com.azure.storage.blob.specialized -import com.azure.core.http.rest.Response import com.azure.core.exception.UnexpectedLengthException +import com.azure.storage.blob.APISpec import com.azure.storage.blob.models.BlobAccessConditions import com.azure.storage.blob.models.BlobHTTPHeaders import com.azure.storage.blob.models.BlobRange @@ -13,7 +13,6 @@ import com.azure.storage.blob.models.LeaseAccessConditions import com.azure.storage.blob.models.Metadata import com.azure.storage.blob.models.ModifiedAccessConditions import com.azure.storage.blob.models.PageBlobAccessConditions -import com.azure.storage.blob.models.PageBlobItem import com.azure.storage.blob.models.PageRange import com.azure.storage.blob.models.PublicAccessType import com.azure.storage.blob.models.SequenceNumberAccessConditions @@ -32,14 +31,14 @@ class PageBlobAPITest extends APISpec { def setup() { blobName = generateBlobName() - bc = cc.getPageBlobClient(blobName) - bcAsync = ccAsync.getPageBlobAsyncClient(blobName) + bc = cc.getBlobClient(blobName).asPageBlobClient() + bcAsync = ccAsync.getBlobAsyncClient(blobName).asPageBlobAsyncClient() bc.create(PageBlobClient.PAGE_BYTES) } def "Create all null"() { setup: - bc = cc.getPageBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asPageBlobClient() when: def response = bc.createWithResponse(PageBlobClient.PAGE_BYTES, null, null, null, null, null, null) @@ -67,7 +66,7 @@ class PageBlobAPITest extends APISpec { @Unroll def "Create headers"() { setup: - BlobHTTPHeaders headers = new BlobHTTPHeaders().setBlobCacheControl(cacheControl) + def headers = new BlobHTTPHeaders().setBlobCacheControl(cacheControl) .setBlobContentDisposition(contentDisposition) .setBlobContentEncoding(contentEncoding) .setBlobContentLanguage(contentLanguage) @@ -94,7 +93,7 @@ class PageBlobAPITest extends APISpec { @Unroll def "Create metadata"() { setup: - Metadata metadata = new Metadata() + def metadata = new Metadata() if (key1 != null) { metadata.put(key1, value1) } @@ -120,7 +119,7 @@ class PageBlobAPITest extends APISpec { @Unroll def "Create AC"() { setup: - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(setupBlobLeaseCondition(bc, leaseID))) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -145,7 +144,7 @@ class PageBlobAPITest extends APISpec { @Unroll def "Create AC fail"() { setup: - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(setupBlobLeaseCondition(bc, leaseID))) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -215,7 +214,7 @@ class PageBlobAPITest extends APISpec { @Unroll def "Upload page AC"() { setup: - PageBlobAccessConditions pac = new PageBlobAccessConditions() + def pac = new PageBlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(setupBlobLeaseCondition(bc, leaseID))) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -249,7 +248,7 @@ class PageBlobAPITest extends APISpec { setup: noneMatch = setupBlobMatchCondition(bc, noneMatch) setupBlobLeaseCondition(bc, leaseID) - PageBlobAccessConditions pac = new PageBlobAccessConditions() + def pac = new PageBlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -282,7 +281,7 @@ class PageBlobAPITest extends APISpec { def "Upload page error"() { setup: - bc = cc.getPageBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asPageBlobClient() when: bc.uploadPagesWithResponse(new PageRange().setStart(0).setEnd(PageBlobClient.PAGE_BYTES - 1), @@ -297,14 +296,14 @@ class PageBlobAPITest extends APISpec { def "Upload page from URL min"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - def destURL = cc.getPageBlobClient(generateBlobName()) + def destURL = cc.getBlobClient(generateBlobName()).asPageBlobClient() destURL.create(PageBlobClient.PAGE_BYTES) destURL.uploadPages(new PageRange().setStart(0).setEnd(PageBlobClient.PAGE_BYTES - 1), new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) def pageRange = new PageRange().setStart(0).setEnd(PageBlobClient.PAGE_BYTES - 1) when: - Response response = bc.uploadPagesFromURLWithResponse(pageRange, destURL.getBlobUrl(), null, null, null, null, null, null) + def response = bc.uploadPagesFromURLWithResponse(pageRange, destURL.getBlobUrl(), null, null, null, null, null, null) then: response.getStatusCode() == 201 @@ -315,14 +314,14 @@ class PageBlobAPITest extends APISpec { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - byte[] data = getRandomByteArray(PageBlobClient.PAGE_BYTES * 4) + def data = getRandomByteArray(PageBlobClient.PAGE_BYTES * 4) - def sourceURL = cc.getPageBlobClient(generateBlobName()) + def sourceURL = cc.getBlobClient(generateBlobName()).asPageBlobClient() sourceURL.create(PageBlobClient.PAGE_BYTES * 4) sourceURL.uploadPages(new PageRange().setStart(0).setEnd(PageBlobClient.PAGE_BYTES * 4 - 1), new ByteArrayInputStream(data)) - def destURL = cc.getPageBlobClient(generateBlobName()) + def destURL = cc.getBlobClient(generateBlobName()).asPageBlobClient() destURL.create(PageBlobClient.PAGE_BYTES * 2) when: @@ -330,7 +329,7 @@ class PageBlobAPITest extends APISpec { sourceURL.getBlobUrl(), PageBlobClient.PAGE_BYTES * 2) then: - ByteArrayOutputStream outputStream = new ByteArrayOutputStream() + def outputStream = new ByteArrayOutputStream() destURL.download(outputStream) outputStream.toByteArray() == Arrays.copyOfRange(data, PageBlobClient.PAGE_BYTES * 2, PageBlobClient.PAGE_BYTES * 4) } @@ -346,7 +345,7 @@ class PageBlobAPITest extends APISpec { def "Upload page from URL MD5"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - def destURL = cc.getPageBlobClient(generateBlobName()) + def destURL = cc.getBlobClient(generateBlobName()).asPageBlobClient() destURL.create(PageBlobClient.PAGE_BYTES) def data = getRandomByteArray(PageBlobClient.PAGE_BYTES) def pageRange = new PageRange().setStart(0).setEnd(PageBlobClient.PAGE_BYTES - 1) @@ -363,7 +362,7 @@ class PageBlobAPITest extends APISpec { def "Upload page from URL MD5 fail"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - def destURL = cc.getPageBlobClient(generateBlobName()) + def destURL = cc.getBlobClient(generateBlobName()).asPageBlobClient() destURL.create(PageBlobClient.PAGE_BYTES) def pageRange = new PageRange().setStart(0).setEnd(PageBlobClient.PAGE_BYTES - 1) bc.uploadPages(pageRange, new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) @@ -380,7 +379,7 @@ class PageBlobAPITest extends APISpec { def "Upload page from URL destination AC"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - def sourceURL = cc.getPageBlobClient(generateBlobName()) + def sourceURL = cc.getBlobClient(generateBlobName()).asPageBlobClient() sourceURL.create(PageBlobClient.PAGE_BYTES) def pageRange = new PageRange().setStart(0).setEnd(PageBlobClient.PAGE_BYTES - 1) sourceURL.uploadPages(pageRange, new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) @@ -418,7 +417,7 @@ class PageBlobAPITest extends APISpec { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - def sourceURL = cc.getPageBlobClient(generateBlobName()) + def sourceURL = cc.getBlobClient(generateBlobName()).asPageBlobClient() sourceURL.create(PageBlobClient.PAGE_BYTES) def pageRange = new PageRange().setStart(0).setEnd(PageBlobClient.PAGE_BYTES - 1) sourceURL.uploadPages(pageRange, new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) @@ -458,7 +457,7 @@ class PageBlobAPITest extends APISpec { def "Upload page from URL source AC"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - def sourceURL = cc.getPageBlobClient(generateBlobName()) + def sourceURL = cc.getBlobClient(generateBlobName()).asPageBlobClient() sourceURL.create(PageBlobClient.PAGE_BYTES) def pageRange = new PageRange().setStart(0).setEnd(PageBlobClient.PAGE_BYTES - 1) sourceURL.uploadPages(pageRange, new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) @@ -486,7 +485,7 @@ class PageBlobAPITest extends APISpec { def "Upload page from URL source AC fail"() { setup: cc.setAccessPolicy(PublicAccessType.CONTAINER, null) - def sourceURL = cc.getPageBlobClient(generateBlobName()) + def sourceURL = cc.getBlobClient(generateBlobName()).asPageBlobClient() sourceURL.create(PageBlobClient.PAGE_BYTES) def pageRange = new PageRange().setStart(0).setEnd(PageBlobClient.PAGE_BYTES - 1) sourceURL.uploadPages(pageRange, new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) @@ -516,7 +515,7 @@ class PageBlobAPITest extends APISpec { new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES)), null, null, null) when: - Response response = bc.clearPagesWithResponse(new PageRange().setStart(0).setEnd(PageBlobClient.PAGE_BYTES - 1), null, null, null) + def response = bc.clearPagesWithResponse(new PageRange().setStart(0).setEnd(PageBlobClient.PAGE_BYTES - 1), null, null, null) then: bc.getPageRanges(new BlobRange(0)).getPageRange().size() == 0 @@ -606,7 +605,7 @@ class PageBlobAPITest extends APISpec { def "Clear page error"() { setup: - bc = cc.getPageBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asPageBlobClient() when: bc.clearPages(new PageRange().setStart(0).setEnd(PageBlobClient.PAGE_BYTES - 1)) @@ -643,7 +642,7 @@ class PageBlobAPITest extends APISpec { setup: match = setupBlobMatchCondition(bc, match) leaseID = setupBlobLeaseCondition(bc, leaseID) - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(leaseID)) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -671,7 +670,7 @@ class PageBlobAPITest extends APISpec { @Unroll def "Get page ranges AC fail"() { setup: - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(setupBlobLeaseCondition(bc, leaseID))) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -696,7 +695,7 @@ class PageBlobAPITest extends APISpec { def "Get page ranges error"() { setup: - bc = cc.getPageBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asPageBlobClient() when: bc.getPageRanges(null) @@ -748,7 +747,7 @@ class PageBlobAPITest extends APISpec { def "Get page ranges diff AC"() { setup: def snapId = bc.createSnapshot().getSnapshotId() - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(setupBlobLeaseCondition(bc, leaseID))) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -777,7 +776,7 @@ class PageBlobAPITest extends APISpec { setup: def snapId = bc.createSnapshot().getSnapshotId() - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(setupBlobLeaseCondition(bc, leaseID))) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -802,7 +801,7 @@ class PageBlobAPITest extends APISpec { def "Get page ranges diff error"() { setup: - bc = cc.getPageBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asPageBlobClient() when: bc.getPageRangesDiff(null, "snapshot") @@ -850,7 +849,7 @@ class PageBlobAPITest extends APISpec { @Unroll def "Resize AC"() { setup: - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(setupBlobLeaseCondition(bc, leaseID))) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -874,7 +873,7 @@ class PageBlobAPITest extends APISpec { @Unroll def "Resize AC fail"() { setup: - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(setupBlobLeaseCondition(bc, leaseID))) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -899,7 +898,7 @@ class PageBlobAPITest extends APISpec { def "Resize error"() { setup: - bc = cc.getPageBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asPageBlobClient() when: bc.resize(0) @@ -911,7 +910,7 @@ class PageBlobAPITest extends APISpec { @Unroll def "Sequence number"() { setup: - Response response = bc.updateSequenceNumberWithResponse(action, number, null, null, null) + def response = bc.updateSequenceNumberWithResponse(action, number, null, null, null) expect: bc.getProperties().getBlobSequenceNumber() == result @@ -933,7 +932,7 @@ class PageBlobAPITest extends APISpec { @Unroll def "Sequence number AC"() { setup: - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(setupBlobLeaseCondition(bc, leaseID))) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -958,7 +957,7 @@ class PageBlobAPITest extends APISpec { @Unroll def "Sequence number AC fail"() { setup: - BlobAccessConditions bac = new BlobAccessConditions() + def bac = new BlobAccessConditions() .setLeaseAccessConditions(new LeaseAccessConditions().setLeaseId(setupBlobLeaseCondition(bc, leaseID))) .setModifiedAccessConditions(new ModifiedAccessConditions() .setIfModifiedSince(modified) @@ -983,7 +982,7 @@ class PageBlobAPITest extends APISpec { def "Sequence number error"() { setup: - bc = cc.getPageBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asPageBlobClient() when: bc.updateSequenceNumber(SequenceNumberActionType.UPDATE, 0) @@ -995,7 +994,7 @@ class PageBlobAPITest extends APISpec { def "Start incremental copy"() { setup: cc.setAccessPolicy(PublicAccessType.BLOB, null) - def bc2 = cc.getPageBlobClient(generateBlobName()) + def bc2 = cc.getBlobClient(generateBlobName()).asPageBlobClient() def snapId = bc.createSnapshot().getSnapshotId() def copyResponse = bc2.copyIncrementalWithResponse(bc.getBlobUrl(), snapId, null, null, null) @@ -1004,7 +1003,7 @@ class PageBlobAPITest extends APISpec { def start = OffsetDateTime.now() while (status != CopyStatusType.SUCCESS) { status = bc2.getProperties().getCopyStatus() - OffsetDateTime currentTime = OffsetDateTime.now() + def currentTime = OffsetDateTime.now() if (status == CopyStatusType.FAILED || currentTime.minusMinutes(1) == start) { throw new Exception("Copy failed or took too long") } @@ -1023,8 +1022,8 @@ class PageBlobAPITest extends APISpec { def "Start incremental copy min"() { setup: cc.setAccessPolicy(PublicAccessType.BLOB, null) - def bc2 = cc.getPageBlobClient(generateBlobName()) - String snapshot = bc.createSnapshot().getSnapshotId() + def bc2 = cc.getBlobClient(generateBlobName()).asPageBlobClient() + def snapshot = bc.createSnapshot().getSnapshotId() expect: bc2.copyIncrementalWithResponse(bc.getBlobUrl(), snapshot, null, null, null).getStatusCode() == 202 @@ -1034,8 +1033,8 @@ class PageBlobAPITest extends APISpec { def "Start incremental copy AC"() { setup: cc.setAccessPolicy(PublicAccessType.BLOB, null) - PageBlobClient bu2 = cc.getPageBlobClient(generateBlobName()) - String snapshot = bc.createSnapshot().getSnapshotId() + def bu2 = cc.getBlobClient(generateBlobName()).asPageBlobClient() + def snapshot = bc.createSnapshot().getSnapshotId() def copyResponse = bu2.copyIncrementalWithResponse(bc.getBlobUrl(), snapshot, null, null, null) @@ -1043,7 +1042,7 @@ class PageBlobAPITest extends APISpec { def start = OffsetDateTime.now() while (status != CopyStatusType.SUCCESS) { status = bu2.getProperties().getCopyStatus() - OffsetDateTime currentTime = OffsetDateTime.now() + def currentTime = OffsetDateTime.now() if (status == CopyStatusType.FAILED || currentTime.minusMinutes(1) == start) { throw new Exception("Copy failed or took too long") } @@ -1074,8 +1073,8 @@ class PageBlobAPITest extends APISpec { def "Start incremental copy AC fail"() { setup: cc.setAccessPolicy(PublicAccessType.BLOB, null) - PageBlobClient bu2 = cc.getPageBlobClient(generateBlobName()) - String snapshot = bc.createSnapshot().getSnapshotId() + def bu2 = cc.getBlobClient(generateBlobName()).asPageBlobClient() + def snapshot = bc.createSnapshot().getSnapshotId() bu2.copyIncremental(bc.getBlobUrl(), snapshot) snapshot = bc.createSnapshot().getSnapshotId() noneMatch = setupBlobMatchCondition(bu2, noneMatch) @@ -1101,7 +1100,7 @@ class PageBlobAPITest extends APISpec { def "Start incremental copy error"() { setup: - bc = cc.getPageBlobClient(generateBlobName()) + bc = cc.getBlobClient(generateBlobName()).asPageBlobClient() when: bc.copyIncremental(new URL("https://www.error.com"), "snapshot") diff --git a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/BaseClientBuilder.java b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/BaseClientBuilder.java index 4006f598c0fc..05bba1f5c36f 100644 --- a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/BaseClientBuilder.java +++ b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/BaseClientBuilder.java @@ -140,13 +140,12 @@ private HttpPipelinePolicy makeValidationPolicy() { * @return the updated builder * @throws NullPointerException If {@code credential} is {@code null}. */ - @SuppressWarnings("unchecked") public final T credential(SharedKeyCredential credential) { this.sharedKeyCredential = Objects.requireNonNull(credential); this.tokenCredential = null; this.sasTokenCredential = null; - return (T) this; + return getClazz().cast(this); } /** @@ -156,13 +155,12 @@ public final T credential(SharedKeyCredential credential) { * @return the updated builder * @throws NullPointerException If {@code credential} is {@code null}. */ - @SuppressWarnings("unchecked") public T credential(TokenCredential credential) { this.tokenCredential = Objects.requireNonNull(credential); this.sharedKeyCredential = null; this.sasTokenCredential = null; - return (T) this; + return getClazz().cast(this); } /** @@ -172,13 +170,12 @@ public T credential(TokenCredential credential) { * @return the updated builder * @throws NullPointerException If {@code credential} is {@code null}. */ - @SuppressWarnings("unchecked") public final T credential(SASTokenCredential credential) { this.sasTokenCredential = Objects.requireNonNull(credential); this.sharedKeyCredential = null; this.tokenCredential = null; - return (T) this; + return getClazz().cast(this); } /** @@ -186,13 +183,12 @@ public final T credential(SASTokenCredential credential) { * * @return the updated buildr */ - @SuppressWarnings("unchecked") public T setAnonymousCredential() { this.sharedKeyCredential = null; this.tokenCredential = null; this.sasTokenCredential = null; - return (T) this; + return getClazz().cast(this); } /** @@ -213,7 +209,6 @@ protected final boolean hasCredential() { * @return the updated builder * @throws IllegalArgumentException If {@code connectionString} doesn't contain AccountName or AccountKey. */ - @SuppressWarnings("unchecked") public final T connectionString(String connectionString) { Objects.requireNonNull(connectionString); @@ -242,7 +237,7 @@ public final T connectionString(String connectionString) { // Use accountName and accountKey to get the SAS token using the credential class. credential(new SharedKeyCredential(accountName, accountKey)); - return (T) this; + return getClazz().cast(this); } /** @@ -258,10 +253,9 @@ public final T connectionString(String connectionString) { * @param httpClient http client to send requests * @return the updated buildr */ - @SuppressWarnings("unchecked") public final T httpClient(HttpClient httpClient) { this.httpClient = httpClient; // builder implicitly handles default creation if null, so no null check - return (T) this; + return getClazz().cast(this); } /** @@ -271,10 +265,9 @@ public final T httpClient(HttpClient httpClient) { * @return the updated builder * @throws NullPointerException If {@code pipelinePolicy} is {@code null} */ - @SuppressWarnings("unchecked") public final T addPolicy(HttpPipelinePolicy pipelinePolicy) { this.additionalPolicies.add(Objects.requireNonNull(pipelinePolicy)); - return (T) this; + return getClazz().cast(this); } /** @@ -284,10 +277,9 @@ public final T addPolicy(HttpPipelinePolicy pipelinePolicy) { * @return the updated builder * @throws NullPointerException If {@code logLevel} is {@code null} */ - @SuppressWarnings("unchecked") public final T httpLogDetailLevel(HttpLogDetailLevel logLevel) { this.logLevel = Objects.requireNonNull(logLevel); - return (T) this; + return getClazz().cast(this); } /** @@ -297,10 +289,9 @@ public final T httpLogDetailLevel(HttpLogDetailLevel logLevel) { * @param configuration configuration store * @return the updated buildr */ - @SuppressWarnings("unchecked") public final T configuration(Configuration configuration) { this.configuration = configuration; - return (T) this; + return getClazz().cast(this); } /** @@ -310,7 +301,7 @@ public final T configuration(Configuration configuration) { */ protected final Configuration getConfiguration() { if (this.configuration == null) { - this.configuration = Configuration.getGlobalConfiguration(); + this.configuration = Configuration.getGlobalConfiguration().clone(); } return this.configuration; @@ -323,10 +314,9 @@ protected final Configuration getConfiguration() { * @return the updated builder * @throws NullPointerException If {@code retryOptions} is {@code null} */ - @SuppressWarnings("unchecked") public final T retryOptions(RequestRetryOptions retryOptions) { this.retryOptions = Objects.requireNonNull(retryOptions); - return (T) this; + return getClazz().cast(this); } /** @@ -338,10 +328,9 @@ public final T retryOptions(RequestRetryOptions retryOptions) { * @param pipeline The HTTP pipeline to use for sending service requests and receiving responses. * @return The updated builder. */ - @SuppressWarnings("unchecked") public final T pipeline(HttpPipeline pipeline) { this.pipeline = pipeline; - return (T) this; + return getClazz().cast(this); } /** @@ -359,4 +348,11 @@ protected final HttpPipeline getPipeline() { * @return The policy. */ protected abstract UserAgentPolicy getUserAgentPolicy(); + + /** + * Gets the implementing client builder class. + * + * @return the implementing client builder class. + */ + protected abstract Class getClazz(); } diff --git a/sdk/storage/azure-storage-common/src/samples/java/com/azure/storage/common/credentials/SASTokenCredentialJavaDocCodeSnippets.java b/sdk/storage/azure-storage-common/src/samples/java/com/azure/storage/common/credentials/SASTokenCredentialJavaDocCodeSnippets.java index 3a619bc18904..1c4dda3832b2 100644 --- a/sdk/storage/azure-storage-common/src/samples/java/com/azure/storage/common/credentials/SASTokenCredentialJavaDocCodeSnippets.java +++ b/sdk/storage/azure-storage-common/src/samples/java/com/azure/storage/common/credentials/SASTokenCredentialJavaDocCodeSnippets.java @@ -13,16 +13,19 @@ * Code snippets for {@link SASTokenCredential}. */ public final class SASTokenCredentialJavaDocCodeSnippets { - private final String preformattedSASToken = "sasToken"; private final URL url = new URL("https://www.example.com?queryString"); - private SASTokenCredentialJavaDocCodeSnippets() throws MalformedURLException { + /** + * @throws MalformedURLException ignored + */ + public SASTokenCredentialJavaDocCodeSnippets() throws MalformedURLException { } /** * Code sample for {@link SASTokenCredential#fromSASTokenString(String)}. */ public void fromSASTokenString() { + String preformattedSASToken = "sasToken"; // BEGIN: com.azure.storage.common.credentials.SASTokenCredential.fromSASTokenString#String SASTokenCredential credential = SASTokenCredential.fromSASTokenString(preformattedSASToken); // END: com.azure.storage.common.credentials.SASTokenCredential.fromSASTokenString#String diff --git a/sdk/storage/azure-storage-common/src/samples/java/com/azure/storage/common/credentials/SharedKeyCredentialJavaDocCodeSnippets.java b/sdk/storage/azure-storage-common/src/samples/java/com/azure/storage/common/credentials/SharedKeyCredentialJavaDocCodeSnippets.java index 510e41285c53..655b231e8fcf 100644 --- a/sdk/storage/azure-storage-common/src/samples/java/com/azure/storage/common/credentials/SharedKeyCredentialJavaDocCodeSnippets.java +++ b/sdk/storage/azure-storage-common/src/samples/java/com/azure/storage/common/credentials/SharedKeyCredentialJavaDocCodeSnippets.java @@ -7,11 +7,12 @@ * Code snippets for {@link SharedKeyCredential}. */ public final class SharedKeyCredentialJavaDocCodeSnippets { - private final String connectionString = "AccountName=accountname;AccountKey=accountkey;additionalproperties"; + /** * Code snippets for {@link SharedKeyCredential#fromConnectionString(String)}. */ public void fromConnectionString() { + String connectionString = "AccountName=accountname;AccountKey=accountkey;additionalproperties"; // BEGIN: com.azure.storage.common.credentials.SharedKeyCredential.fromConnectionString#String SharedKeyCredential credential = SharedKeyCredential.fromConnectionString(connectionString); // END: com.azure.storage.common.credentials.SharedKeyCredential.fromConnectionString#String diff --git a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/BaseFileClientBuilder.java b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/BaseFileClientBuilder.java index 0677c6715ef3..29f63ff1b8ea 100644 --- a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/BaseFileClientBuilder.java +++ b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/BaseFileClientBuilder.java @@ -33,6 +33,7 @@ protected final String getServiceUrlMidfix() { * @return the updated builder * @throws NullPointerException If {@code credential} is {@code null}. */ + @Override public final T credential(TokenCredential credential) { throw logger.logExceptionAsError(new UnsupportedOperationException( "Azure Storage file service does not support token authorization.")); @@ -44,6 +45,7 @@ public final T credential(TokenCredential credential) { * * @return the updated builder */ + @Override public final T setAnonymousCredential() { throw logger.logExceptionAsError(new UnsupportedOperationException( "Azure Storage file service does not support anonymous access.")); diff --git a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/DirectoryAsyncClient.java b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/DirectoryAsyncClient.java index 233843efae69..f8752bd72812 100644 --- a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/DirectoryAsyncClient.java +++ b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/DirectoryAsyncClient.java @@ -3,12 +3,12 @@ package com.azure.storage.file; +import com.azure.core.annotation.ServiceClient; import com.azure.core.http.HttpPipeline; 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.http.rest.SimpleResponse; -import com.azure.core.annotation.ServiceClient; import com.azure.core.implementation.http.PagedResponseBase; import com.azure.core.implementation.util.FluxUtil; import com.azure.core.util.Context; diff --git a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/DirectoryClient.java b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/DirectoryClient.java index 284387bd90a4..50facf50ef28 100644 --- a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/DirectoryClient.java +++ b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/DirectoryClient.java @@ -3,10 +3,10 @@ package com.azure.storage.file; +import com.azure.core.annotation.ServiceClient; import com.azure.core.http.rest.PagedIterable; import com.azure.core.http.rest.Response; import com.azure.core.http.rest.SimpleResponse; -import com.azure.core.annotation.ServiceClient; import com.azure.core.util.Context; import com.azure.storage.common.Utility; import com.azure.storage.common.credentials.SASTokenCredential; diff --git a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileAsyncClient.java b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileAsyncClient.java index 9bbb715b9d72..f522361b49db 100644 --- a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileAsyncClient.java +++ b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileAsyncClient.java @@ -3,12 +3,12 @@ package com.azure.storage.file; +import com.azure.core.annotation.ServiceClient; import com.azure.core.http.HttpPipeline; 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.http.rest.SimpleResponse; -import com.azure.core.annotation.ServiceClient; import com.azure.core.implementation.http.PagedResponseBase; import com.azure.core.implementation.util.FluxUtil; import com.azure.core.util.Context; diff --git a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileClient.java b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileClient.java index 3bba26613d94..7b29e73325bd 100644 --- a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileClient.java +++ b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileClient.java @@ -3,9 +3,9 @@ package com.azure.storage.file; +import com.azure.core.annotation.ServiceClient; import com.azure.core.http.rest.PagedIterable; import com.azure.core.http.rest.Response; -import com.azure.core.annotation.ServiceClient; import com.azure.core.util.Context; import com.azure.storage.common.IPRange; import com.azure.storage.common.SASProtocol; diff --git a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileClientBuilder.java b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileClientBuilder.java index 28b72e989660..82a7e55c612c 100644 --- a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileClientBuilder.java +++ b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileClientBuilder.java @@ -254,4 +254,9 @@ public FileClientBuilder resourcePath(String resourcePath) { this.resourcePath = resourcePath; return this; } + + @Override + protected Class getClazz() { + return FileClientBuilder.class; + } } diff --git a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileServiceAsyncClient.java b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileServiceAsyncClient.java index 8596935e6547..33e26392c506 100644 --- a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileServiceAsyncClient.java +++ b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileServiceAsyncClient.java @@ -3,11 +3,11 @@ package com.azure.storage.file; +import com.azure.core.annotation.ServiceClient; 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.http.rest.SimpleResponse; -import com.azure.core.annotation.ServiceClient; import com.azure.core.implementation.http.PagedResponseBase; import com.azure.core.implementation.util.FluxUtil; import com.azure.core.implementation.util.ImplUtils; diff --git a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileServiceClient.java b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileServiceClient.java index b777dbd6e29c..9924b22530dd 100644 --- a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileServiceClient.java +++ b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileServiceClient.java @@ -3,10 +3,10 @@ package com.azure.storage.file; +import com.azure.core.annotation.ServiceClient; import com.azure.core.http.rest.PagedIterable; import com.azure.core.http.rest.Response; import com.azure.core.http.rest.SimpleResponse; -import com.azure.core.annotation.ServiceClient; import com.azure.core.util.Context; import com.azure.storage.common.AccountSASPermission; import com.azure.storage.common.AccountSASResourceType; diff --git a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileServiceClientBuilder.java b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileServiceClientBuilder.java index d5b3a66965f5..744e0b82a88d 100644 --- a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileServiceClientBuilder.java +++ b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/FileServiceClientBuilder.java @@ -151,4 +151,9 @@ public FileServiceClientBuilder endpoint(String endpoint) { return this; } + + @Override + protected Class getClazz() { + return FileServiceClientBuilder.class; + } } diff --git a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/ShareAsyncClient.java b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/ShareAsyncClient.java index c22826a0976e..a7e55a542510 100644 --- a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/ShareAsyncClient.java +++ b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/ShareAsyncClient.java @@ -3,13 +3,13 @@ package com.azure.storage.file; +import com.azure.core.annotation.ServiceClient; import com.azure.core.http.HttpPipeline; 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.http.rest.SimpleResponse; import com.azure.core.implementation.DateTimeRfc1123; -import com.azure.core.annotation.ServiceClient; import com.azure.core.implementation.http.PagedResponseBase; import com.azure.core.implementation.util.FluxUtil; import com.azure.core.util.Context; diff --git a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/ShareClient.java b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/ShareClient.java index 0eb8401ec664..a7275f948e1f 100644 --- a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/ShareClient.java +++ b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/ShareClient.java @@ -3,10 +3,10 @@ package com.azure.storage.file; +import com.azure.core.annotation.ServiceClient; import com.azure.core.http.rest.PagedIterable; import com.azure.core.http.rest.Response; import com.azure.core.http.rest.SimpleResponse; -import com.azure.core.annotation.ServiceClient; import com.azure.core.util.Context; import com.azure.storage.common.IPRange; import com.azure.storage.common.SASProtocol; diff --git a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/ShareClientBuilder.java b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/ShareClientBuilder.java index 9002a46b6dff..c4605af95dc4 100644 --- a/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/ShareClientBuilder.java +++ b/sdk/storage/azure-storage-file/src/main/java/com/azure/storage/file/ShareClientBuilder.java @@ -194,4 +194,9 @@ public ShareClientBuilder snapshot(String snapshot) { this.snapshot = snapshot; return this; } + + @Override + protected Class getClazz() { + return ShareClientBuilder.class; + } } diff --git a/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueAsyncClient.java b/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueAsyncClient.java index ce12dac6755c..1a8543661560 100644 --- a/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueAsyncClient.java +++ b/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueAsyncClient.java @@ -2,12 +2,12 @@ // Licensed under the MIT License. package com.azure.storage.queue; +import com.azure.core.annotation.ServiceClient; import com.azure.core.http.HttpPipeline; 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.http.rest.SimpleResponse; -import com.azure.core.annotation.ServiceClient; import com.azure.core.implementation.http.PagedResponseBase; import com.azure.core.implementation.util.FluxUtil; import com.azure.core.util.Context; diff --git a/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueClient.java b/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueClient.java index 110a680b891f..72f36b249200 100644 --- a/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueClient.java +++ b/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueClient.java @@ -2,9 +2,9 @@ // Licensed under the MIT License. package com.azure.storage.queue; +import com.azure.core.annotation.ServiceClient; import com.azure.core.http.rest.PagedIterable; import com.azure.core.http.rest.Response; -import com.azure.core.annotation.ServiceClient; import com.azure.core.util.Context; import com.azure.storage.common.IPRange; import com.azure.storage.common.SASProtocol; diff --git a/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueClientBuilder.java b/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueClientBuilder.java index a38451a7b444..7cf7014c1e1b 100644 --- a/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueClientBuilder.java +++ b/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueClientBuilder.java @@ -183,4 +183,9 @@ public QueueClientBuilder queueName(String queueName) { this.queueName = Objects.requireNonNull(queueName); return this; } + + @Override + protected Class getClazz() { + return QueueClientBuilder.class; + } } diff --git a/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueServiceAsyncClient.java b/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueServiceAsyncClient.java index cc4a80cab2af..bf10363c1c7c 100644 --- a/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueServiceAsyncClient.java +++ b/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueServiceAsyncClient.java @@ -2,11 +2,11 @@ // Licensed under the MIT License. package com.azure.storage.queue; +import com.azure.core.annotation.ServiceClient; 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.http.rest.SimpleResponse; -import com.azure.core.annotation.ServiceClient; import com.azure.core.implementation.http.PagedResponseBase; import com.azure.core.implementation.util.FluxUtil; import com.azure.core.util.Context; diff --git a/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueServiceClient.java b/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueServiceClient.java index 260d5d9d7d51..f05b7ec9c504 100644 --- a/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueServiceClient.java +++ b/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueServiceClient.java @@ -2,10 +2,10 @@ // Licensed under the MIT License. package com.azure.storage.queue; +import com.azure.core.annotation.ServiceClient; import com.azure.core.http.rest.PagedIterable; import com.azure.core.http.rest.Response; import com.azure.core.http.rest.SimpleResponse; -import com.azure.core.annotation.ServiceClient; import com.azure.core.util.Context; import com.azure.storage.common.AccountSASPermission; import com.azure.storage.common.AccountSASResourceType; diff --git a/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueServiceClientBuilder.java b/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueServiceClientBuilder.java index e945835455a4..4325e10f8c0f 100644 --- a/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueServiceClientBuilder.java +++ b/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueServiceClientBuilder.java @@ -154,4 +154,9 @@ public QueueServiceClientBuilder endpoint(String endpoint) { return this; } + + @Override + protected Class getClazz() { + return QueueServiceClientBuilder.class; + } }

    * Please refer to the Azure * Docs for more information. */ -@ServiceClient(builder = BlobClientBuilder.class) -public final class PageBlobClient extends BlobClient { +@ServiceClient(builder = SpecializedBlobClientBuilder.class) +public final class PageBlobClient extends BlobClientBase { private final PageBlobAsyncClient pageBlobAsyncClient; /** @@ -60,7 +56,7 @@ public final class PageBlobClient extends BlobClient { public static final int MAX_PUT_PAGES_BYTES = PageBlobAsyncClient.MAX_PUT_PAGES_BYTES; /** - * Package-private constructor for use by {@link BlobClientBuilder}. + * Package-private constructor for use by {@link SpecializedBlobClientBuilder}. * * @param pageBlobAsyncClient the async page blob client */ @@ -122,7 +118,7 @@ public PageBlobItem create(long size) { * *