From 1ec9438d210a125ec9b265c121a9b70c217e5922 Mon Sep 17 00:00:00 2001 From: Gauri Prasad <51212198+gapra-msft@users.noreply.github.com> Date: Fri, 12 Jul 2019 11:57:48 -0700 Subject: [PATCH 1/8] Storage SAS implementation (#4404) * SAS implementation * Fixed some minor formatting issues * Fixed checkstyle problems and test issue --- .../azure/storage/blob/BlobAsyncClient.java | 259 ++++ .../com/azure/storage/blob/BlobClient.java | 207 ++++ .../com/azure/storage/blob/Constants.java | 15 + .../storage/blob/ContainerAsyncClient.java | 231 ++++ .../azure/storage/blob/ContainerClient.java | 188 +++ .../storage/blob/SASQueryParameters.java | 4 +- .../blob/ServiceSASSignatureValues.java | 182 +-- .../storage/blob/StorageAsyncClient.java | 70 ++ .../com/azure/storage/blob/StorageClient.java | 49 + .../java/com/azure/storage/blob/Utility.java | 23 + .../credentials/SASTokenCredential.java | 96 +- .../policy/SharedKeyCredentialPolicy.java | 9 + .../com/azure/storage/blob/SASTest.groovy | 1079 +++++++++++++++++ 13 files changed, 2315 insertions(+), 97 deletions(-) create mode 100644 storage/client/blob/src/test/java/com/azure/storage/blob/SASTest.groovy diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java index 7ec72ecf30b53..5042f9e782af5 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java @@ -21,6 +21,8 @@ import com.azure.storage.blob.models.ModifiedAccessConditions; 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.credentials.SharedKeyCredential; import io.netty.buffer.ByteBuf; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -35,6 +37,7 @@ import java.nio.channels.AsynchronousFileChannel; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; +import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.List; @@ -774,4 +777,260 @@ public Mono> getAccountInfo() { .getAccountInfo() .map(rb -> new SimpleResponse<>(rb, new StorageAccountInfo(rb.deserializedHeaders()))); } + + /** + * 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 + * + * @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 + * @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) { + + ServiceSASSignatureValues serviceSASSignatureValues = new ServiceSASSignatureValues(version, sasProtocol, + startTime, expiryTime, permissions == null ? null : permissions.toString(), ipRange, null /* identifier*/, + cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); + + ServiceSASSignatureValues values = configureServiceSASSignatureValues(serviceSASSignatureValues, accountName); + + SASQueryParameters sasQueryParameters = values.generateSASQueryParameters(userDelegationKey); + + return sasQueryParameters.encode(); + } + + /** + * Generates a SAS token with the specified parameters + * + * @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 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 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 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 + * + * @param identifier + * The {@code String} name of the access policy on the container this SAS references if any + * @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 + * @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) { + + ServiceSASSignatureValues serviceSASSignatureValues = new ServiceSASSignatureValues(version, sasProtocol, + startTime, expiryTime, permissions == null ? null : permissions.toString(), ipRange, identifier, + cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); + + SharedKeyCredential sharedKeyCredential = + Utility.getSharedKeyCredential(this.blobAsyncRawClient.azureBlobStorage.httpPipeline()); + + Utility.assertNotNull("sharedKeyCredential", sharedKeyCredential); + + ServiceSASSignatureValues values = configureServiceSASSignatureValues(serviceSASSignatureValues, + sharedKeyCredential.accountName()); + + SASQueryParameters sasQueryParameters = values.generateSASQueryParameters(sharedKeyCredential); + + return sasQueryParameters.encode(); + } + + /** + * Sets serviceSASSignatureValues parameters dependent on the current blob type + */ + ServiceSASSignatureValues configureServiceSASSignatureValues(ServiceSASSignatureValues serviceSASSignatureValues, + String accountName) { + + // Set canonical name + serviceSASSignatureValues.canonicalName(this.blobAsyncRawClient.azureBlobStorage.url(), accountName); + + // Set snapshotId + serviceSASSignatureValues.snapshotId(getSnapshotId()); + + // Set resource + if (isSnapshot()) { + serviceSASSignatureValues.resource(Constants.UrlConstants.SAS_BLOB_SNAPSHOT_CONSTANT); + } else { + serviceSASSignatureValues.resource(Constants.UrlConstants.SAS_BLOB_CONSTANT); + } + + return serviceSASSignatureValues; + } + + /** + * Gets the snapshotId for a blob resource + * + * @return + * A string that represents the snapshotId of the snapshot blob + */ + public String getSnapshotId() { + return this.blobAsyncRawClient.snapshot; + } + + /** + * Determines if a blob is a snapshot + * + * @return + * A boolean that indicates if a blob is a snapshot + */ + public boolean isSnapshot() { + return this.blobAsyncRawClient.snapshot != null; + } } diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java index f47c3cf6d7830..21a2212713f5c 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java @@ -16,6 +16,7 @@ import com.azure.storage.blob.models.ModifiedAccessConditions; import com.azure.storage.blob.models.ReliableDownloadOptions; import com.azure.storage.blob.models.StorageAccountInfo; +import com.azure.storage.blob.models.UserDelegationKey; import reactor.core.publisher.Mono; import java.io.IOException; @@ -23,6 +24,7 @@ import java.io.UncheckedIOException; import java.net.URL; import java.time.Duration; +import java.time.OffsetDateTime; /** * Client to a blob of any type: block, append, or page. It may only be instantiated through a {@link BlobClientBuilder} or via @@ -800,4 +802,209 @@ public Response getAccountInfo(Duration timeout) { 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 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.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 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.blobAsyncClient.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime, + startTime, version, sasProtocol, ipRange); + } + + /** + * 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 + * @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 ContainerSASPermissions} 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 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 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 + * + * @param identifier + * The {@code String} name of the access policy on the container this SAS references if any + * @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 + * @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(); + } } diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/Constants.java b/storage/client/blob/src/main/java/com/azure/storage/blob/Constants.java index 653625b572c15..fa812df4b531b 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/Constants.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/Constants.java @@ -288,6 +288,21 @@ static final class UrlConstants { */ public static final String SAS_SIGNED_KEY_VERSION = "skv"; + /** + * The SAS blob constant. + */ + public static final String SAS_BLOB_CONSTANT = "b"; + + /** + * The SAS blob snapshot constant. + */ + public static final String SAS_BLOB_SNAPSHOT_CONSTANT = "bs"; + + /** + * The SAS blob snapshot constant. + */ + public static final String SAS_CONTAINER_CONSTANT = "c"; + private UrlConstants() { // Private to prevent construction. } diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java index 406a7440b0c5b..f979f084ac151 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java @@ -24,12 +24,15 @@ import com.azure.storage.blob.models.PublicAccessType; import com.azure.storage.blob.models.SignedIdentifier; import com.azure.storage.blob.models.StorageAccountInfo; +import com.azure.storage.blob.models.UserDelegationKey; +import com.azure.storage.common.credentials.SharedKeyCredential; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.net.MalformedURLException; import java.net.URL; import java.time.Duration; +import java.time.OffsetDateTime; import java.util.List; /** @@ -878,4 +881,232 @@ public Mono> getAccountInfo() { .getAccountInfo() .map(rb -> new SimpleResponse<>(rb, new StorageAccountInfo(rb.deserializedHeaders()))); } + + /** + * 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, + ContainerSASPermission 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, + ContainerSASPermission 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 + * + * @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 + * @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, + ContainerSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, + SASProtocol sasProtocol, IPRange ipRange, String cacheControl, String contentDisposition, + String contentEncoding, String contentLanguage, String contentType) { + ServiceSASSignatureValues serviceSASSignatureValues = new ServiceSASSignatureValues(version, sasProtocol, + startTime, expiryTime, permissions == null ? null : permissions.toString(), ipRange, null /* identifier*/, + cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); + + ServiceSASSignatureValues values = configureServiceSASSignatureValues(serviceSASSignatureValues, accountName); + + SASQueryParameters sasQueryParameters = values.generateSASQueryParameters(userDelegationKey); + + return sasQueryParameters.encode(); + } + + /** + * Generates a SAS token with the specified parameters + * + * @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 generateSAS(ContainerSASPermission permissions, OffsetDateTime expiryTime) { + return this.generateSAS(null, permissions, /* identifier */ expiryTime, null /* startTime */, null /* version + */, null /* sasProtocol */, null /* ipRange */, null /* cacheControl */, null /* contentDisposition */, + 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 /* + contentDisposition */, 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 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 generateSAS(String identifier, ContainerSASPermission permissions, OffsetDateTime expiryTime, + OffsetDateTime startTime, + String version, SASProtocol sasProtocol, IPRange ipRange) { + return this.generateSAS(identifier, permissions, expiryTime, startTime, version, sasProtocol, ipRange, null + /* cacheControl */, null /* contentDisposition */, 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 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 + * @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, ContainerSASPermission permissions, OffsetDateTime expiryTime, + OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange, String cacheControl, + String contentDisposition, String contentEncoding, String contentLanguage, String contentType) { + ServiceSASSignatureValues serviceSASSignatureValues = new ServiceSASSignatureValues(version, sasProtocol, + startTime, expiryTime, permissions == null ? null : permissions.toString(), ipRange, identifier, + cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); + + SharedKeyCredential sharedKeyCredential = + Utility.getSharedKeyCredential(this.containerAsyncRawClient.azureBlobStorage.httpPipeline()); + + Utility.assertNotNull("sharedKeyCredential", sharedKeyCredential); + + ServiceSASSignatureValues values = configureServiceSASSignatureValues(serviceSASSignatureValues, + sharedKeyCredential.accountName()); + + SASQueryParameters sasQueryParameters = values.generateSASQueryParameters(sharedKeyCredential); + + return sasQueryParameters.encode(); + } + + /** + * Sets serviceSASSignatureValues parameters dependent on the current blob type + */ + private ServiceSASSignatureValues configureServiceSASSignatureValues(ServiceSASSignatureValues serviceSASSignatureValues, String accountName) { + // Set canonical name + serviceSASSignatureValues.canonicalName(this.containerAsyncRawClient.azureBlobStorage.url(), accountName); + + // Set snapshotId to null + serviceSASSignatureValues.snapshotId(null); + + // Set resource + serviceSASSignatureValues.resource(Constants.UrlConstants.SAS_CONTAINER_CONSTANT); + return serviceSASSignatureValues; + } } diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClient.java index b8c1f9d8bd09e..c9733fd3a7f61 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClient.java @@ -15,11 +15,13 @@ import com.azure.storage.blob.models.PublicAccessType; import com.azure.storage.blob.models.SignedIdentifier; import com.azure.storage.blob.models.StorageAccountInfo; +import com.azure.storage.blob.models.UserDelegationKey; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.net.URL; import java.time.Duration; +import java.time.OffsetDateTime; import java.util.List; /** @@ -738,4 +740,190 @@ public Response getAccountInfo(Duration timeout) { 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 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, + ContainerSASPermission permissions, OffsetDateTime expiryTime) { + return this.containerAsyncClient.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 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, + ContainerSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, + SASProtocol sasProtocol, IPRange ipRange) { + return this.containerAsyncClient.generateUserDelegationSAS(userDelegationKey, accountName, permissions, + expiryTime, startTime, version, sasProtocol, ipRange); + } + + /** + * 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 + * @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, + ContainerSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, + SASProtocol sasProtocol, IPRange ipRange, String cacheControl, String contentDisposition, + String contentEncoding, String contentLanguage, String contentType) { + return this.containerAsyncClient.generateUserDelegationSAS(userDelegationKey, accountName, permissions, + expiryTime, startTime, version, sasProtocol, ipRange, cacheControl, contentDisposition, contentEncoding, + contentLanguage, contentType); + } + + /** + * Generates a SAS token with the specified parameters + * + * @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 generateSAS(ContainerSASPermission permissions, OffsetDateTime expiryTime) { + return this.containerAsyncClient.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.containerAsyncClient.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 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 generateSAS(String identifier, ContainerSASPermission permissions, OffsetDateTime expiryTime, + OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange) { + return this.containerAsyncClient.generateSAS(identifier, permissions, expiryTime, startTime, version, + sasProtocol, ipRange); + } + + /** + * 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 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 + * @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, ContainerSASPermission permissions, OffsetDateTime expiryTime, + OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange, String cacheControl, + String contentDisposition, String contentEncoding, String contentLanguage, String contentType) { + return this.containerAsyncClient.generateSAS(identifier, permissions, expiryTime, startTime, version, + sasProtocol, ipRange, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); + } } diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/SASQueryParameters.java b/storage/client/blob/src/main/java/com/azure/storage/blob/SASQueryParameters.java index b6afd82addcab..cd918e636bbd4 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/SASQueryParameters.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/SASQueryParameters.java @@ -333,9 +333,7 @@ UserDelegationKey userDelegationKey() { private void tryAppendQueryParameter(StringBuilder sb, String param, Object value) { if (value != null) { - if (sb.length() == 0) { - sb.append('?'); - } else { + if (sb.length() != 0) { sb.append('&'); } sb.append(safeURLEncode(param)).append('=').append(safeURLEncode(value.toString())); diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ServiceSASSignatureValues.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ServiceSASSignatureValues.java index 7450ae699f5a4..114c28eb71209 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/ServiceSASSignatureValues.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ServiceSASSignatureValues.java @@ -6,6 +6,8 @@ import com.azure.storage.blob.models.UserDelegationKey; import com.azure.storage.common.credentials.SharedKeyCredential; +import java.net.MalformedURLException; +import java.net.URL; import java.security.InvalidKeyException; import java.time.OffsetDateTime; @@ -40,9 +42,9 @@ final class ServiceSASSignatureValues { private IPRange ipRange; - private String containerName; + private String canonicalName; - private String blobName; + private String resource; private String snapshotId; @@ -64,6 +66,43 @@ final class ServiceSASSignatureValues { ServiceSASSignatureValues() { } + /** + * Creates an object with the specified expiry time and permissions + * @param expiryTime + * @param permissions + */ + ServiceSASSignatureValues(OffsetDateTime expiryTime, String permissions) { + this.expiryTime = expiryTime; + this.permissions = permissions; + } + + /** + * Creates an object with the specified identifier + * @param identifier + */ + ServiceSASSignatureValues(String identifier) { + this.identifier = identifier; + } + + ServiceSASSignatureValues(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) { + this.version = version; + } + this.protocol = sasProtocol; + this.startTime = startTime; + this.expiryTime = expiryTime; + this.permissions = permission; + this.ipRange = ipRange; + this.identifier = identifier; + this.cacheControl = cacheControl; + this.contentDisposition = contentDisposition; + this.contentEncoding = contentEncoding; + this.contentLanguage = contentLanguage; + this.contentType = contentType; + } + /** * The version of the service this SAS will target. If not specified, it will default to the version targeted by the * library. @@ -159,32 +198,51 @@ public ServiceSASSignatureValues ipRange(IPRange ipRange) { } /** - * The name of the container the SAS user may access. + * The resource the SAS user may access. */ - public String containerName() { - return containerName; + public String resource() { + return resource; } /** - * The name of the container the SAS user may access. + * The resource the SAS user may access. */ - public ServiceSASSignatureValues containerName(String containerName) { - this.containerName = containerName; + public ServiceSASSignatureValues resource(String resource) { + this.resource = resource; return this; } /** - * The name of the blob the SAS user may access. + * The canonical name of the object the SAS user may access. */ - public String blobName() { - return blobName; + public String canonicalName() { + return canonicalName; } /** - * The name of the blob the SAS user may access. + * The canonical name of the object the SAS user may access. */ - public ServiceSASSignatureValues blobName(String blobName) { - this.blobName = blobName; + public ServiceSASSignatureValues canonicalName(String canonicalName) { + this.canonicalName = canonicalName; + return this; + } + + /** + * The canonical name of the object the SAS user may access. + * @throws RuntimeException If urlString is a malformed URL. + */ + public ServiceSASSignatureValues canonicalName(String urlString, String accountName) { + URL url = null; + try { + url = new URL(urlString); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + + StringBuilder canonicalName = new StringBuilder("/blob"); + canonicalName.append('/').append(accountName).append(url.getPath()); + this.canonicalName = canonicalName.toString(); + return this; } @@ -192,7 +250,7 @@ public ServiceSASSignatureValues blobName(String blobName) { * The specific snapshot the SAS user may access. */ public String snapshotId() { - return snapshotId; + return this.snapshotId; } /** @@ -309,13 +367,10 @@ public ServiceSASSignatureValues contentType(String contentType) { */ public SASQueryParameters generateSASQueryParameters(SharedKeyCredential sharedKeyCredentials) { Utility.assertNotNull("sharedKeyCredentials", sharedKeyCredentials); - assertGenerateOK(); - - String resource = getResource(); - String verifiedPermissions = getVerifiedPermissions(); + assertGenerateOK(false); // Signature is generated on the un-url-encoded values. - final String stringToSign = stringToSign(verifiedPermissions, resource, sharedKeyCredentials); + final String stringToSign = stringToSign(); String signature = null; try { @@ -336,22 +391,15 @@ public SASQueryParameters generateSASQueryParameters(SharedKeyCredential sharedK * @param delegationKey * A {@link UserDelegationKey} object used to sign the SAS values. * - * @param accountName - * Name of the account holding the resource this SAS is authorizing. - * * @return {@link SASQueryParameters} * @throws Error If the accountKey is not a valid Base64-encoded string. */ - public SASQueryParameters generateSASQueryParameters(UserDelegationKey delegationKey, String accountName) { + public SASQueryParameters generateSASQueryParameters(UserDelegationKey delegationKey) { Utility.assertNotNull("delegationKey", delegationKey); - Utility.assertNotNull("accountName", accountName); - assertGenerateOK(); - - String resource = getResource(); - String verifiedPermissions = getVerifiedPermissions(); + assertGenerateOK(true); // Signature is generated on the un-url-encoded values. - final String stringToSign = stringToSign(verifiedPermissions, resource, delegationKey, accountName); + final String stringToSign = stringToSign(delegationKey); String signature = null; try { @@ -369,70 +417,39 @@ public SASQueryParameters generateSASQueryParameters(UserDelegationKey delegatio /** * Common assertions for generateSASQueryParameters overloads. */ - private void assertGenerateOK() { + private void assertGenerateOK(boolean usingUserDelegation) { Utility.assertNotNull("version", this.version); - Utility.assertNotNull("containerName", this.containerName); - if (blobName == null && snapshotId != null) { - throw new IllegalArgumentException("Cannot set a snapshotId without a blobName."); - } - } + Utility.assertNotNull("canonicalName", this.canonicalName); - /** - * Gets the resource string for SAS tokens based on object state. - */ - private String getResource() { - String resource = "c"; - if (!Utility.isNullOrEmpty(this.blobName)) { - resource = snapshotId != null && !snapshotId.isEmpty() ? "bs" : "b"; - } - - return resource; - } - - /** - * Gets the verified permissions string for SAS tokens based on object state. - */ - private String getVerifiedPermissions() { - String verifiedPermissions = null; - // Calling parse and toString guarantees the proper ordering and throws on invalid characters. - if (Utility.isNullOrEmpty(this.blobName)) { - if (this.permissions != null) { - verifiedPermissions = ContainerSASPermission.parse(this.permissions).toString(); + // Ensure either (expiryTime and permissions) or (identifier) is set + if (this.expiryTime == null || this.permissions == null) { + // Identifier is not required if user delegation is being used + if (!usingUserDelegation) { + Utility.assertNotNull("identifier", this.identifier); } } else { - if (this.permissions != null) { - verifiedPermissions = BlobSASPermission.parse(this.permissions).toString(); - } + Utility.assertNotNull("expiryTime", this.expiryTime); + Utility.assertNotNull("permissions", this.permissions); } - return verifiedPermissions; - } - - private String getCanonicalName(String accountName) { - // Container: "/blob/account/containername" - // Blob: "/blob/account/containername/blobname" - StringBuilder canonicalName = new StringBuilder("/blob"); - canonicalName.append('/').append(accountName).append('/').append(this.containerName); - - if (!Utility.isNullOrEmpty(this.blobName)) { - canonicalName.append("/").append(this.blobName); + if (this.resource != null && this.resource.equals(Constants.UrlConstants.SAS_CONTAINER_CONSTANT)) { + if (this.snapshotId != null) { + throw new IllegalArgumentException("Cannot set a snapshotId without resource being a blob."); + } } - - return canonicalName.toString(); } - private String stringToSign(final String verifiedPermissions, final String resource, - final SharedKeyCredential sharedKeyCredentials) { + private String stringToSign() { return String.join("\n", - verifiedPermissions == null ? "" : verifiedPermissions, + this.permissions == null ? "" : this.permissions, this.startTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.startTime), this.expiryTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.expiryTime), - getCanonicalName(sharedKeyCredentials.accountName()), + this.canonicalName == null ? "" : this.canonicalName, this.identifier == null ? "" : this.identifier, this.ipRange == null ? (new IPRange()).toString() : this.ipRange.toString(), this.protocol == null ? "" : protocol.toString(), this.version == null ? "" : this.version, - resource == null ? "" : resource, + this.resource == null ? "" : this.resource, this.snapshotId == null ? "" : this.snapshotId, this.cacheControl == null ? "" : this.cacheControl, this.contentDisposition == null ? "" : this.contentDisposition, @@ -442,13 +459,12 @@ private String stringToSign(final String verifiedPermissions, final String resou ); } - private String stringToSign(final String verifiedPermissions, final String resource, - final UserDelegationKey key, final String accountName) { + private String stringToSign(final UserDelegationKey key) { return String.join("\n", - verifiedPermissions == null ? "" : verifiedPermissions, + this.permissions == null ? "" : this.permissions, this.startTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.startTime), this.expiryTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.expiryTime), - getCanonicalName(accountName), + this.canonicalName == null ? "" : this.canonicalName, key.signedOid() == null ? "" : key.signedOid(), key.signedTid() == null ? "" : key.signedTid(), key.signedStart() == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(key.signedStart()), @@ -458,7 +474,7 @@ private String stringToSign(final String verifiedPermissions, final String resou this.ipRange == null ? new IPRange().toString() : this.ipRange.toString(), this.protocol == null ? "" : this.protocol.toString(), this.version == null ? "" : this.version, - resource == null ? "" : resource, + this.resource == null ? "" : this.resource, this.snapshotId == null ? "" : this.snapshotId, this.cacheControl == null ? "" : this.cacheControl, this.contentDisposition == null ? "" : this.contentDisposition, diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncClient.java index d5b0aecc3a3f1..c6c48d7e5770d 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncClient.java @@ -18,6 +18,7 @@ import com.azure.storage.blob.models.StorageServiceProperties; import com.azure.storage.blob.models.StorageServiceStats; import com.azure.storage.blob.models.UserDelegationKey; +import com.azure.storage.common.credentials.SharedKeyCredential; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -233,4 +234,73 @@ public Mono> getAccountInfo() { .getAccountInfo() .map(rb -> new SimpleResponse<>(rb, new StorageAccountInfo(rb.deserializedHeaders()))); } + + /** + * Generates an account SAS token with the specified parameters + * + * @param accountSASService + * The {@code AccountSASService} services for the account SAS + * @param accountSASResourceType + * An optional {@code AccountSASResourceType} resources for the account SAS + * @param accountSASPermission + * The {@code AccountSASPermission} permission for the account SAS + * @param expiryTime + * The {@code OffsetDateTime} expiry time for the account SAS + * + * @return + * A string that represents the SAS token + */ + public String generateAccountSAS(AccountSASService accountSASService, AccountSASResourceType accountSASResourceType, + AccountSASPermission accountSASPermission, OffsetDateTime expiryTime) { + return this.generateAccountSAS(accountSASService, accountSASResourceType, accountSASPermission, expiryTime, + null /* startTime */, null /* version */, null /* ipRange */, null /* sasProtocol */); + } + + /** + * Generates an account SAS token with the specified parameters + * + * @param accountSASService + * The {@code AccountSASService} services for the account SAS + * @param accountSASResourceType + * An optional {@code AccountSASResourceType} resources for the account SAS + * @param accountSASPermission + * The {@code AccountSASPermission} permission for the account SAS + * @param expiryTime + * The {@code OffsetDateTime} expiry time for the account SAS + * @param startTime + * The {@code OffsetDateTime} start time for the account SAS + * @param version + * The {@code String} version for the account SAS + * @param ipRange + * An optional {@code IPRange} ip address range for the SAS + * @param sasProtocol + * An optional {@code SASProtocol} protocol for the SAS + * + * @return + * A string that represents the SAS token + */ + public String generateAccountSAS(AccountSASService accountSASService, AccountSASResourceType accountSASResourceType, + AccountSASPermission accountSASPermission, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, IPRange ipRange, + SASProtocol sasProtocol) { + + AccountSASSignatureValues accountSASSignatureValues = new AccountSASSignatureValues(); + accountSASSignatureValues.services(accountSASService == null ? null : accountSASService.toString()); + accountSASSignatureValues.resourceTypes(accountSASResourceType == null ? null : accountSASResourceType.toString()); + accountSASSignatureValues.permissions(accountSASPermission == null ? null : accountSASPermission.toString()); + accountSASSignatureValues.expiryTime(expiryTime); + accountSASSignatureValues.startTime(startTime); + + if (version != null) { + accountSASSignatureValues.version(version); + } + + accountSASSignatureValues.ipRange(ipRange); + accountSASSignatureValues.protocol(sasProtocol); + + SharedKeyCredential sharedKeyCredential = Utility.getSharedKeyCredential(this.storageAsyncRawClient.azureBlobStorage.httpPipeline()); + + SASQueryParameters sasQueryParameters = accountSASSignatureValues.generateSASQueryParameters(sharedKeyCredential); + + return sasQueryParameters.encode(); + } } diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClient.java index f18cf0640fbd9..c895cdda58bbc 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClient.java @@ -290,4 +290,53 @@ public Response getAccountInfo(Duration timeout) { return Utility.blockWithOptionalTimeout(response, timeout); } + + /** + * Generates an account SAS token with the specified parameters + * + * @param accountSASService + * The {@code AccountSASService} services for the account SAS + * @param accountSASResourceType + * An optional {@code AccountSASResourceType} resources for the account SAS + * @param accountSASPermission + * The {@code AccountSASPermission} permission for the account SAS + * @param expiryTime + * The {@code OffsetDateTime} expiry time for the account SAS + * + * @return + * A string that represents the SAS token + */ + public String generateAccountSAS(AccountSASService accountSASService, AccountSASResourceType accountSASResourceType, + AccountSASPermission accountSASPermission, OffsetDateTime expiryTime) { + return this.storageAsyncClient.generateAccountSAS(accountSASService, accountSASResourceType, accountSASPermission, expiryTime); + } + + /** + * Generates an account SAS token with the specified parameters + * + * @param accountSASService + * The {@code AccountSASService} services for the account SAS + * @param accountSASResourceType + * An optional {@code AccountSASResourceType} resources for the account SAS + * @param accountSASPermission + * The {@code AccountSASPermission} permission for the account SAS + * @param expiryTime + * The {@code OffsetDateTime} expiry time for the account SAS + * @param startTime + * The {@code OffsetDateTime} start time for the account SAS + * @param version + * The {@code String} version for the account SAS + * @param ipRange + * An optional {@code IPRange} ip address range for the SAS + * @param sasProtocol + * An optional {@code SASProtocol} protocol for the SAS + * + * @return + * A string that represents the SAS token + */ + public String generateAccountSAS(AccountSASService accountSASService, AccountSASResourceType accountSASResourceType, + AccountSASPermission accountSASPermission, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, IPRange ipRange, + SASProtocol sasProtocol) { + return this.storageAsyncClient.generateAccountSAS(accountSASService, accountSASResourceType, accountSASPermission, expiryTime, startTime, version, ipRange, sasProtocol); + } } diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/Utility.java b/storage/client/blob/src/main/java/com/azure/storage/blob/Utility.java index 3b5d073c4023e..252a5e83bbaf2 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/Utility.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/Utility.java @@ -5,9 +5,13 @@ import com.azure.core.http.HttpHeader; import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.policy.HttpPipelinePolicy; import com.azure.core.implementation.http.UrlBuilder; import com.azure.storage.blob.models.StorageErrorException; import com.azure.storage.blob.models.UserDelegationKey; +import com.azure.storage.common.credentials.SharedKeyCredential; +import com.azure.storage.common.policy.SharedKeyCredentialPolicy; import reactor.core.publisher.Mono; import reactor.util.annotation.Nullable; @@ -387,4 +391,23 @@ static T blockWithOptionalTimeout(Mono response, @Nullable Duration timeo return response.block(timeout); } } + + /** + * Gets the SharedKeyCredential from the HttpPipeline + * + * @param httpPipeline + * The {@code HttpPipeline} httpPipeline from which a sharedKeyCredential will be extracted + * + * @return The {@code SharedKeyCredential} sharedKeyCredential in the httpPipeline + */ + static SharedKeyCredential getSharedKeyCredential(HttpPipeline httpPipeline) { + for (int i = 0; i < httpPipeline.getPolicyCount(); i++) { + HttpPipelinePolicy httpPipelinePolicy = httpPipeline.getPolicy(i); + if (httpPipelinePolicy instanceof SharedKeyCredentialPolicy) { + SharedKeyCredentialPolicy sharedKeyCredentialPolicy = (SharedKeyCredentialPolicy) httpPipelinePolicy; + return sharedKeyCredentialPolicy.sharedKeyCredential(); + } + } + return null; + } } diff --git a/storage/client/blob/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java b/storage/client/blob/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java index fe93273e3f64e..4dce1c831ce21 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java +++ b/storage/client/blob/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java @@ -18,12 +18,27 @@ public final class SASTokenCredential { private static final String SIGNED_PERMISSIONS = "sp"; private static final String SIGNED_EXPIRY = "se"; private static final String SIGNATURE = "sig"; + private static final String SIGNED_RESOURCE = "sr"; // Optional SAS token pieces private static final String SIGNED_START = "st"; private static final String SIGNED_PROTOCOL = "spr"; private static final String SIGNED_IP = "sip"; + private static final String CACHE_CONTROL = "rscc"; + private static final String CONTENT_DISPOSITION = "rscd"; + private static final String CONTENT_ENCODING = "rsce"; + private static final String CONTENT_LANGUAGE = "rscl"; + private static final String CONTENT_TYPE = "rsct"; + + // Possible User Delegation Key pieces + private static final String SIGNED_KEY_O_ID = "skoid"; + private static final String SIGNED_KEY_T_ID = "sktid"; + private static final String SIGNED_KEY_START = "skt"; + private static final String SIGNED_KEY_EXPIRY = "ske"; + private static final String SIGNED_KEY_SERVICE = "sks"; + private static final String SIGNED_KEY_VERSION = "skv"; + private final String sasToken; /** @@ -57,20 +72,34 @@ public static SASTokenCredential fromQuery(String query) { queryParams.put(key, queryParam); } - if (queryParams.size() < 6 - || !queryParams.containsKey(SIGNED_VERSION) - || !queryParams.containsKey(SIGNED_SERVICES) - || !queryParams.containsKey(SIGNED_RESOURCE_TYPES) - || !queryParams.containsKey(SIGNED_PERMISSIONS) - || !queryParams.containsKey(SIGNED_EXPIRY) - || !queryParams.containsKey(SIGNATURE)) { + /* Because ServiceSAS only requires expiry and permissions, both of which could be on the container + acl, the only guaranteed indication of a SAS is the signature. We'll let the service validate + the other query parameters. */ + if (!queryParams.containsKey(SIGNATURE)) { return null; } - StringBuilder sasTokenBuilder = new StringBuilder(queryParams.get(SIGNED_VERSION)) - .append("&").append(queryParams.get(SIGNED_SERVICES)) - .append("&").append(queryParams.get(SIGNED_RESOURCE_TYPES)) - .append("&").append(queryParams.get(SIGNED_PERMISSIONS)); + StringBuilder sasTokenBuilder = new StringBuilder(); + + if (queryParams.containsKey(SIGNED_VERSION)) { + sasTokenBuilder.append(queryParams.get(SIGNED_VERSION)); + } + + if (queryParams.containsKey(SIGNED_SERVICES)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_SERVICES)); + } + + if (queryParams.containsKey(SIGNED_RESOURCE_TYPES)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_RESOURCE_TYPES)); + } + + if (queryParams.containsKey(SIGNED_PERMISSIONS)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_PERMISSIONS)); + } + + if (queryParams.containsKey(SIGNED_RESOURCE)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_RESOURCE)); + } // SIGNED_START is optional if (queryParams.containsKey(SIGNED_START)) { @@ -89,6 +118,51 @@ public static SASTokenCredential fromQuery(String query) { sasTokenBuilder.append("&").append(queryParams.get(SIGNED_PROTOCOL)); } + if (queryParams.containsKey(CACHE_CONTROL)) { + sasTokenBuilder.append("&").append(queryParams.get(CACHE_CONTROL)); + } + + if (queryParams.containsKey(CONTENT_DISPOSITION)) { + sasTokenBuilder.append("&").append(queryParams.get(CONTENT_DISPOSITION)); + } + + if (queryParams.containsKey(CONTENT_ENCODING)) { + sasTokenBuilder.append("&").append(queryParams.get(CONTENT_ENCODING)); + } + + if (queryParams.containsKey(CONTENT_LANGUAGE)) { + sasTokenBuilder.append("&").append(queryParams.get(CONTENT_LANGUAGE)); + } + + if (queryParams.containsKey(CONTENT_TYPE)) { + sasTokenBuilder.append("&").append(queryParams.get(CONTENT_TYPE)); + } + + // User Delegation Key Parameters + if (queryParams.containsKey(SIGNED_KEY_O_ID)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_KEY_O_ID)); + } + + if (queryParams.containsKey(SIGNED_KEY_T_ID)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_KEY_T_ID)); + } + + if (queryParams.containsKey(SIGNED_KEY_START)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_KEY_START)); + } + + if (queryParams.containsKey(SIGNED_KEY_EXPIRY)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_KEY_EXPIRY)); + } + + if (queryParams.containsKey(SIGNED_KEY_SERVICE)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_KEY_SERVICE)); + } + + if (queryParams.containsKey(SIGNED_KEY_VERSION)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_KEY_VERSION)); + } + sasTokenBuilder.append("&").append(queryParams.get(SIGNATURE)); return new SASTokenCredential(sasTokenBuilder.toString()); diff --git a/storage/client/blob/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java b/storage/client/blob/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java index 8ee1284591dd2..743eae8f262e4 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java +++ b/storage/client/blob/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java @@ -24,6 +24,15 @@ public SharedKeyCredentialPolicy(SharedKeyCredential credential) { this.credential = credential; } + /** + * Gets the shared key credential linked to the policy. + * @return + * The {@link SharedKeyCredential} linked to the policy. + */ + public SharedKeyCredential sharedKeyCredential() { + return this.credential; + } + @Override public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { String authorizationValue = credential.generateAuthorizationHeader(context.httpRequest().url(), diff --git a/storage/client/blob/src/test/java/com/azure/storage/blob/SASTest.groovy b/storage/client/blob/src/test/java/com/azure/storage/blob/SASTest.groovy new file mode 100644 index 0000000000000..1ebf9860f2ac3 --- /dev/null +++ b/storage/client/blob/src/test/java/com/azure/storage/blob/SASTest.groovy @@ -0,0 +1,1079 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob + +import com.azure.storage.blob.models.AccessPolicy +import com.azure.storage.blob.models.BlobRange +import com.azure.storage.blob.models.SignedIdentifier +import com.azure.storage.blob.models.StorageErrorCode +import com.azure.storage.blob.models.UserDelegationKey +import com.azure.storage.common.credentials.SASTokenCredential +import com.azure.storage.common.credentials.SharedKeyCredential +import spock.lang.Unroll + +import java.time.LocalDateTime +import java.time.OffsetDateTime +import java.time.ZoneOffset + +class SASTest extends APISpec { + + def "responseError"() { + when: + cu.listBlobsFlat() + + then: + def e = thrown(StorageException) + e.errorCode() == StorageErrorCode.INVALID_QUERY_PARAMETER_VALUE + e.statusCode() == 400 + e.message().contains("Value for one of the query parameters specified in the request URI is invalid.") + e.getMessage().contains(" Date: Tue, 16 Jul 2019 10:48:17 -0700 Subject: [PATCH 2/8] Remove RawClients from Blobs (#4375) Removes RawClients from Storage Blobs --- .../storage/blob/AppendBlobAsyncClient.java | 47 +- .../blob/AppendBlobAsyncRawClient.java | 192 ---- .../azure/storage/blob/AppendBlobClient.java | 17 +- .../azure/storage/blob/BlobAsyncClient.java | 830 +++++++-------- .../storage/blob/BlobAsyncRawClient.java | 766 -------------- .../com/azure/storage/blob/BlobClient.java | 680 +++++-------- .../azure/storage/blob/BlobInputStream.java | 2 +- .../azure/storage/blob/BlobOutputStream.java | 4 +- .../com/azure/storage/blob/BlobURLParts.java | 8 +- .../storage/blob/BlockBlobAsyncClient.java | 50 +- .../storage/blob/BlockBlobAsyncRawClient.java | 364 ------- .../azure/storage/blob/BlockBlobClient.java | 14 +- .../storage/blob/ContainerAsyncClient.java | 955 +++++++++--------- .../storage/blob/ContainerAsyncRawClient.java | 708 ------------- .../azure/storage/blob/ContainerClient.java | 660 +++++------- .../storage/blob/ContainerRawClient.java | 652 ------------ .../storage/blob/PageBlobAsyncClient.java | 210 +++- .../storage/blob/PageBlobAsyncRawClient.java | 620 ------------ .../azure/storage/blob/PageBlobClient.java | 12 +- .../blob/ServiceSASSignatureValues.java | 111 +- .../storage/blob/StorageAsyncClient.java | 222 ++-- .../storage/blob/StorageAsyncRawClient.java | 172 ---- .../com/azure/storage/blob/StorageClient.java | 197 ++-- .../azure/storage/blob/StorageRawClient.java | 259 ----- .../credentials/SASTokenCredential.java | 2 + .../policy/SharedKeyCredentialPolicy.java | 5 +- .../java/com/azure/storage/blob/Sample.java | 6 +- 27 files changed, 1885 insertions(+), 5880 deletions(-) delete mode 100644 storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncRawClient.java delete mode 100644 storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncRawClient.java delete mode 100644 storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncRawClient.java delete mode 100644 storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncRawClient.java delete mode 100644 storage/client/blob/src/main/java/com/azure/storage/blob/ContainerRawClient.java delete mode 100644 storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobAsyncRawClient.java delete mode 100644 storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncRawClient.java delete mode 100644 storage/client/blob/src/main/java/com/azure/storage/blob/StorageRawClient.java diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncClient.java index 7b4585580e16f..60376a3d990ab 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncClient.java @@ -5,6 +5,7 @@ import com.azure.core.http.rest.Response; import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.util.Context; import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; import com.azure.storage.blob.models.AppendBlobAccessConditions; import com.azure.storage.blob.models.AppendBlobItem; @@ -13,12 +14,13 @@ import com.azure.storage.blob.models.BlobRange; import com.azure.storage.blob.models.Metadata; import com.azure.storage.blob.models.SourceModifiedAccessConditions; -import io.netty.buffer.Unpooled; +import io.netty.buffer.ByteBuf; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.net.URL; -import java.nio.ByteBuffer; + +import static com.azure.storage.blob.Utility.postProcessResponse; /** @@ -45,8 +47,6 @@ * object through {@link Mono#toFuture()}. */ public final class AppendBlobAsyncClient extends BlobAsyncClient { - final AppendBlobAsyncRawClient appendBlobAsyncRawClient; - /** * Indicates the maximum number of bytes that can be sent in a call to appendBlock. */ @@ -63,7 +63,6 @@ public final class AppendBlobAsyncClient extends BlobAsyncClient { */ AppendBlobAsyncClient(AzureBlobStorageBuilder azureBlobStorageBuilder, String snapshot) { super(azureBlobStorageBuilder, snapshot); - appendBlobAsyncRawClient = new AppendBlobAsyncRawClient(azureBlobStorageBuilder.build()); } /** @@ -90,8 +89,13 @@ public Mono> create() { * A reactive response containing the information of the created appended blob. */ public Mono> create(BlobHTTPHeaders headers, Metadata metadata, BlobAccessConditions accessConditions) { - return appendBlobAsyncRawClient - .create(headers, metadata, accessConditions) + metadata = (metadata == null) ? new Metadata() : metadata; + accessConditions = (accessConditions == null) ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.appendBlobs().createWithRestResponseAsync(null, + null, 0, null, metadata, null, null, + null, null, headers, accessConditions.leaseAccessConditions(), + accessConditions.modifiedAccessConditions(), Context.NONE)) .map(rb -> new SimpleResponse<>(rb, new AppendBlobItem(rb.deserializedHeaders()))); } @@ -111,7 +115,7 @@ public Mono> create(BlobHTTPHeaders headers, Metadata m * @return * A reactive response containing the information of the append blob operation. */ - public Mono> appendBlock(Flux data, long length) { + public Mono> appendBlock(Flux data, long length) { return this.appendBlock(data, length, null); } @@ -133,10 +137,17 @@ public Mono> appendBlock(Flux data, long le * @return * A reactive response containing the information of the append blob operation. */ - public Mono> appendBlock(Flux data, long length, - AppendBlobAccessConditions appendBlobAccessConditions) { - return appendBlobAsyncRawClient - .appendBlock(data.map(Unpooled::wrappedBuffer), length, appendBlobAccessConditions) + public Mono> appendBlock(Flux data, long length, + AppendBlobAccessConditions appendBlobAccessConditions) { + appendBlobAccessConditions = appendBlobAccessConditions == null ? new AppendBlobAccessConditions() + : appendBlobAccessConditions; + + return postProcessResponse(this.azureBlobStorage.appendBlobs().appendBlockWithRestResponseAsync( + null, null, data, length, null, null, + null, null, null, null, + appendBlobAccessConditions.leaseAccessConditions(), + appendBlobAccessConditions.appendPositionAccessConditions(), + appendBlobAccessConditions.modifiedAccessConditions(), Context.NONE)) .map(rb -> new SimpleResponse<>(rb, new AppendBlobItem(rb.deserializedHeaders()))); } @@ -183,8 +194,16 @@ public Mono> appendBlockFromUrl(URL sourceURL, BlobRang public Mono> appendBlockFromUrl(URL sourceURL, BlobRange sourceRange, byte[] sourceContentMD5, AppendBlobAccessConditions destAccessConditions, SourceModifiedAccessConditions sourceAccessConditions) { - return appendBlobAsyncRawClient - .appendBlockFromUrl(sourceURL, sourceRange, sourceContentMD5, destAccessConditions, sourceAccessConditions) + sourceRange = sourceRange == null ? new BlobRange(0) : sourceRange; + destAccessConditions = destAccessConditions == null + ? new AppendBlobAccessConditions() : destAccessConditions; + + return postProcessResponse( + this.azureBlobStorage.appendBlobs().appendBlockFromUrlWithRestResponseAsync(null, null, + sourceURL, 0, sourceRange.toString(), sourceContentMD5, null, null, + destAccessConditions.leaseAccessConditions(), + destAccessConditions.appendPositionAccessConditions(), + destAccessConditions.modifiedAccessConditions(), sourceAccessConditions, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, new AppendBlobItem(rb.deserializedHeaders()))); } } diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncRawClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncRawClient.java deleted file mode 100644 index 15bf8e09e4d1f..0000000000000 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncRawClient.java +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.storage.blob; - -import com.azure.core.util.Context; -import com.azure.storage.blob.implementation.AzureBlobStorageImpl; -import com.azure.storage.blob.models.AppendBlobAccessConditions; -import com.azure.storage.blob.models.AppendBlobsAppendBlockFromUrlResponse; -import com.azure.storage.blob.models.AppendBlobsAppendBlockResponse; -import com.azure.storage.blob.models.AppendBlobsCreateResponse; -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.Metadata; -import com.azure.storage.blob.models.SourceModifiedAccessConditions; -import io.netty.buffer.ByteBuf; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.net.URL; - -import static com.azure.storage.blob.Utility.postProcessResponse; - - -/** - * Represents a URL to an append blob. It may be obtained by direct construction or via the create method on a - * {@link ContainerAsyncClient} object. This class does not hold any state about a particular append blob but is instead a - * convenient way of sending off appropriate requests to the resource on the service. Please refer to the - * Azure Docs - */ -final class AppendBlobAsyncRawClient extends BlobAsyncRawClient { - - /** - * Indicates the maximum number of bytes that can be sent in a call to appendBlock. - */ - public static final int MAX_APPEND_BLOCK_BYTES = 4 * Constants.MB; - - /** - * Indicates the maximum number of blocks allowed in an append blob. - */ - public static final int MAX_BLOCKS = 50000; - - /** - * Creates a {@code AppendBlobAsyncRawClient} object pointing to the account specified by the URL and using the provided - * pipeline to make HTTP requests. - */ - AppendBlobAsyncRawClient(AzureBlobStorageImpl azureBlobStorage) { - super(azureBlobStorage, null); - } - - /** - * Creates a 0-length append blob. Call AppendBlock to append data to an append blob. For more information, see - * the Azure Docs. - * - * @return Emits the successful response. - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=append_blob "Sample code for AppendBlobAsyncRawClient.create")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono create() { - return this.create(null, null, null); - } - - /** - * Creates a 0-length append blob. Call AppendBlock to append data to an append blob. For more information, see - * the Azure Docs. - * - * @param headers {@link BlobHTTPHeaders} - * @param metadata {@link Metadata} - * @param accessConditions {@link BlobAccessConditions} - * @return Emits the successful response. - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=append_blob "Sample code for AppendBlobAsyncRawClient.create")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono create(BlobHTTPHeaders headers, Metadata metadata, - BlobAccessConditions accessConditions) { - metadata = metadata == null ? new Metadata() : metadata; - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - return postProcessResponse(this.azureBlobStorage.appendBlobs().createWithRestResponseAsync(null, - null, 0, null, metadata, null, null, - null, null, headers, accessConditions.leaseAccessConditions(), - accessConditions.modifiedAccessConditions(), Context.NONE)); - } - - /** - * Commits a new block of data to the end of the existing append blob. For more information, see the - * 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. - * - * @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 Flowable must produce the same data each time it is subscribed to. - * @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 Emits the successful response. - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=append_blob "Sample code for AppendBlobAsyncRawClient.appendBlock")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono appendBlock(Flux data, long length) { - return this.appendBlock(data, length, null); - } - - /** - * Commits a new block of data to the end of the existing append blob. For more information, see the - * 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. - * - * @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 Flowable must produce the same data each time it is subscribed to. - * @param length The exact length of the data. It is important that this value match precisely the length of the data - * emitted by the {@code Flux}. - * @param appendBlobAccessConditions {@link AppendBlobAccessConditions} - * @return Emits the successful response. - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=append_blob "Sample code for AppendBlobAsyncRawClient.appendBlock")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono appendBlock(Flux data, long length, - AppendBlobAccessConditions appendBlobAccessConditions) { - appendBlobAccessConditions = appendBlobAccessConditions == null ? new AppendBlobAccessConditions() - : appendBlobAccessConditions; - - return postProcessResponse(this.azureBlobStorage.appendBlobs().appendBlockWithRestResponseAsync( - null, null, data, length, null, null, - null, null, null, null, - appendBlobAccessConditions.leaseAccessConditions(), - appendBlobAccessConditions.appendPositionAccessConditions(), - appendBlobAccessConditions.modifiedAccessConditions(), Context.NONE)); - } - - /** - * Commits a new block of data from another blob to the end of this append blob. For more information, see the - * Azure Docs. - *

- * - * @param sourceURL The url to the blob that will be the source of the copy. A source blob in the same storage account can - * be authenticated via Shared Key. However, if the source is a blob in another account, the source blob - * must either be public or must be authenticated via a shared access signature. If the source blob is - * public, no authentication is required to perform the operation. - * @param sourceRange The source {@link BlobRange} to copy. - * @return Emits the successful response. - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=append_from_url "Sample code for AppendBlobAsyncRawClient.appendBlockFromUrl")] - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono appendBlockFromUrl(URL sourceURL, BlobRange sourceRange) { - return this.appendBlockFromUrl(sourceURL, sourceRange, null, null, - null); - } - - /** - * Commits a new block of data from another blob to the end of this append blob. For more information, see the - * Azure Docs. - *

- * - * @param sourceURL The url to the blob that will be the source of the copy. A source blob in the same storage account can - * be authenticated via Shared Key. However, if the source is a blob in another account, the source blob - * must either be public or must be authenticated via a shared access signature. If the source blob is - * public, no authentication is required to perform the operation. - * @param sourceRange {@link BlobRange} - * @param sourceContentMD5 An MD5 hash of the block content from the source blob. If specified, the service will calculate the MD5 - * of the received data and fail the request if it does not match the provided MD5. - * @param destAccessConditions {@link AppendBlobAccessConditions} - * @param sourceAccessConditions {@link SourceModifiedAccessConditions} - * @return Emits the successful response. - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=append_from_url "Sample code for AppendBlobAsyncRawClient.appendBlockFromUrl")] - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono appendBlockFromUrl(URL sourceURL, BlobRange sourceRange, - byte[] sourceContentMD5, AppendBlobAccessConditions destAccessConditions, - SourceModifiedAccessConditions sourceAccessConditions) { - - sourceRange = sourceRange == null ? new BlobRange(0) : sourceRange; - destAccessConditions = destAccessConditions == null - ? new AppendBlobAccessConditions() : destAccessConditions; - - return postProcessResponse( - this.azureBlobStorage.appendBlobs().appendBlockFromUrlWithRestResponseAsync(null, null, - sourceURL, 0, sourceRange.toString(), sourceContentMD5, null, null, - destAccessConditions.leaseAccessConditions(), - destAccessConditions.appendPositionAccessConditions(), - destAccessConditions.modifiedAccessConditions(), sourceAccessConditions, Context.NONE)); - } -} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobClient.java index 47a379649659f..6be2bf7f4e5aa 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobClient.java @@ -11,13 +11,14 @@ import com.azure.storage.blob.models.BlobRange; import com.azure.storage.blob.models.Metadata; import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; import java.io.InputStream; import java.net.URL; -import java.nio.ByteBuffer; import java.time.Duration; @@ -37,18 +38,17 @@ * for more information. */ public final class AppendBlobClient extends BlobClient { - - AppendBlobAsyncClient appendBlobAsyncClient; + private AppendBlobAsyncClient appendBlobAsyncClient; /** * Indicates the maximum number of bytes that can be sent in a call to appendBlock. */ - public static final int MAX_APPEND_BLOCK_BYTES = 4 * Constants.MB; + public static final int MAX_APPEND_BLOCK_BYTES = AppendBlobAsyncClient.MAX_APPEND_BLOCK_BYTES; /** * Indicates the maximum number of blocks allowed in an append blob. */ - public static final int MAX_BLOCKS = 50000; + public static final int MAX_BLOCKS = AppendBlobAsyncClient.MAX_BLOCKS; /** * Package-private constructor for use by {@link AppendBlobClientBuilder}. @@ -58,7 +58,7 @@ public final class AppendBlobClient extends BlobClient { super(appendBlobAsyncClient); this.appendBlobAsyncClient = appendBlobAsyncClient; } - + /** * Creates and opens an output stream to write data to the append blob. If the blob already exists on the service, * it will be overwritten. @@ -160,7 +160,7 @@ public Response appendBlock(InputStream data, long length) { */ public Response appendBlock(InputStream data, long length, AppendBlobAccessConditions appendBlobAccessConditions, Duration timeout) { - Flux fbb = Flux.range(0, (int) Math.ceil((double) length / (double) MAX_APPEND_BLOCK_BYTES)) + Flux fbb = Flux.range(0, (int) Math.ceil((double) length / (double) MAX_APPEND_BLOCK_BYTES)) .map(i -> i * MAX_APPEND_BLOCK_BYTES) .concatMap(pos -> Mono.fromCallable(() -> { long count = pos + MAX_APPEND_BLOCK_BYTES > length ? length - pos : MAX_APPEND_BLOCK_BYTES; @@ -169,7 +169,8 @@ public Response appendBlock(InputStream data, long length, while (read < count) { read += data.read(cache, read, (int) count - read); } - return ByteBuffer.wrap(cache); + + return ByteBufAllocator.DEFAULT.buffer((int) count).writeBytes(cache); })); Mono> response = appendBlobAsyncClient.appendBlock(fbb.subscribeOn(Schedulers.elastic()), length, appendBlobAccessConditions); diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java index 5042f9e782af5..2601107aaa0b6 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java @@ -9,7 +9,9 @@ import com.azure.core.http.rest.VoidResponse; import com.azure.core.implementation.http.UrlBuilder; import com.azure.core.implementation.util.FluxUtil; +import com.azure.core.util.Context; 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; @@ -20,6 +22,7 @@ import com.azure.storage.blob.models.Metadata; import com.azure.storage.blob.models.ModifiedAccessConditions; 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.UserDelegationKey; import com.azure.storage.common.credentials.SharedKeyCredential; @@ -41,82 +44,89 @@ import java.util.ArrayList; import java.util.List; +import static com.azure.storage.blob.Utility.postProcessResponse; + /** - * 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. + * 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 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()}. + * client can be converted into one of these clients easily through the methods {@link #asBlockBlobAsyncClient}, {@link + * #asPageBlobAsyncClient}, and {@link #asAppendBlobAsyncClient()}. * *

* 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 StorageAsyncClient}. * *

- * Please refer to the Azure Docs - * for more information. + * 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()}. + * 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()}. */ 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; - final BlobAsyncRawClient blobAsyncRawClient; + protected final AzureBlobStorageImpl azureBlobStorage; + protected final String snapshot; /** * Package-private constructor for use by {@link BlobClientBuilder}. + * * @param azureBlobStorageBuilder the API client builder for blob storage API */ BlobAsyncClient(AzureBlobStorageBuilder azureBlobStorageBuilder, String snapshot) { - this.blobAsyncRawClient = new BlobAsyncRawClient(azureBlobStorageBuilder.build(), snapshot); + this.azureBlobStorage = azureBlobStorageBuilder.build(); + this.snapshot = snapshot; } /** * 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. + * @return A {@link BlockBlobAsyncClient} to this resource. */ public BlockBlobAsyncClient asBlockBlobAsyncClient() { - return new BlockBlobAsyncClient(new AzureBlobStorageBuilder().url(getBlobUrl().toString()).pipeline(blobAsyncRawClient.azureBlobStorage.httpPipeline()), blobAsyncRawClient.snapshot); + return new BlockBlobAsyncClient(new AzureBlobStorageBuilder() + .url(getBlobUrl().toString()) + .pipeline(azureBlobStorage.httpPipeline()), snapshot); } /** * 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. + * @return A {@link AppendBlobAsyncClient} to this resource. */ public AppendBlobAsyncClient asAppendBlobAsyncClient() { - return new AppendBlobAsyncClient(new AzureBlobStorageBuilder().url(getBlobUrl().toString()).pipeline(blobAsyncRawClient.azureBlobStorage.httpPipeline()), blobAsyncRawClient.snapshot); + return new AppendBlobAsyncClient(new AzureBlobStorageBuilder() + .url(getBlobUrl().toString()) + .pipeline(azureBlobStorage.httpPipeline()), snapshot); } /** * 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. + * @return A {@link PageBlobAsyncClient} to this resource. */ public PageBlobAsyncClient asPageBlobAsyncClient() { - return new PageBlobAsyncClient(new AzureBlobStorageBuilder().url(getBlobUrl().toString()).pipeline(blobAsyncRawClient.azureBlobStorage.httpPipeline()), blobAsyncRawClient.snapshot); + return new PageBlobAsyncClient(new AzureBlobStorageBuilder() + .url(getBlobUrl().toString()) + .pipeline(azureBlobStorage.httpPipeline()), snapshot); } /** - * Initializes a {@link ContainerAsyncClient} 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 + * Initializes a {@link ContainerAsyncClient} 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 ContainerAsyncClient} object pointing to the container containing the blob @@ -125,31 +135,31 @@ public ContainerAsyncClient getContainerAsyncClient() { BlobURLParts parts = URLParser.parse(getBlobUrl()); return new ContainerAsyncClient(new AzureBlobStorageBuilder() .url(String.format("%s://%s/%s", parts.scheme(), parts.host(), parts.containerName())) - .pipeline(blobAsyncRawClient.azureBlobStorage.httpPipeline())); + .pipeline(azureBlobStorage.httpPipeline())); } /** * 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(blobAsyncRawClient.azureBlobStorage.url()); - if (blobAsyncRawClient.snapshot != null) { - urlBuilder.query("snapshot=" + blobAsyncRawClient.snapshot); + UrlBuilder urlBuilder = UrlBuilder.parse(azureBlobStorage.url()); + if (snapshot != null) { + urlBuilder.query("snapshot=" + snapshot); } return urlBuilder.toURL(); } catch (MalformedURLException e) { - throw new RuntimeException(String.format("Invalid URL on %s: %s" + getClass().getSimpleName(), blobAsyncRawClient.azureBlobStorage.url()), e); + throw new RuntimeException(String.format("Invalid URL on %s: %s" + getClass().getSimpleName(), azureBlobStorage.url()), e); } } /** * Gets if the blob this client represents exists in the cloud. * - * @return - * true if the blob exists, false if it doesn't + * @return true if the blob exists, false if it doesn't */ public Mono> exists() { return this.getProperties() @@ -164,11 +174,8 @@ public Mono> exists() { * Copies the data at the source URL to a blob. 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. + * @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 this.startCopyFromURL(sourceURL, null, null, null); @@ -178,37 +185,41 @@ public Mono> startCopyFromURL(URL sourceURL) { * Copies the data at the source URL to a blob. 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 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. + * @param sourceURL The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * @param metadata {@link Metadata} + * @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> startCopyFromURL(URL sourceURL, Metadata metadata, - ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions) { - return blobAsyncRawClient - .startCopyFromURL(sourceURL, metadata, sourceModifiedAccessConditions, destAccessConditions) + ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions) { + 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() + .sourceIfModifiedSince(sourceModifiedAccessConditions.ifModifiedSince()) + .sourceIfUnmodifiedSince(sourceModifiedAccessConditions.ifUnmodifiedSince()) + .sourceIfMatch(sourceModifiedAccessConditions.ifMatch()) + .sourceIfNoneMatch(sourceModifiedAccessConditions.ifNoneMatch()); + + return postProcessResponse(this.azureBlobStorage.blobs().startCopyFromURLWithRestResponseAsync( + null, null, sourceURL, null, metadata, null, sourceConditions, + destAccessConditions.modifiedAccessConditions(), destAccessConditions.leaseAccessConditions(), Context.NONE)) .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().copyId())); } /** * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. * - * @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. + * @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 this.abortCopyFromURL(copyId, null); @@ -217,30 +228,23 @@ public Mono abortCopyFromURL(String copyId) { /** * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. * - * @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. + * @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 abortCopyFromURL(String copyId, LeaseAccessConditions leaseAccessConditions) { - return blobAsyncRawClient - .abortCopyFromURL(copyId, leaseAccessConditions) + return postProcessResponse(this.azureBlobStorage.blobs().abortCopyFromURLWithRestResponseAsync( + null, null, copyId, null, null, leaseAccessConditions, Context.NONE)) .map(VoidResponse::new); } /** * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. * - * @param copySource - * The source URL to copy from. - * - * @return - * A reactive response containing the copy ID for the long running operation. + * @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 this.copyFromURL(copySource, null, null, null); @@ -249,63 +253,110 @@ public Mono> copyFromURL(URL copySource) { /** * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. * - * @param copySource - * The source URL to copy from. URLs outside of Azure may only be copied to block blobs. - * @param metadata - * {@link Metadata} - * @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. + * @param copySource The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * @param metadata {@link Metadata} + * @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> copyFromURL(URL copySource, Metadata metadata, - ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions) { - return blobAsyncRawClient - .syncCopyFromURL(copySource, metadata, sourceModifiedAccessConditions, destAccessConditions) + ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions) { + 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() + .sourceIfModifiedSince(sourceModifiedAccessConditions.ifModifiedSince()) + .sourceIfUnmodifiedSince(sourceModifiedAccessConditions.ifUnmodifiedSince()) + .sourceIfMatch(sourceModifiedAccessConditions.ifMatch()) + .sourceIfNoneMatch(sourceModifiedAccessConditions.ifNoneMatch()); + + return postProcessResponse(this.azureBlobStorage.blobs().copyFromURLWithRestResponseAsync( + null, null, copySource, null, metadata, null, sourceConditions, + destAccessConditions.modifiedAccessConditions(), destAccessConditions.leaseAccessConditions(), Context.NONE)) .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().copyId())); } /** - * Reads the entire blob. Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient}. + * Reads the entire blob. Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or + * {@link AppendBlobClient}. * - * @return - * A reactive response containing the blob data. + * @return A reactive response containing the blob data. */ public Mono>> download() { return this.download(null, null, false, null); } /** - * Reads a range of bytes from a blob. Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient}. + * Reads a range of bytes from a blob. Uploading data must be done from the {@link BlockBlobClient}, {@link + * PageBlobClient}, or {@link AppendBlobClient}. * - * @param range - * {@link BlobRange} - * @param accessConditions - * {@link BlobAccessConditions} - * @param rangeGetContentMD5 - * Whether the contentMD5 for the specified blob range should be returned. + * @param range {@link BlobRange} + * @param accessConditions {@link BlobAccessConditions} + * @param rangeGetContentMD5 Whether the contentMD5 for the specified blob range should be returned. * @param options {@link ReliableDownloadOptions} - * * @return A reactive response containing the blob data. */ public Mono>> download(BlobRange range, BlobAccessConditions accessConditions, - boolean rangeGetContentMD5, ReliableDownloadOptions options) { - return blobAsyncRawClient - .download(range, accessConditions, rangeGetContentMD5) + boolean rangeGetContentMD5, ReliableDownloadOptions options) { + return this.download(range, accessConditions, rangeGetContentMD5) .map(response -> new SimpleResponse<>( response.rawResponse(), response.body(options).map(ByteBuf::nioBuffer).switchIfEmpty(Flux.just(ByteBuffer.allocate(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. + * @apiNote ## Sample Code \n [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=upload_download + * "Sample code for BlobAsyncClient.download")] \n For more samples, please see the [Samples + * file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + Mono download(BlobRange range, BlobAccessConditions accessConditions, boolean rangeGetContentMD5) { + range = range == null ? new BlobRange(0) : range; + Boolean getMD5 = rangeGetContentMD5 ? rangeGetContentMD5 : null; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + HTTPGetterInfo info = new HTTPGetterInfo() + .offset(range.offset()) + .count(range.count()) + .eTag(accessConditions.modifiedAccessConditions().ifMatch()); + + // TODO: range is BlobRange but expected as String + // TODO: figure out correct response + return postProcessResponse(this.azureBlobStorage.blobs().downloadWithRestResponseAsync( + null, null, snapshot, null, null, range.toHeaderValue(), getMD5, + null, null, null, null, + accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)) + // 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.eTag(response.deserializedHeaders().eTag()); + 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.offset(), newInfo.count()), + new BlobAccessConditions().modifiedAccessConditions( + new ModifiedAccessConditions().ifMatch(info.eTag())), false)); + }); + } + /** * Downloads the entire blob into a file specified by the path. The file will be created if it doesn't exist. - * Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient}. + * 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, * use the other overload providing the {@link BlobRange} parameter. @@ -319,21 +370,17 @@ public Mono downloadToFile(String filePath) { /** * Downloads a range of bytes blob into a file specified by the path. The file will be created if it doesn't exist. - * Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient}. + * 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. * - * @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 accessConditions - * {@link BlobAccessConditions} - * @param rangeGetContentMD5 - * Whether the contentMD5 for the specified blob range should be returned. + * @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 accessConditions {@link BlobAccessConditions} + * @param rangeGetContentMD5 Whether the contentMD5 for the specified blob range should be returned. * @param options {@link ReliableDownloadOptions} * @return An empty response * @throws IllegalArgumentException If {@code blockSize} is less than 0 or greater than 100MB. @@ -349,8 +396,7 @@ public Mono downloadToFile(String filePath, BlobRange range, Integer block channel -> Mono.justOrEmpty(range) .switchIfEmpty(getFullBlobRange(accessConditions)) .flatMapMany(rg -> Flux.fromIterable(sliceBlobRange(rg, blockSize))) - .flatMap(chunk -> blobAsyncRawClient - .download(chunk, accessConditions, rangeGetContentMD5) + .flatMap(chunk -> this.download(chunk, accessConditions, rangeGetContentMD5) .subscribeOn(Schedulers.elastic()) .flatMap(dar -> FluxUtil.bytebufStreamToFile(dar.body(options), channel, chunk.offset() - (range == null ? 0 : range.offset())))) .then(), this::downloadToFileCleanup); @@ -396,8 +442,7 @@ private List sliceBlobRange(BlobRange blobRange, Integer blockSize) { /** * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. * - * @return - * A reactive response signalling completion. + * @return A reactive response signalling completion. */ public Mono delete() { return this.delete(null, null); @@ -406,28 +451,27 @@ public Mono delete() { /** * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. * - * @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. + * @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 delete(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, - BlobAccessConditions accessConditions) { - return blobAsyncRawClient - .delete(deleteBlobSnapshotOptions, accessConditions) + BlobAccessConditions accessConditions) { + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blobs().deleteWithRestResponseAsync( + null, null, snapshot, null, null, deleteBlobSnapshotOptions, + null, accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), + Context.NONE)) .map(VoidResponse::new); } /** * Returns the blob's metadata and properties. * - * @return - * A reactive response containing the blob properties and metadata. + * @return A reactive response containing the blob properties and metadata. */ public Mono> getProperties() { return this.getProperties(null); @@ -436,93 +480,87 @@ public Mono> getProperties() { /** * Returns the blob's metadata and properties. * - * @param accessConditions - * {@link BlobAccessConditions} - * - * @return - * A reactive response containing the blob properties and metadata. + * @param accessConditions {@link BlobAccessConditions} + * @return A reactive response containing the blob properties and metadata. */ public Mono> getProperties(BlobAccessConditions accessConditions) { - return blobAsyncRawClient - .getProperties(accessConditions) + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blobs().getPropertiesWithRestResponseAsync( + null, null, snapshot, null, null, null, + null, null, null, accessConditions.leaseAccessConditions(), + accessConditions.modifiedAccessConditions(), Context.NONE)) .map(rb -> new SimpleResponse<>(rb, new BlobProperties(rb.deserializedHeaders()))); } /** - * 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. For more information, see the + * 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. For more information, + * see the * Azure Docs. * - * @param headers - * {@link BlobHTTPHeaders} - * - * @return - * A reactive response signalling completion. + * @param headers {@link BlobHTTPHeaders} + * @return A reactive response signalling completion. */ public Mono setHTTPHeaders(BlobHTTPHeaders headers) { return this.setHTTPHeaders(headers, null); } /** - * 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. For more information, see the + * 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. For more information, + * see the * Azure Docs. * - * @param headers - * {@link BlobHTTPHeaders} - * @param accessConditions - * {@link BlobAccessConditions} - * - * @return - * A reactive response signalling completion. + * @param headers {@link BlobHTTPHeaders} + * @param accessConditions {@link BlobAccessConditions} + * @return A reactive response signalling completion. */ public Mono setHTTPHeaders(BlobHTTPHeaders headers, BlobAccessConditions accessConditions) { - return blobAsyncRawClient - .setHTTPHeaders(headers, accessConditions) + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blobs().setHTTPHeadersWithRestResponseAsync( + null, null, null, null, headers, + accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)) .map(VoidResponse::new); } /** - * 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. For more information, see the Azure Docs. - * - * @param metadata - * {@link Metadata} + * 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. For more information, see the + * Azure Docs. * - * @return - * A reactive response signalling completion. + * @param metadata {@link Metadata} + * @return A reactive response signalling completion. */ public Mono setMetadata(Metadata metadata) { return this.setMetadata(metadata, 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. For more information, see the Azure Docs. - * - * @param metadata - * {@link Metadata} - * @param accessConditions - * {@link BlobAccessConditions} + * 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. For more information, see the + * Azure Docs. * - * @return - * A reactive response signalling completion. + * @param metadata {@link Metadata} + * @param accessConditions {@link BlobAccessConditions} + * @return A reactive response signalling completion. */ public Mono setMetadata(Metadata metadata, BlobAccessConditions accessConditions) { - return blobAsyncRawClient - .setMetadata(metadata, accessConditions) + metadata = metadata == null ? new Metadata() : metadata; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blobs().setMetadataWithRestResponseAsync( + null, null, null, metadata, null, null, + null, null, accessConditions.leaseAccessConditions(), + accessConditions.modifiedAccessConditions(), Context.NONE)) .map(VoidResponse::new); } /** * Creates a read-only snapshot of a blob. * - * @return - * A reactive response containing the ID of the new snapshot. + * @return A reactive response containing the ID of the new snapshot. */ public Mono> createSnapshot() { return this.createSnapshot(null, null); @@ -531,30 +569,29 @@ public Mono> createSnapshot() { /** * Creates a read-only snapshot of a blob. * - * @param metadata - * {@link Metadata} - * @param accessConditions - * {@link BlobAccessConditions} - * - * @return - * A reactive response containing the ID of the new snapshot. + * @param metadata {@link Metadata} + * @param accessConditions {@link BlobAccessConditions} + * @return A reactive response containing the ID of the new snapshot. */ public Mono> createSnapshot(Metadata metadata, BlobAccessConditions accessConditions) { - return blobAsyncRawClient - .createSnapshot(metadata, accessConditions) + metadata = metadata == null ? new Metadata() : metadata; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blobs().createSnapshotWithRestResponseAsync( + null, null, null, metadata, null, null, + null, null, accessConditions.modifiedAccessConditions(), + accessConditions.leaseAccessConditions(), Context.NONE)) .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().snapshot())); } /** * 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. - * - * @param tier - * The new tier for the blob. + * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's + * etag. * - * @return - * A reactive response signalling completion. + * @param tier The new tier for the blob. + * @return A reactive response signalling completion. */ public Mono setTier(AccessTier tier) { return this.setTier(tier, null); @@ -563,32 +600,30 @@ public Mono setTier(AccessTier tier) { /** * 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. + * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's + * etag. * - * @param tier - * The new tier for the blob. - * @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. + * @param tier The new tier for the blob. + * @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 setTier(AccessTier tier, LeaseAccessConditions leaseAccessConditions) { - return blobAsyncRawClient - .setTier(tier, leaseAccessConditions) + Utility.assertNotNull("tier", tier); + + return postProcessResponse(this.azureBlobStorage.blobs().setTierWithRestResponseAsync( + null, null, tier, null, null, leaseAccessConditions, Context.NONE)) .map(VoidResponse::new); } /** * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots. * - * @return - * A reactive response signalling completion. + * @return A reactive response signalling completion. */ public Mono undelete() { - return blobAsyncRawClient - .undelete() + return postProcessResponse(this.azureBlobStorage.blobs().undeleteWithRestResponseAsync(null, + null, Context.NONE)) .map(VoidResponse::new); } @@ -596,14 +631,10 @@ public Mono undelete() { * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 * seconds, or infinite (-1). * - * @param proposedId - * A {@code String} in any valid GUID format. May be null. - * @param duration - * The duration of the lease, in seconds, or negative one (-1) for a lease that - * never expires. A non-infinite lease can be between 15 and 60 seconds. - * - * @return - * A reactive response containing the lease ID. + * @param proposedId A {@code String} in any valid GUID format. May be null. + * @param duration The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A + * non-infinite lease can be between 15 and 60 seconds. + * @return A reactive response containing the lease ID. */ public Mono> acquireLease(String proposedId, int duration) { return this.acquireLease(proposedId, duration, null); @@ -613,33 +644,33 @@ public Mono> acquireLease(String proposedId, int duration) { * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 * seconds, or infinite (-1). * - * @param proposedID - * A {@code String} in any valid GUID format. May be null. - * @param duration - * The duration of the lease, in seconds, or negative one (-1) for a lease that - * never expires. A non-infinite lease can be between 15 and 60 seconds. - * @param modifiedAccessConditions - * 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. - * - * @return - * A reactive response containing the lease ID. + * @param proposedID A {@code String} in any valid GUID format. May be null. + * @param duration The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A + * non-infinite lease can be between 15 and 60 seconds. + * @param modifiedAccessConditions 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. + * @return A reactive response containing the lease ID. + * @throws IllegalArgumentException If {@code duration} is outside the bounds of 15 to 60 or isn't -1. */ public Mono> acquireLease(String proposedID, int duration, ModifiedAccessConditions modifiedAccessConditions) { - return blobAsyncRawClient - .acquireLease(proposedID, duration, modifiedAccessConditions) + if (!(duration == -1 || (duration >= 15 && duration <= 60))) { + // Throwing is preferred to Mono.error because this will error out immediately instead of waiting until + // subscription. + throw new IllegalArgumentException("Duration must be -1 or between 15 and 60."); + } + + return postProcessResponse(this.azureBlobStorage.blobs().acquireLeaseWithRestResponseAsync( + null, null, null, duration, proposedID, null, + modifiedAccessConditions, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseId())); } /** * Renews the blob's previously-acquired lease. * - * @param leaseID - * The leaseId of the active lease on the blob. - * - * @return - * A reactive response containing the renewed lease ID. + * @param leaseID The leaseId of the active lease on the blob. + * @return A reactive response containing the renewed lease ID. */ public Mono> renewLease(String leaseID) { return this.renewLease(leaseID, null); @@ -648,30 +679,23 @@ public Mono> renewLease(String leaseID) { /** * Renews the blob's previously-acquired lease. * - * @param leaseID - * The leaseId of the active lease on the blob. - * @param modifiedAccessConditions - * 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. - * - * @return - * A reactive response containing the renewed lease ID. + * @param leaseID The leaseId of the active lease on the blob. + * @param modifiedAccessConditions 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. + * @return A reactive response containing the renewed lease ID. */ public Mono> renewLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions) { - return blobAsyncRawClient - .renewLease(leaseID, modifiedAccessConditions) + return postProcessResponse(this.azureBlobStorage.blobs().renewLeaseWithRestResponseAsync(null, + null, leaseID, null, null, modifiedAccessConditions, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseId())); } /** * Releases the blob's previously-acquired lease. * - * @param leaseID - * The leaseId of the active lease on the blob. - * - * @return - * A reactive response signalling completion. + * @param leaseID The leaseId of the active lease on the blob. + * @return A reactive response signalling completion. */ public Mono releaseLease(String leaseID) { return this.releaseLease(leaseID, null); @@ -680,19 +704,15 @@ public Mono releaseLease(String leaseID) { /** * Releases the blob's previously-acquired lease. * - * @param leaseID - * The leaseId of the active lease on the blob. - * @param modifiedAccessConditions - * 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. - * - * @return - * A reactive response signalling completion. + * @param leaseID The leaseId of the active lease on the blob. + * @param modifiedAccessConditions 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. + * @return A reactive response signalling completion. */ public Mono releaseLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions) { - return blobAsyncRawClient - .releaseLease(leaseID, modifiedAccessConditions) + return postProcessResponse(this.azureBlobStorage.blobs().releaseLeaseWithRestResponseAsync(null, + null, leaseID, null, null, modifiedAccessConditions, Context.NONE)) .map(VoidResponse::new); } @@ -700,8 +720,7 @@ public Mono releaseLease(String leaseID, ModifiedAccessConditions * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant * to break a fixed-duration lease when it expires or an infinite lease immediately. * - * @return - * A reactive response containing the remaining time in the broken lease in seconds. + * @return A reactive response containing the remaining time in the broken lease in seconds. */ public Mono> breakLease() { return this.breakLease(null, null); @@ -711,90 +730,74 @@ public Mono> breakLease() { * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant * to break a fixed-duration lease when it expires or an infinite lease immediately. * - * @param breakPeriodInSeconds - * An optional {@code Integer} representing the proposed duration of seconds that the lease should continue - * before it is broken, between 0 and 60 seconds. This break period is only used if it is shorter than the - * time remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be - * available before the break period has expired, but the lease may be held for longer than the break - * period. - * @param modifiedAccessConditions - * 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. - * - * @return - * A reactive response containing the remaining time in the broken lease in seconds. + * @param breakPeriodInSeconds An optional {@code Integer} representing the proposed duration of seconds that the + * lease should continue before it is broken, between 0 and 60 seconds. This break period is only used if it is + * shorter than the time remaining on the lease. If longer, the time remaining on the lease is used. A new lease + * will not be available before the break period has expired, but the lease may be held for longer than the break + * period. + * @param modifiedAccessConditions 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. + * @return A reactive response containing the remaining time in the broken lease in seconds. */ public Mono> breakLease(Integer breakPeriodInSeconds, ModifiedAccessConditions modifiedAccessConditions) { - return blobAsyncRawClient - .breakLease(breakPeriodInSeconds, modifiedAccessConditions) + return postProcessResponse(this.azureBlobStorage.blobs().breakLeaseWithRestResponseAsync(null, + null, null, breakPeriodInSeconds, null, modifiedAccessConditions, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseTime())); } /** * ChangeLease changes the blob's lease ID. * - * @param leaseId - * The leaseId of the active lease on the blob. - * @param proposedID - * A {@code String} in any valid GUID format. - * - * @return - * A reactive response containing the new lease ID. + * @param leaseId The leaseId of the active lease on the blob. + * @param proposedID A {@code String} in any valid GUID format. + * @return A reactive response containing the new lease ID. */ public Mono> changeLease(String leaseId, String proposedID) { return this.changeLease(leaseId, proposedID, null); } /** - * ChangeLease changes the blob's lease ID. For more information, see the Azure Docs. - * - * @param leaseId - * The leaseId of the active lease on the blob. - * @param proposedID - * A {@code String} in any valid GUID format. - * @param modifiedAccessConditions - * 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. + * ChangeLease changes the blob's lease ID. For more information, see the Azure + * Docs. * + * @param leaseId The leaseId of the active lease on the blob. + * @param proposedID A {@code String} in any valid GUID format. + * @param modifiedAccessConditions 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. * @return A reactive response containing the new lease ID. */ public Mono> changeLease(String leaseId, String proposedID, ModifiedAccessConditions modifiedAccessConditions) { - return blobAsyncRawClient - .changeLease(leaseId, proposedID, modifiedAccessConditions) + return postProcessResponse(this.azureBlobStorage.blobs().changeLeaseWithRestResponseAsync(null, + null, leaseId, proposedID, null, null, modifiedAccessConditions, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseId())); } /** - * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. + * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. * * @return a reactor response containing the sku name and account kind. */ // TODO (unknown): determine this return type public Mono> getAccountInfo() { - return blobAsyncRawClient - .getAccountInfo() + return postProcessResponse( + this.azureBlobStorage.blobs().getAccountInfoWithRestResponseAsync(null, null, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, new StorageAccountInfo(rb.deserializedHeaders()))); } /** * 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 + * @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) { + 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 */); @@ -803,29 +806,19 @@ public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, Str /** * 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 + * @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) { + 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 */); @@ -834,40 +827,25 @@ public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, Str /** * 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 - * @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 + * @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 + * @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) { + BlobSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, + SASProtocol sasProtocol, IPRange ipRange, String cacheControl, String contentDisposition, + String contentEncoding, String contentLanguage, String contentType) { ServiceSASSignatureValues serviceSASSignatureValues = new ServiceSASSignatureValues(version, sasProtocol, startTime, expiryTime, permissions == null ? null : permissions.toString(), ipRange, null /* identifier*/, @@ -883,13 +861,9 @@ public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, Str /** * Generates a SAS token with the specified parameters * - * @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 + * @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 generateSAS(BlobSASPermission permissions, OffsetDateTime expiryTime) { return this.generateSAS(null, permissions, expiryTime, null /* startTime */, /* identifier */ null /* @@ -900,11 +874,8 @@ public String generateSAS(BlobSASPermission permissions, OffsetDateTime expiryTi /** * 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 + * @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 */, @@ -915,26 +886,17 @@ public String generateSAS(String 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 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 + * @param identifier The {@code String} name of the access policy on the container this SAS references if any + * @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 generateSAS(String identifier, BlobSASPermission permissions, OffsetDateTime expiryTime, - OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange) { + 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 */); @@ -943,44 +905,30 @@ public String generateSAS(String identifier, BlobSASPermission permissions, Offs /** * 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 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 - * @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 + * @param identifier The {@code String} name of the access policy on the container this SAS references if any + * @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 + * @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) { + OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange, String cacheControl, + String contentDisposition, String contentEncoding, String contentLanguage, String contentType) { ServiceSASSignatureValues serviceSASSignatureValues = new ServiceSASSignatureValues(version, sasProtocol, startTime, expiryTime, permissions == null ? null : permissions.toString(), ipRange, identifier, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); SharedKeyCredential sharedKeyCredential = - Utility.getSharedKeyCredential(this.blobAsyncRawClient.azureBlobStorage.httpPipeline()); + Utility.getSharedKeyCredential(this.azureBlobStorage.httpPipeline()); Utility.assertNotNull("sharedKeyCredential", sharedKeyCredential); @@ -996,10 +944,10 @@ public String generateSAS(String identifier, BlobSASPermission permissions, Offs * Sets serviceSASSignatureValues parameters dependent on the current blob type */ ServiceSASSignatureValues configureServiceSASSignatureValues(ServiceSASSignatureValues serviceSASSignatureValues, - String accountName) { + String accountName) { // Set canonical name - serviceSASSignatureValues.canonicalName(this.blobAsyncRawClient.azureBlobStorage.url(), accountName); + serviceSASSignatureValues.canonicalName(this.azureBlobStorage.url(), accountName); // Set snapshotId serviceSASSignatureValues.snapshotId(getSnapshotId()); @@ -1017,20 +965,18 @@ ServiceSASSignatureValues configureServiceSASSignatureValues(ServiceSASSignature /** * Gets the snapshotId for a blob resource * - * @return - * A string that represents the snapshotId of the snapshot blob + * @return A string that represents the snapshotId of the snapshot blob */ public String getSnapshotId() { - return this.blobAsyncRawClient.snapshot; + return this.snapshot; } /** * Determines if a blob is a snapshot * - * @return - * A boolean that indicates if a blob is a snapshot + * @return A boolean that indicates if a blob is a snapshot */ public boolean isSnapshot() { - return this.blobAsyncRawClient.snapshot != null; + return this.snapshot != null; } } diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncRawClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncRawClient.java deleted file mode 100644 index 002ba761a3bf8..0000000000000 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncRawClient.java +++ /dev/null @@ -1,766 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.storage.blob; - -import com.azure.core.util.Context; -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.BlobsAbortCopyFromURLResponse; -import com.azure.storage.blob.models.BlobsAcquireLeaseResponse; -import com.azure.storage.blob.models.BlobsBreakLeaseResponse; -import com.azure.storage.blob.models.BlobsChangeLeaseResponse; -import com.azure.storage.blob.models.BlobsCopyFromURLResponse; -import com.azure.storage.blob.models.BlobsCreateSnapshotResponse; -import com.azure.storage.blob.models.BlobsDeleteResponse; -import com.azure.storage.blob.models.BlobsGetAccountInfoResponse; -import com.azure.storage.blob.models.BlobsGetPropertiesResponse; -import com.azure.storage.blob.models.BlobsReleaseLeaseResponse; -import com.azure.storage.blob.models.BlobsRenewLeaseResponse; -import com.azure.storage.blob.models.BlobsSetHTTPHeadersResponse; -import com.azure.storage.blob.models.BlobsSetMetadataResponse; -import com.azure.storage.blob.models.BlobsSetTierResponse; -import com.azure.storage.blob.models.BlobsStartCopyFromURLResponse; -import com.azure.storage.blob.models.BlobsUndeleteResponse; -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.ReliableDownloadOptions; -import com.azure.storage.blob.models.SourceModifiedAccessConditions; -import reactor.core.publisher.Mono; - -import java.net.URL; - -import static com.azure.storage.blob.Utility.postProcessResponse; - -/** - * Represents a URL to a blob of any type: block, append, or page. It may be obtained by direct construction or via the - * create method on a {@link ContainerAsyncClient} object. This class does not hold any state about a particular blob but is - * instead a convenient way of sending off appropriate requests to the resource on the service. Please refer to the - * Azure Docs for more information. - */ -class BlobAsyncRawClient { - - protected AzureBlobStorageImpl azureBlobStorage; - - final String snapshot; - - /** - * Creates a {@code BlobAsyncRawClient} object pointing to the account specified by the URL and using the provided pipeline to - * make HTTP requests.. - */ - BlobAsyncRawClient(AzureBlobStorageImpl azureBlobStorage, String snapshot) { - this.azureBlobStorage = azureBlobStorage; - this.snapshot = snapshot; - } - - /** - * Copies the data at the source URL to a blob. 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 Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=start_copy "Sample code for BlobAsyncRawClient.startCopyFromURL")] \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=start_copy_helper "Helper for start_copy sample.")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono startCopyFromURL(URL sourceURL) { - return this.startCopyFromURL(sourceURL, null, null, null); - } - - /** - * Copies the data at the source URL to a blob. 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 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 Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=start_copy "Sample code for BlobAsyncRawClient.startCopyFromURL")] \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=start_copy_helper "Helper for start_copy sample.")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono startCopyFromURL(URL sourceURL, Metadata metadata, - ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions) { - 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() - .sourceIfModifiedSince(sourceModifiedAccessConditions.ifModifiedSince()) - .sourceIfUnmodifiedSince(sourceModifiedAccessConditions.ifUnmodifiedSince()) - .sourceIfMatch(sourceModifiedAccessConditions.ifMatch()) - .sourceIfNoneMatch(sourceModifiedAccessConditions.ifNoneMatch()); - - return postProcessResponse(this.azureBlobStorage.blobs().startCopyFromURLWithRestResponseAsync( - null, null, sourceURL, null, metadata, null, sourceConditions, - destAccessConditions.modifiedAccessConditions(), destAccessConditions.leaseAccessConditions(), Context.NONE)); - } - - /** - * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. 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 Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=abort_copy "Sample code for BlobAsyncRawClient.abortCopyFromURL")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono abortCopyFromURL(String copyId) { - return this.abortCopyFromURL(copyId, null); - } - - /** - * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. 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 Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=abort_copy "Sample code for BlobAsyncRawClient.abortCopyFromURL")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono abortCopyFromURL(String copyId, - LeaseAccessConditions leaseAccessConditions) { - return postProcessResponse(this.azureBlobStorage.blobs().abortCopyFromURLWithRestResponseAsync( - null, null, copyId, null, null, leaseAccessConditions, Context.NONE)); - } - - /** - * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. - * For more information, see the Azure Docs - * - * @param copySource - * The source URL to copy from. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=sync_copy "Sample code for BlobAsyncRawClient.copyFromURL")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono syncCopyFromURL(URL copySource) { - return this.syncCopyFromURL(copySource, null, null, null); - } - - /** - * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. - * 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 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 Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=sync_copy "Sample code for BlobAsyncRawClient.copyFromURL")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono syncCopyFromURL(URL copySource, Metadata metadata, - ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions) { - 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() - .sourceIfModifiedSince(sourceModifiedAccessConditions.ifModifiedSince()) - .sourceIfUnmodifiedSince(sourceModifiedAccessConditions.ifUnmodifiedSince()) - .sourceIfMatch(sourceModifiedAccessConditions.ifMatch()) - .sourceIfNoneMatch(sourceModifiedAccessConditions.ifNoneMatch()); - - return postProcessResponse(this.azureBlobStorage.blobs().copyFromURLWithRestResponseAsync( - null, null, copySource, null, metadata, null, sourceConditions, - destAccessConditions.modifiedAccessConditions(), destAccessConditions.leaseAccessConditions(), Context.NONE)); - } - - /** - * 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}. - * - * @return Emits the successful response. - * @apiNote ## Sample Code \n [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=upload_download - * "Sample code for BlobAsyncRawClient.download")] \n For more samples, please see the [Samples - * file](%https://github.com/Azure/azure-storage-java/blob/New-Storage-SDK-V10-Preview/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono download() { - return this.download(null, null, false); - } - - /** - * 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. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=upload_download "Sample code for BlobAsyncRawClient.download")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono download(BlobRange range, BlobAccessConditions accessConditions, - boolean rangeGetContentMD5) { - range = range == null ? new BlobRange(0) : range; - Boolean getMD5 = rangeGetContentMD5 ? rangeGetContentMD5 : null; - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - HTTPGetterInfo info = new HTTPGetterInfo() - .offset(range.offset()) - .count(range.count()) - .eTag(accessConditions.modifiedAccessConditions().ifMatch()); - - // TODO: range is BlobRange but expected as String - // TODO: figure out correct response - return postProcessResponse(this.azureBlobStorage.blobs().downloadWithRestResponseAsync( - null, null, snapshot, null, null, range.toHeaderValue(), getMD5, - null, null, null, null, - accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)) - // 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.eTag(response.deserializedHeaders().eTag()); - 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.offset(), newInfo.count()), - new BlobAccessConditions().modifiedAccessConditions( - new ModifiedAccessConditions().ifMatch(info.eTag())), false)); - }); - } - - /** - * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. For more - * information, see the Azure Docs. - * - * @return Emits the successful response. - * @apiNote ## Sample Code \n [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_delete - * "Sample code for BlobAsyncRawClient.delete")] \n For more samples, please see the [Samples - * file](%https://github.com/Azure/azure-storage-java/blob/New-Storage-SDK-V10-Preview/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono delete() { - return this.delete(null, null); - } - - /** - * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. 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 Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_delete "Sample code for BlobAsyncRawClient.delete")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono delete(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, - BlobAccessConditions accessConditions) { - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - return postProcessResponse(this.azureBlobStorage.blobs().deleteWithRestResponseAsync( - null, null, snapshot, null, null, deleteBlobSnapshotOptions, - null, accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), - Context.NONE)); - } - - /** - * Returns the blob's metadata and properties. For more information, see the Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=properties_metadata "Sample code for BlobAsyncRawClient.getProperties")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono getProperties() { - return this.getProperties(null); - } - - /** - * Returns the blob's metadata and properties. For more information, see the Azure Docs. - * - * @param accessConditions - * {@link BlobAccessConditions} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=properties_metadata "Sample code for BlobAsyncRawClient.getProperties")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono getProperties(BlobAccessConditions accessConditions) { - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - return postProcessResponse(this.azureBlobStorage.blobs().getPropertiesWithRestResponseAsync( - null, null, snapshot, null, null, null, - null, null, null, accessConditions.leaseAccessConditions(), - accessConditions.modifiedAccessConditions(), Context.NONE)); - } - - /** - * Changes a blob's HTTP header properties. For more information, see the Azure - * Docs. - * - * @param headers - * {@link BlobHTTPHeaders} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=properties_metadata "Sample code for BlobAsyncRawClient.setHTTPHeaders")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono setHTTPHeaders(BlobHTTPHeaders headers) { - return this.setHTTPHeaders(headers, null); - } - - /** - * Changes a blob's HTTP header properties. For more information, see the Azure Docs. - * - * @param headers - * {@link BlobHTTPHeaders} - * @param accessConditions - * {@link BlobAccessConditions} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=properties_metadata "Sample code for BlobAsyncRawClient.setHTTPHeaders")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono setHTTPHeaders(BlobHTTPHeaders headers, - BlobAccessConditions accessConditions) { - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - return postProcessResponse(this.azureBlobStorage.blobs().setHTTPHeadersWithRestResponseAsync( - null, null, null, null, headers, - accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)); - } - - /** - * Changes a blob's metadata. For more information, see the Azure Docs. - * - * @param metadata - * {@link Metadata} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=properties_metadata "Sample code for BlobAsyncRawClient.setMetadata")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono setMetadata(Metadata metadata) { - return this.setMetadata(metadata, null); - } - - /** - * Changes a blob's metadata. For more information, see the Azure Docs. - * - * @param metadata - * {@link Metadata} - * @param accessConditions - * {@link BlobAccessConditions} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=properties_metadata "Sample code for BlobAsyncRawClient.setMetadata")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono setMetadata(Metadata metadata, BlobAccessConditions accessConditions) { - metadata = metadata == null ? new Metadata() : metadata; - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - return postProcessResponse(this.azureBlobStorage.blobs().setMetadataWithRestResponseAsync( - null, null, null, metadata, null, null, - null, null, accessConditions.leaseAccessConditions(), - accessConditions.modifiedAccessConditions(), Context.NONE)); - } - - /** - * Creates a read-only snapshot of a blob. For more information, see the Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=snapshot "Sample code for BlobAsyncRawClient.createSnapshot")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono createSnapshot() { - return this.createSnapshot(null, null); - } - - /** - * Creates a read-only snapshot of a blob. For more information, see the Azure Docs. - * - * @param metadata - * {@link Metadata} - * @param accessConditions - * {@link BlobAccessConditions} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=snapshot "Sample code for BlobAsyncRawClient.createSnapshot")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono createSnapshot(Metadata metadata, BlobAccessConditions accessConditions) { - metadata = metadata == null ? new Metadata() : metadata; - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - return postProcessResponse(this.azureBlobStorage.blobs().createSnapshotWithRestResponseAsync( - null, null, null, metadata, null, null, - null, null, accessConditions.modifiedAccessConditions(), - accessConditions.leaseAccessConditions(), 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. - *

- * For detailed information about block blob level tiering see the Azure Docs. - * - * @param tier - * The new tier for the blob. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=tier "Sample code for BlobAsyncRawClient.setTier")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono setTier(AccessTier tier) { - return this.setTier(tier, null); - } - - /** - * 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. - *

- * For detailed information about block blob level tiering see the Azure Docs. - * - * @param tier - * The new tier for the blob. - * @param leaseAccessConditions - * By setting lease access conditions, requests will fail if the provided lease does not match the active - * lease on the blob. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=tier "Sample code for BlobAsyncRawClient.setTier")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono setTier(AccessTier tier, LeaseAccessConditions leaseAccessConditions) { - Utility.assertNotNull("tier", tier); - - return postProcessResponse(this.azureBlobStorage.blobs().setTierWithRestResponseAsync( - null, null, tier, null, null, leaseAccessConditions, Context.NONE)); - } - - /** - * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots. - * For more information, see the Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=undelete "Sample code for BlobAsyncRawClient.undelete")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono undelete() { - return postProcessResponse(this.azureBlobStorage.blobs().undeleteWithRestResponseAsync(null, - null, Context.NONE)); - } - - /** - * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 - * seconds, or infinite (-1). For more information, see the Azure Docs. - * - * @param proposedId - * A {@code String} in any valid GUID format. May be null. - * @param duration - * The duration of the lease, in seconds, or negative one (-1) for a lease that - * never expires. A non-infinite lease can be between 15 and 60 seconds. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.acquireLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono acquireLease(String proposedId, int duration) { - return this.acquireLease(proposedId, duration, null); - } - - /** - * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 - * seconds, or infinite (-1). For more information, see the Azure Docs. - * - * @param proposedID - * A {@code String} in any valid GUID format. May be null. - * @param duration - * The duration of the lease, in seconds, or negative one (-1) for a lease that - * never expires. A non-infinite lease can be between 15 and 60 seconds. - * @param modifiedAccessConditions - * 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. - * - * @return Emits the successful response. - * @throws IllegalArgumentException If {@code duration} is outside the bounds of 15 to 60 or isn't -1. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.acquireLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono acquireLease(String proposedID, int duration, - ModifiedAccessConditions modifiedAccessConditions) { - if (!(duration == -1 || (duration >= 15 && duration <= 60))) { - // Throwing is preferred to Mono.error because this will error out immediately instead of waiting until - // subscription. - throw new IllegalArgumentException("Duration must be -1 or between 15 and 60."); - } - - return postProcessResponse(this.azureBlobStorage.blobs().acquireLeaseWithRestResponseAsync( - null, null, null, duration, proposedID, null, - modifiedAccessConditions, Context.NONE)); - } - - /** - * Renews the blob's previously-acquired lease. For more information, see the Azure Docs. - * - * @param leaseID - * The leaseId of the active lease on the blob. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.renewLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono renewLease(String leaseID) { - return this.renewLease(leaseID, null); - } - - /** - * Renews the blob's previously-acquired lease. For more information, see the Azure Docs. - * - * @param leaseID - * The leaseId of the active lease on the blob. - * @param modifiedAccessConditions - * 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. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.renewLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono renewLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions) { - return postProcessResponse(this.azureBlobStorage.blobs().renewLeaseWithRestResponseAsync(null, - null, leaseID, null, null, modifiedAccessConditions, Context.NONE)); - } - - /** - * Releases the blob's previously-acquired lease. For more information, see the Azure Docs. - * - * @param leaseID - * The leaseId of the active lease on the blob. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.releaseLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono releaseLease(String leaseID) { - return this.releaseLease(leaseID, null); - } - - /** - * Releases the blob's previously-acquired lease. For more information, see the Azure Docs. - * - * @param leaseID - * The leaseId of the active lease on the blob. - * @param modifiedAccessConditions - * 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. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.releaseLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono releaseLease(String leaseID, - ModifiedAccessConditions modifiedAccessConditions) { - return postProcessResponse(this.azureBlobStorage.blobs().releaseLeaseWithRestResponseAsync(null, - null, leaseID, null, null, modifiedAccessConditions, Context.NONE)); - } - - /** - * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant - * to break a fixed-duration lease when it expires or an infinite lease immediately. For more information, see the - * Azure Docs. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.breakLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/New-Storage-SDK-V10-Preview/src/test/java/com/microsoft/azure/storage/Samples.java) - * - * @return - * Emits the successful response. - */ - public Mono breakLease() { - return this.breakLease(null, null); - } - - /** - * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant - * to break a fixed-duration lease when it expires or an infinite lease immediately. For more information, see the - * Azure Docs. - * - * @param breakPeriodInSeconds - * An optional {@code Integer} representing the proposed duration of seconds that the lease should continue - * before it is broken, between 0 and 60 seconds. This break period is only used if it is shorter than the - * time remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be - * available before the break period has expired, but the lease may be held for longer than the break - * period. - * @param modifiedAccessConditions - * 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. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.breakLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono breakLease(Integer breakPeriodInSeconds, - ModifiedAccessConditions modifiedAccessConditions) { - return postProcessResponse(this.azureBlobStorage.blobs().breakLeaseWithRestResponseAsync(null, - null, null, breakPeriodInSeconds, null, modifiedAccessConditions, Context.NONE)); - } - - /** - * ChangeLease changes the blob's lease ID. For more information, see the Azure Docs. - * - * @param leaseId - * The leaseId of the active lease on the blob. - * @param proposedID - * A {@code String} in any valid GUID format. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.changeLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono changeLease(String leaseId, String proposedID) { - return this.changeLease(leaseId, proposedID, null); - } - - /** - * ChangeLease changes the blob's lease ID. For more information, see the Azure Docs. - * - * @param leaseId - * The leaseId of the active lease on the blob. - * @param proposedID - * A {@code String} in any valid GUID format. - * @param modifiedAccessConditions - * 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. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.changeLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono changeLease(String leaseId, String proposedID, - ModifiedAccessConditions modifiedAccessConditions) { - return postProcessResponse(this.azureBlobStorage.blobs().changeLeaseWithRestResponseAsync(null, - null, leaseId, proposedID, null, null, modifiedAccessConditions, Context.NONE)); - } - - /** - * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=account_info "Sample code for BlobAsyncRawClient.getAccountInfo")] \n - * For more samples, please see the [Samples file](https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono getAccountInfo() { - return postProcessResponse( - this.azureBlobStorage.blobs().getAccountInfoWithRestResponseAsync(null, null, Context.NONE)); - } -} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java index 21a2212713f5c..a937b8ca47613 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java @@ -27,30 +27,30 @@ import java.time.OffsetDateTime; /** - * 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. + * 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 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}. + * client can be converted into one of these clients easily through the methods {@link #asBlockBlobClient}, {@link + * #asPageBlobClient}, and {@link #asAppendBlobClient}. * *

- * 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 StorageClient}. + * 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 StorageClient}. * *

- * Please refer to the Azure Docs - * for more information. + * Please refer to the Azure + * Docs for more information. */ public class BlobClient { - private static final int BLOB_DEFAULT_DOWNLOAD_BLOCK_SIZE = 4 * Constants.MB; private final BlobAsyncClient blobAsyncClient; /** * Package-private constructor for use by {@link BlobClientBuilder}. + * * @param blobAsyncClient the async blob client */ BlobClient(BlobAsyncClient blobAsyncClient) { @@ -58,45 +58,41 @@ public class BlobClient { } /** - * Creates a new {@link BlockBlobClient} to this resource, maintaining configurations. Only do this for blobs - * that are known to be block blobs. + * 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. + * @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. + * 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. + * @return A {@link AppendBlobClient} to this resource. */ 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. + * 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. + * @return A {@link PageBlobClient} to this resource. */ public PageBlobClient asPageBlobClient() { return new PageBlobClient(blobAsyncClient.asPageBlobAsyncClient()); } /** - * 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 + * 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 + * @return A {@link ContainerClient} object pointing to the container containing the blob */ public ContainerClient getContainerClient() { return new ContainerClient(blobAsyncClient.getContainerAsyncClient()); @@ -104,6 +100,7 @@ public ContainerClient getContainerClient() { /** * Gets the URL of the blob represented by this client. + * * @return the URL. */ public URL getBlobUrl() { @@ -115,9 +112,7 @@ public URL getBlobUrl() { *

* * @return An InputStream object that represents the stream to use for reading from the blob. - * - * @throws StorageException - * If a storage service error occurred. + * @throws StorageException If a storage service error occurred. */ public final BlobInputStream openInputStream() { return openInputStream(new BlobRange(0), null); @@ -127,15 +122,11 @@ public final BlobInputStream openInputStream() { * 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. - * + * @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. + * @throws StorageException If a storage service error occurred. */ public final BlobInputStream openInputStream(BlobRange range, BlobAccessConditions accessConditions) { return new BlobInputStream(blobAsyncClient, range.offset(), range.count(), accessConditions); @@ -153,10 +144,8 @@ public Response exists() { /** * Gets if the container this client represents exists in the cloud. * - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * @return - * true if the container exists, false if it doesn't + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return true if the container exists, false if it doesn't */ public Response exists(Duration timeout) { Mono> response = blobAsyncClient.exists(); @@ -168,11 +157,8 @@ public Response exists(Duration timeout) { * Copies the data at the source URL to a blob. 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. + * @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 Response startCopyFromURL(URL sourceURL) { return this.startCopyFromURL(sourceURL, null, null, null, null); @@ -182,26 +168,19 @@ public Response startCopyFromURL(URL sourceURL) { * Copies the data at the source URL to a blob. 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 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. - * - * @return - * The copy ID for the long running operation. + * @param sourceURL The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * @param metadata {@link Metadata} + * @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. + * @return The copy ID for the long running operation. */ public Response startCopyFromURL(URL sourceURL, Metadata metadata, - ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions, - Duration timeout) { + ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions, + Duration timeout) { Mono> response = blobAsyncClient .startCopyFromURL(sourceURL, metadata, sourceModifiedAccessConditions, destAccessConditions); @@ -211,9 +190,8 @@ public Response startCopyFromURL(URL sourceURL, Metadata metadata, /** * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. * - * @param copyId - * The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link - * BlobStartCopyFromURLHeaders} object. + * @param copyId The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link + * BlobStartCopyFromURLHeaders} object. * @return A response containing status code and HTTP headers. */ public VoidResponse abortCopyFromURL(String copyId) { @@ -223,14 +201,11 @@ public VoidResponse abortCopyFromURL(String copyId) { /** * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. * - * @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 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. * @return A response containing status code and HTTP headers. */ public VoidResponse abortCopyFromURL(String copyId, LeaseAccessConditions leaseAccessConditions, Duration timeout) { @@ -243,11 +218,8 @@ public VoidResponse abortCopyFromURL(String copyId, LeaseAccessConditions leaseA /** * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. * - * @param copySource - * The source URL to copy from. - * - * @return - * The copy ID for the long running operation. + * @param copySource The source URL to copy from. + * @return The copy ID for the long running operation. */ public Response copyFromURL(URL copySource) { return this.copyFromURL(copySource, null, null, null, null); @@ -256,26 +228,19 @@ public Response copyFromURL(URL copySource) { /** * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. * - * @param copySource - * The source URL to copy from. URLs outside of Azure may only be copied to block blobs. - * @param metadata - * {@link Metadata} - * @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. - * - * @return - * The copy ID for the long running operation. + * @param copySource The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * @param metadata {@link Metadata} + * @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. + * @return The copy ID for the long running operation. */ public Response copyFromURL(URL copySource, Metadata metadata, - ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions, - Duration timeout) { + ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions, + Duration timeout) { Mono> response = blobAsyncClient .copyFromURL(copySource, metadata, sourceModifiedAccessConditions, destAccessConditions); @@ -286,8 +251,7 @@ public Response copyFromURL(URL copySource, Metadata metadata, * Downloads the entire blob into an output stream. Uploading data must be done from the {@link BlockBlobClient}, * {@link PageBlobClient}, or {@link AppendBlobClient}. * - * @param stream - * A non-null {@link OutputStream} instance where the downloaded data will be written. + * @param stream A non-null {@link OutputStream} instance where the downloaded data will be written. * @return A response containing status code and HTTP headers. * @throws UncheckedIOException If an I/O error occurs. */ @@ -296,23 +260,17 @@ public VoidResponse download(OutputStream stream) { } /** - * 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}. + * 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}. * - * @param stream - * A non-null {@link OutputStream} instance where the downloaded data will be written. + * @param stream A non-null {@link OutputStream} instance where the downloaded data will be written. * @param options {@link ReliableDownloadOptions} - * @param range - * {@link BlobRange} - * @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 range {@link BlobRange} + * @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. * @return A response containing status code and HTTP headers. * @throws UncheckedIOException If an I/O error occurs. - * */ public VoidResponse download(OutputStream stream, ReliableDownloadOptions options, BlobRange range, BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Duration timeout) { @@ -334,37 +292,32 @@ public VoidResponse download(OutputStream stream, ReliableDownloadOptions option /** * Downloads the entire blob into a file specified by the path. The file will be created if it doesn't exist. - * Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient}. + * Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link + * AppendBlobClient}. * - * @param filePath - * A non-null {@link OutputStream} instance where the downloaded data will be written. + * @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written. * @throws IOException If an I/O error occurs */ public void downloadToFile(String filePath) throws IOException { - this.downloadToFile(filePath, null, null, BLOB_DEFAULT_DOWNLOAD_BLOCK_SIZE, null, false, null); + blobAsyncClient.downloadToFile(filePath); } /** * Downloads a range of bytes blob into a file specified by the path. The file will be created if it doesn't exist. - * Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient}. + * Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link + * AppendBlobClient}. * - * @param filePath - * A non-null {@link OutputStream} instance where the downloaded data will be written. + * @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written. * @param options {@link ReliableDownloadOptions} - * @param range - * {@link BlobRange} - * @param blockSize - * the size of a chunk to download at a time, in bytes - * @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 range {@link BlobRange} + * @param blockSize the size of a chunk to download at a time, in bytes + * @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. * @throws IOException If an I/O error occurs */ public void downloadToFile(String filePath, ReliableDownloadOptions options, BlobRange range, Integer blockSize, - BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Duration timeout) throws IOException { + BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Duration timeout) throws IOException { Mono download = blobAsyncClient.downloadToFile(filePath, range, blockSize, accessConditions, rangeGetContentMD5, options); try { @@ -386,19 +339,15 @@ public VoidResponse delete() { /** * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. * - * @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 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. * @return A response containing status code and HTTP headers. */ public VoidResponse delete(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, - BlobAccessConditions accessConditions, Duration timeout) { + BlobAccessConditions accessConditions, Duration timeout) { Mono response = blobAsyncClient .delete(deleteBlobSnapshotOptions, accessConditions); @@ -408,8 +357,7 @@ public VoidResponse delete(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, /** * Returns the blob's metadata and properties. * - * @return - * The blob properties and metadata. + * @return The blob properties and metadata. */ public Response getProperties() { return this.getProperties(null, null); @@ -418,13 +366,9 @@ public Response getProperties() { /** * Returns the blob's metadata and properties. * - * @param accessConditions - * {@link BlobAccessConditions} - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * - * @return - * The blob properties and metadata. + * @param accessConditions {@link BlobAccessConditions} + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return The blob properties and metadata. */ public Response getProperties(BlobAccessConditions accessConditions, Duration timeout) { Mono> response = blobAsyncClient @@ -434,13 +378,12 @@ public Response getProperties(BlobAccessConditions accessConditi } /** - * 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. For more information, see the + * 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. For more information, + * see the * Azure Docs. * - * @param headers - * {@link BlobHTTPHeaders} + * @param headers {@link BlobHTTPHeaders} * @return A response containing status code and HTTP headers. */ public VoidResponse setHTTPHeaders(BlobHTTPHeaders headers) { @@ -448,21 +391,18 @@ public VoidResponse setHTTPHeaders(BlobHTTPHeaders headers) { } /** - * 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. For more information, see the + * 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. 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 headers {@link BlobHTTPHeaders} + * @param accessConditions {@link BlobAccessConditions} + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return A response containing status code and HTTP headers. */ public VoidResponse setHTTPHeaders(BlobHTTPHeaders headers, BlobAccessConditions accessConditions, - Duration timeout) { + Duration timeout) { Mono response = blobAsyncClient .setHTTPHeaders(headers, accessConditions); @@ -470,12 +410,11 @@ public VoidResponse setHTTPHeaders(BlobHTTPHeaders headers, BlobAccessConditions } /** - * 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. For more information, see the Azure Docs. + * 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. For more information, see the + * Azure Docs. * - * @param metadata - * {@link Metadata} + * @param metadata {@link Metadata} * @return A response containing status code and HTTP headers. */ public VoidResponse setMetadata(Metadata metadata) { @@ -483,16 +422,13 @@ public VoidResponse setMetadata(Metadata metadata) { } /** - * 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. For more information, see the Azure Docs. + * 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. 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 metadata {@link Metadata} + * @param accessConditions {@link BlobAccessConditions} + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return A response containing status code and HTTP headers. */ public VoidResponse setMetadata(Metadata metadata, BlobAccessConditions accessConditions, Duration timeout) { @@ -505,8 +441,7 @@ public VoidResponse setMetadata(Metadata metadata, BlobAccessConditions accessCo /** * Creates a read-only snapshot of a blob. * - * @return - * The ID of the new snapshot. + * @return The ID of the new snapshot. */ public Response createSnapshot() { return this.createSnapshot(null, null, null); @@ -515,15 +450,10 @@ public Response createSnapshot() { /** * Creates a read-only snapshot of a blob. * - * @param metadata - * {@link Metadata} - * @param accessConditions - * {@link BlobAccessConditions} - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * - * @return - * The ID of the new snapshot. + * @param metadata {@link Metadata} + * @param accessConditions {@link BlobAccessConditions} + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return The ID of the new snapshot. */ public Response createSnapshot(Metadata metadata, BlobAccessConditions accessConditions, Duration timeout) { Mono> response = blobAsyncClient @@ -535,10 +465,10 @@ public Response createSnapshot(Metadata metadata, BlobAccessConditions a /** * 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. + * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's + * etag. * - * @param tier - * The new tier for the blob. + * @param tier The new tier for the blob. * @return A response containing status code and HTTP headers. */ public VoidResponse setTier(AccessTier tier) { @@ -548,15 +478,13 @@ public VoidResponse setTier(AccessTier tier) { /** * 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. - * - * @param tier - * The new tier for the blob. - * @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. + * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's + * etag. + * + * @param tier The new tier for the blob. + * @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. * @return A response containing status code and HTTP headers. */ public VoidResponse setTier(AccessTier tier, LeaseAccessConditions leaseAccessConditions, Duration timeout) { @@ -578,8 +506,7 @@ public VoidResponse undelete() { /** * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots. * - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return A response containing status code and HTTP headers. */ public VoidResponse undelete(Duration timeout) { @@ -593,14 +520,10 @@ public VoidResponse undelete(Duration timeout) { * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 * seconds, or infinite (-1). * - * @param proposedId - * A {@code String} in any valid GUID format. May be null. - * @param duration - * The duration of the lease, in seconds, or negative one (-1) for a lease that - * never expires. A non-infinite lease can be between 15 and 60 seconds. - * - * @return - * The lease ID. + * @param proposedId A {@code String} in any valid GUID format. May be null. + * @param duration The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A + * non-infinite lease can be between 15 and 60 seconds. + * @return The lease ID. */ public Response acquireLease(String proposedId, int duration) { return this.acquireLease(proposedId, duration, null, null); @@ -610,23 +533,17 @@ public Response acquireLease(String proposedId, int duration) { * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 * seconds, or infinite (-1). * - * @param proposedID - * A {@code String} in any valid GUID format. May be null. - * @param duration - * The duration of the lease, in seconds, or negative one (-1) for a lease that - * never expires. A non-infinite lease can be between 15 and 60 seconds. - * @param modifiedAccessConditions - * 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 timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * - * @return - * The lease ID. + * @param proposedID A {@code String} in any valid GUID format. May be null. + * @param duration The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A + * non-infinite lease can be between 15 and 60 seconds. + * @param modifiedAccessConditions 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 timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return The lease ID. */ public Response acquireLease(String proposedID, int duration, - ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { Mono> response = blobAsyncClient .acquireLease(proposedID, duration, modifiedAccessConditions); @@ -636,11 +553,8 @@ public Response acquireLease(String proposedID, int duration, /** * Renews the blob's previously-acquired lease. * - * @param leaseID - * The leaseId of the active lease on the blob. - * - * @return - * The renewed lease ID. + * @param leaseID The leaseId of the active lease on the blob. + * @return The renewed lease ID. */ public Response renewLease(String leaseID) { return this.renewLease(leaseID, null, null); @@ -649,20 +563,15 @@ public Response renewLease(String leaseID) { /** * Renews the blob's previously-acquired lease. * - * @param leaseID - * The leaseId of the active lease on the blob. - * @param modifiedAccessConditions - * 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 timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * - * @return - * The renewed lease ID. + * @param leaseID The leaseId of the active lease on the blob. + * @param modifiedAccessConditions 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 timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return The renewed lease ID. */ public Response renewLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions, - Duration timeout) { + Duration timeout) { Mono> response = blobAsyncClient .renewLease(leaseID, modifiedAccessConditions); @@ -672,8 +581,7 @@ public Response renewLease(String leaseID, ModifiedAccessConditions modi /** * Releases the blob's previously-acquired lease. * - * @param leaseID - * The leaseId of the active lease on the blob. + * @param leaseID The leaseId of the active lease on the blob. * @return A response containing status code and HTTP headers. */ public VoidResponse releaseLease(String leaseID) { @@ -683,18 +591,15 @@ public VoidResponse releaseLease(String leaseID) { /** * Releases the blob's previously-acquired lease. * - * @param leaseID - * The leaseId of the active lease on the blob. - * @param modifiedAccessConditions - * 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 timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @param leaseID The leaseId of the active lease on the blob. + * @param modifiedAccessConditions 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 timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return A response containing status code and HTTP headers. */ public VoidResponse releaseLease(String leaseID, - ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { Mono response = blobAsyncClient .releaseLease(leaseID, modifiedAccessConditions); @@ -705,8 +610,7 @@ public VoidResponse releaseLease(String leaseID, * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant * to break a fixed-duration lease when it expires or an infinite lease immediately. * - * @return - * The remaining time in the broken lease in seconds. + * @return The remaining time in the broken lease in seconds. */ public Response breakLease() { return this.breakLease(null, null, null); @@ -716,24 +620,19 @@ public Response breakLease() { * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant * to break a fixed-duration lease when it expires or an infinite lease immediately. * - * @param breakPeriodInSeconds - * An optional {@code Integer} representing the proposed duration of seconds that the lease should continue - * before it is broken, between 0 and 60 seconds. This break period is only used if it is shorter than the - * time remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be - * available before the break period has expired, but the lease may be held for longer than the break - * period. - * @param modifiedAccessConditions - * 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 timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * - * @return - * The remaining time in the broken lease in seconds. + * @param breakPeriodInSeconds An optional {@code Integer} representing the proposed duration of seconds that the + * lease should continue before it is broken, between 0 and 60 seconds. This break period is only used if it is + * shorter than the time remaining on the lease. If longer, the time remaining on the lease is used. A new lease + * will not be available before the break period has expired, but the lease may be held for longer than the break + * period. + * @param modifiedAccessConditions 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 timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return The remaining time in the broken lease in seconds. */ public Response breakLease(Integer breakPeriodInSeconds, - ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { Mono> response = blobAsyncClient .breakLease(breakPeriodInSeconds, modifiedAccessConditions); @@ -743,36 +642,28 @@ public Response breakLease(Integer breakPeriodInSeconds, /** * ChangeLease changes the blob's lease ID. * - * @param leaseId - * The leaseId of the active lease on the blob. - * @param proposedID - * A {@code String} in any valid GUID format. - * - * @return - * The new lease ID. + * @param leaseId The leaseId of the active lease on the blob. + * @param proposedID A {@code String} in any valid GUID format. + * @return The new lease ID. */ public Response changeLease(String leaseId, String proposedID) { return this.changeLease(leaseId, proposedID, null, null); } /** - * ChangeLease changes the blob's lease ID. For more information, see the Azure Docs. - * - * @param leaseId - * The leaseId of the active lease on the blob. - * @param proposedID - * A {@code String} in any valid GUID format. - * @param modifiedAccessConditions - * 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 timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * ChangeLease changes the blob's lease ID. For more information, see the Azure + * Docs. * + * @param leaseId The leaseId of the active lease on the blob. + * @param proposedID A {@code String} in any valid GUID format. + * @param modifiedAccessConditions 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 timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return The new lease ID. */ public Response changeLease(String leaseId, String proposedID, - ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { Mono> response = blobAsyncClient .changeLease(leaseId, proposedID, modifiedAccessConditions); @@ -780,7 +671,8 @@ public Response changeLease(String leaseId, String proposedID, } /** - * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. + * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. * * @return The sku name and account kind. */ @@ -789,11 +681,10 @@ public Response getAccountInfo() { } /** - * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. - * - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. * + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return The sku name and account kind. */ public Response getAccountInfo(Duration timeout) { @@ -806,49 +697,33 @@ public Response getAccountInfo(Duration 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 ContainerSASPermissions} permission for the SAS - * @param expiryTime - * The {@code OffsetDateTime} expiry time for the SAS - * - * @return - * A string that represents the SAS token + * @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) { + 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 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 + * @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) { + BlobSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, + SASProtocol sasProtocol, IPRange ipRange) { return this.blobAsyncClient.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime, startTime, version, sasProtocol, ipRange); } @@ -856,40 +731,25 @@ public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, Str /** * 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 - * @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 + * @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 + * @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) { + 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); @@ -898,13 +758,9 @@ public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, Str /** * Generates a SAS token with the specified parameters * - * @param expiryTime - * The {@code OffsetDateTime} expiry time for the SAS - * @param permissions - * The {@code ContainerSASPermissions} permission for the SAS - * - * @return - * A string that represents the SAS token + * @param expiryTime The {@code OffsetDateTime} expiry time for the SAS + * @param permissions The {@code ContainerSASPermissions} 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); @@ -913,11 +769,8 @@ public String generateSAS(OffsetDateTime expiryTime, BlobSASPermission permissio /** * 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 + * @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); @@ -926,26 +779,17 @@ public String generateSAS(String 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 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 + * @param identifier The {@code String} name of the access policy on the container this SAS references if any + * @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 generateSAS(String identifier, BlobSASPermission permissions, OffsetDateTime expiryTime, - OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange) { + OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange) { return this.blobAsyncClient.generateSAS(identifier, permissions, expiryTime, startTime, version, sasProtocol, ipRange); } @@ -953,37 +797,23 @@ public String generateSAS(String identifier, BlobSASPermission permissions, Offs /** * 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 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 - * @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 + * @param identifier The {@code String} name of the access policy on the container this SAS references if any + * @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 + * @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) { + 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); } @@ -991,8 +821,7 @@ public String generateSAS(String identifier, BlobSASPermission permissions, Offs /** * Gets the snapshotId for a blob resource * - * @return - * A string that represents the snapshotId of the snapshot blob + * @return A string that represents the snapshotId of the snapshot blob */ public String getSnapshotId() { return this.blobAsyncClient.getSnapshotId(); @@ -1001,8 +830,7 @@ public String getSnapshotId() { /** * Determines if a blob is a snapshot * - * @return - * A boolean that indicates if a blob is a snapshot + * @return A boolean that indicates if a blob is a snapshot */ public boolean isSnapshot() { return this.blobAsyncClient.isSnapshot(); diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobInputStream.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobInputStream.java index 2e093f50738f2..1a990e179688b 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobInputStream.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobInputStream.java @@ -189,7 +189,7 @@ public synchronized void close() throws IOException { */ private synchronized void dispatchRead(final int readLength) throws IOException { try { - this.currentBuffer = this.blobClient.blobAsyncRawClient.download(new BlobRange(this.currentAbsoluteReadPosition, (long) readLength), this.accessCondition, false) + this.currentBuffer = this.blobClient.download(new BlobRange(this.currentAbsoluteReadPosition, (long) readLength), this.accessCondition, false) .flatMap(res -> ByteBufFlux.fromInbound(res.body(null)).aggregate().asByteBuffer()) .block(); diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobOutputStream.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobOutputStream.java index 176fe06c321d1..c733a580f2500 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobOutputStream.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobOutputStream.java @@ -295,7 +295,7 @@ private Mono writePages(Flux pageData, long offset, long writeLen PageBlobAccessConditions pageBlobAccessConditions = accessCondition == null ? null : new PageBlobAccessConditions().leaseAccessConditions(accessCondition.leaseAccessConditions()).modifiedAccessConditions(accessCondition.modifiedAccessConditions()); - return blobRef.pageBlobAsyncRawClient.uploadPages(new PageRange().start(offset).end(offset + writeLength - 1), pageData, pageBlobAccessConditions) + return blobRef.uploadPages(new PageRange().start(offset).end(offset + writeLength - 1), pageData, pageBlobAccessConditions) .then() .onErrorResume(t -> t instanceof StorageException, e -> { this.lastError = new IOException(e); @@ -312,7 +312,7 @@ private Mono appendBlock(Flux blockData, long offset, long writeL this.appendPositionAccessConditions.appendPosition(offset); AppendBlobAccessConditions appendBlobAccessConditions = accessCondition == null ? null : new AppendBlobAccessConditions().leaseAccessConditions(accessCondition.leaseAccessConditions()).modifiedAccessConditions(accessCondition.modifiedAccessConditions()); - return blobRef.appendBlobAsyncRawClient.appendBlock(blockData, writeLength, appendBlobAccessConditions) + return blobRef.appendBlock(blockData, writeLength, appendBlobAccessConditions) .then() .onErrorResume(t -> t instanceof IOException || t instanceof StorageException, e -> { this.lastError = new IOException(e); diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobURLParts.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobURLParts.java index 473d998c446b2..1200e960f7501 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobURLParts.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobURLParts.java @@ -76,14 +76,14 @@ public BlobURLParts host(String host) { } /** - * The container name or {@code null} if a {@link StorageAsyncRawClient} was parsed. + * The container name or {@code null} if a {@link StorageAsyncClient} was parsed. */ public String containerName() { return containerName; } /** - * The container name or {@code null} if a {@link StorageAsyncRawClient} was parsed. + * The container name or {@code null} if a {@link StorageAsyncClient} was parsed. */ public BlobURLParts containerName(String containerName) { this.containerName = containerName; @@ -91,14 +91,14 @@ public BlobURLParts containerName(String containerName) { } /** - * The blob name or {@code null} if a {@link StorageAsyncRawClient} or {@link ContainerAsyncClient} was parsed. + * The blob name or {@code null} if a {@link StorageAsyncClient} or {@link ContainerAsyncClient} was parsed. */ public String blobName() { return blobName; } /** - * The blob name or {@code null} if a {@link StorageAsyncRawClient} or {@link ContainerAsyncClient} was parsed. + * The blob name or {@code null} if a {@link StorageAsyncClient} or {@link ContainerAsyncClient} was parsed. */ public BlobURLParts blobName(String blobName) { this.blobName = blobName; diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncClient.java index ada7a125d4ef1..e7d8aa9b0c03d 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncClient.java @@ -8,6 +8,7 @@ import com.azure.core.http.rest.SimpleResponse; import com.azure.core.http.rest.VoidResponse; import com.azure.core.implementation.util.FluxUtil; +import com.azure.core.util.Context; import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; import com.azure.storage.blob.models.BlobAccessConditions; import com.azure.storage.blob.models.BlobHTTPHeaders; @@ -15,11 +16,11 @@ import com.azure.storage.blob.models.BlockBlobItem; import com.azure.storage.blob.models.BlockItem; import com.azure.storage.blob.models.BlockListType; +import com.azure.storage.blob.models.BlockLookupList; import com.azure.storage.blob.models.LeaseAccessConditions; import com.azure.storage.blob.models.Metadata; import com.azure.storage.blob.models.SourceModifiedAccessConditions; import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -27,7 +28,6 @@ import java.io.IOException; import java.io.UncheckedIOException; import java.net.URL; -import java.nio.ByteBuffer; import java.nio.channels.AsynchronousFileChannel; import java.nio.charset.StandardCharsets; import java.nio.file.Paths; @@ -39,6 +39,8 @@ import java.util.TreeMap; import java.util.UUID; +import static com.azure.storage.blob.Utility.postProcessResponse; + /** * Client to a block blob. It may only be instantiated through a {@link BlockBlobClientBuilder}, via * the method {@link BlobAsyncClient#asBlockBlobAsyncClient()}, or via the method @@ -66,8 +68,6 @@ public final class BlockBlobAsyncClient extends BlobAsyncClient { static final int BLOB_DEFAULT_UPLOAD_BLOCK_SIZE = 4 * Constants.MB; static final int BLOB_MAX_UPLOAD_BLOCK_SIZE = 100 * Constants.MB; - final BlockBlobAsyncRawClient blockBlobAsyncRawClient; - /** * Indicates the maximum number of bytes that can be sent in a call to upload. */ @@ -89,7 +89,6 @@ public final class BlockBlobAsyncClient extends BlobAsyncClient { */ BlockBlobAsyncClient(AzureBlobStorageBuilder azureBlobStorageBuilder, String snapshot) { super(azureBlobStorageBuilder, snapshot); - this.blockBlobAsyncRawClient = new BlockBlobAsyncRawClient(azureBlobStorageBuilder.build(), snapshot); } /** @@ -114,7 +113,7 @@ public final class BlockBlobAsyncClient extends BlobAsyncClient { * @return * A reactive response containing the information of the uploaded block blob. */ - public Mono> upload(Flux data, long length) { + public Mono> upload(Flux data, long length) { return this.upload(data, length, null, null, null); } @@ -146,10 +145,15 @@ public Mono> upload(Flux data, long length) * @return * A reactive response containing the information of the uploaded block blob. */ - public Mono> upload(Flux data, long length, BlobHTTPHeaders headers, + public Mono> upload(Flux data, long length, BlobHTTPHeaders headers, Metadata metadata, BlobAccessConditions accessConditions) { - return blockBlobAsyncRawClient - .upload(data.map(Unpooled::wrappedBuffer), length, headers, metadata, accessConditions) + metadata = metadata == null ? new Metadata() : metadata; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blockBlobs().uploadWithRestResponseAsync(null, + null, data, length, null, metadata, null, null, + null, null, headers, accessConditions.leaseAccessConditions(), + accessConditions.modifiedAccessConditions(), Context.NONE)) .map(rb -> new SimpleResponse<>(rb, new BlockBlobItem(rb.deserializedHeaders()))); } @@ -291,8 +295,9 @@ public Mono stageBlock(String base64BlockID, Flux data, */ public Mono stageBlock(String base64BlockID, Flux data, long length, LeaseAccessConditions leaseAccessConditions) { - return blockBlobAsyncRawClient - .stageBlock(base64BlockID, data, length, leaseAccessConditions) + return postProcessResponse(this.azureBlobStorage.blockBlobs().stageBlockWithRestResponseAsync(null, + null, base64BlockID, length, data, null, null, null, + null, null, null, leaseAccessConditions, Context.NONE)) .map(VoidResponse::new); } @@ -349,8 +354,13 @@ public Mono stageBlockFromURL(String base64BlockID, URL sourceURL, public Mono stageBlockFromURL(String base64BlockID, URL sourceURL, BlobRange sourceRange, byte[] sourceContentMD5, LeaseAccessConditions leaseAccessConditions, SourceModifiedAccessConditions sourceModifiedAccessConditions) { - return blockBlobAsyncRawClient - .stageBlockFromURL(base64BlockID, sourceURL, sourceRange, sourceContentMD5, leaseAccessConditions, sourceModifiedAccessConditions) + sourceRange = sourceRange == null ? new BlobRange(0) : sourceRange; + + return postProcessResponse( + this.azureBlobStorage.blockBlobs().stageBlockFromURLWithRestResponseAsync(null, null, + base64BlockID, 0, sourceURL, sourceRange.toHeaderValue(), sourceContentMD5, null, + null, null, null, null, + leaseAccessConditions, sourceModifiedAccessConditions, Context.NONE)) .map(VoidResponse::new); } @@ -386,8 +396,9 @@ public Flux listBlocks(BlockListType listType) { */ public Flux listBlocks(BlockListType listType, LeaseAccessConditions leaseAccessConditions) { - return blockBlobAsyncRawClient - .listBlocks(listType, leaseAccessConditions) + return postProcessResponse(this.azureBlobStorage.blockBlobs().getBlockListWithRestResponseAsync( + null, null, listType, snapshot, null, null, null, + leaseAccessConditions, Context.NONE)) .map(ResponseBase::value) .flatMapMany(bl -> { Flux committed = Flux.fromIterable(bl.committedBlocks()) @@ -440,8 +451,13 @@ public Mono> commitBlockList(List base64BlockIDs */ public Mono> commitBlockList(List base64BlockIDs, BlobHTTPHeaders headers, Metadata metadata, BlobAccessConditions accessConditions) { - return blockBlobAsyncRawClient - .commitBlockList(base64BlockIDs, headers, metadata, accessConditions) + metadata = metadata == null ? new Metadata() : metadata; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blockBlobs().commitBlockListWithRestResponseAsync( + null, null, new BlockLookupList().latest(base64BlockIDs), null, metadata, + null, null, null, null, headers, + accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)) .map(rb -> new SimpleResponse<>(rb, new BlockBlobItem(rb.deserializedHeaders()))); } } diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncRawClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncRawClient.java deleted file mode 100644 index 03b7e650167b6..0000000000000 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncRawClient.java +++ /dev/null @@ -1,364 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.storage.blob; - -import com.azure.core.util.Context; -import com.azure.storage.blob.implementation.AzureBlobStorageImpl; -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.BlockBlobsCommitBlockListResponse; -import com.azure.storage.blob.models.BlockBlobsGetBlockListResponse; -import com.azure.storage.blob.models.BlockBlobsStageBlockFromURLResponse; -import com.azure.storage.blob.models.BlockBlobsStageBlockResponse; -import com.azure.storage.blob.models.BlockBlobsUploadResponse; -import com.azure.storage.blob.models.BlockListType; -import com.azure.storage.blob.models.BlockLookupList; -import com.azure.storage.blob.models.LeaseAccessConditions; -import com.azure.storage.blob.models.Metadata; -import com.azure.storage.blob.models.SourceModifiedAccessConditions; -import io.netty.buffer.ByteBuf; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.net.URL; -import java.util.List; - -import static com.azure.storage.blob.Utility.postProcessResponse; - -/** - * Represents a URL to a block blob. It may be obtained by direct construction or via the create method on a - * {@link ContainerAsyncClient} object. This class does not hold any state about a particular blob but is instead a convenient - * way of sending off appropriate requests to the resource on the service. Please refer to the - * Azure Docs - * for more information on block blobs. - */ -final class BlockBlobAsyncRawClient extends BlobAsyncRawClient { - - /** - * Indicates the maximum number of bytes that can be sent in a call to upload. - */ - public static final int MAX_UPLOAD_BLOB_BYTES = 256 * Constants.MB; - - /** - * Indicates the maximum number of bytes that can be sent in a call to stageBlock. - */ - public static final int MAX_STAGE_BLOCK_BYTES = 100 * Constants.MB; - - /** - * Indicates the maximum number of blocks allowed in a block blob. - */ - public static final int MAX_BLOCKS = 50000; - - /** - * Creates a {@code BlockBlobAsyncRawClient} object pointing to the account specified by the URL and using the provided - */ - BlockBlobAsyncRawClient(AzureBlobStorageImpl azureBlobStorage, String snapshot) { - super(azureBlobStorage, snapshot); - } - - - /** - * Creates a new block blob, or updates the content of an existing block blob. - * Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not - * supported with PutBlob; the content of the existing blob is overwritten with the new content. To - * perform a partial update of a block blob's, use PutBlock and PutBlockList. - * For more information, see the - * 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. - *

- * - * @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 Flowable must produce the same data each time it is subscribed to. - * @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 Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=upload_download "Sample code for BlockBlobAsyncRawClient.upload")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono upload(Flux data, long length) { - return this.upload(data, length, null, null, null); - } - - /** - * Creates a new block blob, or updates the content of an existing block blob. - * Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not - * supported with PutBlob; the content of the existing blob is overwritten with the new content. To - * perform a partial update of a block blob's, use PutBlock and PutBlockList. - * For more information, see the - * 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. - *

- * - * @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 Flowable must produce the same data each time it is subscribed to. - * @param length - * The exact length of the data. It is important that this value match precisely the length of the data - * emitted by the {@code Flux}. - * @param headers - * {@link BlobHTTPHeaders} - * @param metadata - * {@link Metadata} - * @param accessConditions - * {@link BlobAccessConditions} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=upload_download "Sample code for BlockBlobAsyncRawClient.upload")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono upload(Flux data, long length, BlobHTTPHeaders headers, - Metadata metadata, BlobAccessConditions accessConditions) { - metadata = metadata == null ? new Metadata() : metadata; - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - return postProcessResponse(this.azureBlobStorage.blockBlobs().uploadWithRestResponseAsync(null, - null, data, length, null, metadata, null, null, - null, null, headers, accessConditions.leaseAccessConditions(), - accessConditions.modifiedAccessConditions(), Context.NONE)); - } - - /** - * Uploads the specified block to the block blob's "staging area" to be later committed by a call to - * commitBlockList. For more information, see the - * 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. - * - * @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. - * @param data - * The data to write to the block. Note that this {@code Flux} must be replayable if retries are enabled - * (the default). In other words, the Flowable must produce the same data each time it is subscribed to. - * @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 Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blocks "Sample code for BlockBlobAsyncRawClient.stageBlock")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono stageBlock(String base64BlockID, Flux data, - long length) { - return this.stageBlock(base64BlockID, data, length, null); - } - - /** - * Uploads the specified block to the block blob's "staging area" to be later committed by a call to - * commitBlockList. For more information, see the - * 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. - * - * @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. - * @param data - * The data to write to the block. Note that this {@code Flux} must be replayable if retries are enabled - * (the default). In other words, the Flowable must produce the same data each time it is subscribed to. - * @param length - * The exact length of the data. It is important that this value match precisely the length of the data - * emitted by the {@code Flux}. - * @param leaseAccessConditions - * By setting lease access conditions, requests will fail if the provided lease does not match the active - * lease on the blob. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blocks "Sample code for BlockBlobAsyncRawClient.stageBlock")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono stageBlock(String base64BlockID, Flux data, long length, - LeaseAccessConditions leaseAccessConditions) { - return postProcessResponse(this.azureBlobStorage.blockBlobs().stageBlockWithRestResponseAsync(null, - null, base64BlockID, length, data, null, null, null, - null, null, null, leaseAccessConditions, Context.NONE)); - } - - /** - * Creates a new block to be committed as part of a blob where the contents are read from a URL. For more - * information, see the Azure Docs. - * - * @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. - * @param sourceURL - * The url to the blob that will be the source of the copy. A source blob in the same storage account can be - * authenticated via Shared Key. However, if the source is a blob in another account, the source blob must - * either be public or must be authenticated via a shared access signature. If the source blob is public, no - * authentication is required to perform the operation. - * @param sourceRange - * {@link BlobRange} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=block_from_url "Sample code for BlockBlobAsyncRawClient.stageBlockFromURL")] - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono stageBlockFromURL(String base64BlockID, URL sourceURL, - BlobRange sourceRange) { - return this.stageBlockFromURL(base64BlockID, sourceURL, sourceRange, null, - null, null); - } - - /** - * Creates a new block to be committed as part of a blob where the contents are read from a URL. For more - * information, see the Azure Docs. - * - * @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. - * @param sourceURL - * The url to the blob that will be the source of the copy. A source blob in the same storage account can - * be authenticated via Shared Key. However, if the source is a blob in another account, the source blob - * must either be public or must be authenticated via a shared access signature. If the source blob is - * public, no authentication is required to perform the operation. - * @param sourceRange - * {@link BlobRange} - * @param sourceContentMD5 - * An MD5 hash of the block content from the source blob. If specified, the service will calculate the MD5 - * of the received data and fail the request if it does not match the provided MD5. - * @param leaseAccessConditions - * By setting lease access conditions, requests will fail if the provided lease does not match the active - * lease on the blob. - * @param sourceModifiedAccessConditions - * {@link SourceModifiedAccessConditions} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=block_from_url "Sample code for BlockBlobAsyncRawClient.stageBlockFromURL")] - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono stageBlockFromURL(String base64BlockID, URL sourceURL, - BlobRange sourceRange, byte[] sourceContentMD5, LeaseAccessConditions leaseAccessConditions, - SourceModifiedAccessConditions sourceModifiedAccessConditions) { - sourceRange = sourceRange == null ? new BlobRange(0) : sourceRange; - - return postProcessResponse( - this.azureBlobStorage.blockBlobs().stageBlockFromURLWithRestResponseAsync(null, null, - base64BlockID, 0, sourceURL, sourceRange.toHeaderValue(), sourceContentMD5, null, - null, null, null, null, - leaseAccessConditions, sourceModifiedAccessConditions, Context.NONE)); - } - - /** - * Returns the list of blocks that have been uploaded as part of a block blob using the specified block list filter. - * For more information, see the - * Azure Docs. - * - * @param listType - * Specifies which type of blocks to return. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blocks "Sample code for BlockBlobAsyncRawClient.listBlocks")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono listBlocks(BlockListType listType) { - return this.listBlocks(listType, null); - } - - /** - * Returns the list of blocks that have been uploaded as part of a block blob using the specified block list filter. - * For more information, see the - * Azure Docs. - * - * @param listType - * Specifies which type of blocks to return. - * @param leaseAccessConditions - * By setting lease access conditions, requests will fail if the provided lease does not match the active - * lease on the blob. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blocks "Sample code for BlockBlobAsyncRawClient.listBlocks")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono listBlocks(BlockListType listType, - LeaseAccessConditions leaseAccessConditions) { - return postProcessResponse(this.azureBlobStorage.blockBlobs().getBlockListWithRestResponseAsync( - null, null, listType, snapshot, null, null, null, - leaseAccessConditions, Context.NONE)); - } - - /** - * Writes a blob by specifying the list of block IDs that are to make up the blob. - * In order to be written as part of a blob, a block must have been successfully written - * to the server in a prior stageBlock operation. You can call commitBlockList to update a blob - * by uploading only those blocks that have changed, then committing the new and existing - * blocks together. Any blocks not specified in the block list and permanently deleted. - * For more information, see the - * Azure Docs. - *

- * - * @param base64BlockIDs - * A list of base64 encode {@code String}s that specifies the block IDs to be committed. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blocks "Sample code for BlockBlobAsyncRawClient.commitBlockList")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono commitBlockList(List base64BlockIDs) { - return this.commitBlockList(base64BlockIDs, null, null, null); - } - - /** - * Writes a blob by specifying the list of block IDs that are to make up the blob. - * In order to be written as part of a blob, a block must have been successfully written - * to the server in a prior stageBlock operation. You can call commitBlockList to update a blob - * by uploading only those blocks that have changed, then committing the new and existing - * blocks together. Any blocks not specified in the block list and permanently deleted. - * For more information, see the - * Azure Docs. - *

- * - * @param base64BlockIDs - * A list of base64 encode {@code String}s that specifies the block IDs to be committed. - * @param headers - * {@link BlobHTTPHeaders} - * @param metadata - * {@link Metadata} - * @param accessConditions - * {@link BlobAccessConditions} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blocks "Sample code for BlockBlobAsyncRawClient.commitBlockList")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono commitBlockList(List base64BlockIDs, - BlobHTTPHeaders headers, Metadata metadata, BlobAccessConditions accessConditions) { - metadata = metadata == null ? new Metadata() : metadata; - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - return postProcessResponse(this.azureBlobStorage.blockBlobs().commitBlockListWithRestResponseAsync( - null, null, new BlockLookupList().latest(base64BlockIDs), null, metadata, - null, null, null, null, headers, - accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)); - } -} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobClient.java index 9dced1f87022b..ec76f684c1bb4 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobClient.java @@ -4,7 +4,6 @@ package com.azure.storage.blob; import com.azure.core.http.rest.Response; -import com.azure.core.http.rest.SimpleResponse; import com.azure.core.http.rest.VoidResponse; import com.azure.storage.blob.models.BlobAccessConditions; import com.azure.storage.blob.models.BlobHTTPHeaders; @@ -44,22 +43,22 @@ * for more information. */ public final class BlockBlobClient extends BlobClient { + private final BlockBlobAsyncClient blockBlobAsyncClient; - private BlockBlobAsyncClient blockBlobAsyncClient; /** * Indicates the maximum number of bytes that can be sent in a call to upload. */ - public static final int MAX_UPLOAD_BLOB_BYTES = 256 * Constants.MB; + public static final int MAX_UPLOAD_BLOB_BYTES = BlockBlobAsyncClient.MAX_UPLOAD_BLOB_BYTES; /** * Indicates the maximum number of bytes that can be sent in a call to stageBlock. */ - public static final int MAX_STAGE_BLOCK_BYTES = 100 * Constants.MB; + public static final int MAX_STAGE_BLOCK_BYTES = BlockBlobAsyncClient.MAX_STAGE_BLOCK_BYTES; /** * Indicates the maximum number of blocks allowed in a block blob. */ - public static final int MAX_BLOCKS = 50000; + public static final int MAX_BLOCKS = BlockBlobAsyncClient.MAX_BLOCKS; /** * Package-private constructor for use by {@link BlockBlobClientBuilder}. @@ -161,9 +160,8 @@ public Response upload(InputStream data, long length, BlobHTTPHea return ByteBufAllocator.DEFAULT.buffer((int) count).writeBytes(cache); })); - Mono> upload = blockBlobAsyncClient.blockBlobAsyncRawClient - .upload(fbb.subscribeOn(Schedulers.elastic()), length, headers, metadata, accessConditions) - .map(rb -> new SimpleResponse<>(rb, new BlockBlobItem(rb.deserializedHeaders()))); + Mono> upload = blockBlobAsyncClient + .upload(fbb.subscribeOn(Schedulers.elastic()), length, headers, metadata, accessConditions); try { return Utility.blockWithOptionalTimeout(upload, timeout); diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java index f979f084ac151..6d9e64f16a924 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java @@ -9,6 +9,7 @@ import com.azure.core.http.rest.VoidResponse; import com.azure.core.util.Context; import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; +import com.azure.storage.blob.implementation.AzureBlobStorageImpl; import com.azure.storage.blob.models.BlobFlatListSegment; import com.azure.storage.blob.models.BlobHierarchyListSegment; import com.azure.storage.blob.models.BlobItem; @@ -33,57 +34,59 @@ import java.net.URL; import java.time.Duration; import java.time.OffsetDateTime; +import java.time.temporal.ChronoUnit; import java.util.List; +import static com.azure.storage.blob.Utility.postProcessResponse; + /** - * Client to a container. It may only be instantiated through a {@link ContainerClientBuilder} or via the method - * {@link StorageAsyncClient#getContainerAsyncClient(String)}. This class does not hold any - * state about a particular blob but is instead a convenient way of sending off appropriate requests to - * the resource on the service. It may also be used to construct URLs to blobs. + * Client to a container. It may only be instantiated through a {@link ContainerClientBuilder} or via the method {@link + * StorageAsyncClient#getContainerAsyncClient(String)}. This class does not hold any state about a particular blob but + * is instead a convenient way of sending off appropriate requests to the resource on the service. It may also be used + * to construct URLs to blobs. * *

* This client contains operations on a container. Operations on a blob are available on {@link BlobAsyncClient} through * {@link #getBlobAsyncClient(String)}, and operations on the service are available on {@link StorageAsyncClient}. * *

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

- * 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()}. + * 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()}. */ public final class ContainerAsyncClient { - ContainerAsyncRawClient containerAsyncRawClient; - public static final String ROOT_CONTAINER_NAME = "$root"; public static final String STATIC_WEBSITE_CONTAINER_NAME = "$web"; public static final String LOG_CONTAINER_NAME = "$logs"; + private final AzureBlobStorageImpl azureBlobStorage; + /** * Package-private constructor for use by {@link ContainerClientBuilder}. + * * @param azureBlobStorageBuilder the API client builder for blob storage API */ ContainerAsyncClient(AzureBlobStorageBuilder azureBlobStorageBuilder) { - this.containerAsyncRawClient = new ContainerAsyncRawClient(azureBlobStorageBuilder.build()); + this.azureBlobStorage = azureBlobStorageBuilder.build(); } /** * 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. - * - * @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. + * 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. + * + * @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); @@ -91,106 +94,95 @@ public BlockBlobAsyncClient getBlockBlobAsyncClient(String blobName) { /** * 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. - * - * @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. + * 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. + * + * @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(containerAsyncRawClient.azureBlobStorage.httpPipeline()), snapshot); + .pipeline(azureBlobStorage.httpPipeline()), snapshot); } /** - * 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. - * - * @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. + * 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. + * + * @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. - * - * @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. + * 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. + * + * @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(containerAsyncRawClient.azureBlobStorage.httpPipeline()), snapshot); + .pipeline(azureBlobStorage.httpPipeline()), snapshot); } /** - * 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 + * 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. * - * @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. + * @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 + * 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. * - * @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. + * @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(containerAsyncRawClient.azureBlobStorage.httpPipeline()), snapshot); + .pipeline(azureBlobStorage.httpPipeline()), snapshot); } /** - * Creates a new BlobAsyncClient object by concatenating blobName to the end of - * ContainerAsyncClient's URL. The new BlobAsyncClient uses the same request policy pipeline as the ContainerAsyncClient. - * To change the pipeline, create the BlobAsyncClient and then call its WithPipeline method passing in the - * desired pipeline object. Or, call this package's getBlobAsyncClient instead of calling this object's - * getBlobAsyncClient method. - * - * @param blobName - * A {@code String} representing the name of the blob. + * Creates a new BlobAsyncClient object by concatenating blobName to the end of ContainerAsyncClient's URL. The new + * BlobAsyncClient uses the same request policy pipeline as the ContainerAsyncClient. To change the pipeline, create + * the BlobAsyncClient and then call its WithPipeline method passing in the desired pipeline object. Or, call this + * package's getBlobAsyncClient instead of calling this object's getBlobAsyncClient method. * + * @param blobName A {@code String} representing the name of the blob. * @return A new {@link BlobAsyncClient} object which references the blob with the specified name in this container. */ public BlobAsyncClient getBlobAsyncClient(String blobName) { @@ -198,55 +190,50 @@ public BlobAsyncClient getBlobAsyncClient(String blobName) { } /** - * Creates a new BlobAsyncClient object by concatenating blobName to the end of - * ContainerAsyncClient's URL. The new BlobAsyncClient uses the same request policy pipeline as the ContainerAsyncClient. - * To change the pipeline, create the BlobAsyncClient and then call its WithPipeline method passing in the - * desired pipeline object. Or, call this package's getBlobAsyncClient instead of calling this object's - * getBlobAsyncClient method. - * - * @param blobName - * A {@code String} representing the name of the blob. - * @param snapshot - * the snapshot identifier for the blob. + * Creates a new BlobAsyncClient object by concatenating blobName to the end of ContainerAsyncClient's URL. The new + * BlobAsyncClient uses the same request policy pipeline as the ContainerAsyncClient. To change the pipeline, create + * the BlobAsyncClient and then call its WithPipeline method passing in the desired pipeline object. Or, call this + * package's getBlobAsyncClient instead of calling this object's getBlobAsyncClient method. * + * @param blobName A {@code String} representing the name of the blob. + * @param snapshot the snapshot identifier for the blob. * @return A new {@link BlobAsyncClient} object which references the blob with the specified name in this container. */ public BlobAsyncClient getBlobAsyncClient(String blobName, String snapshot) { return new BlobAsyncClient(new AzureBlobStorageBuilder() .url(Utility.appendToURLPath(getContainerUrl(), blobName).toString()) - .pipeline(containerAsyncRawClient.azureBlobStorage.httpPipeline()), snapshot); + .pipeline(azureBlobStorage.httpPipeline()), snapshot); } /** * Initializes a {@link StorageAsyncClient} object pointing to the storage account this container is in. * - * @return - * A {@link StorageAsyncClient} object pointing to the specified storage account + * @return A {@link StorageAsyncClient} object pointing to the specified storage account */ public StorageAsyncClient getStorageAsyncClient() { return new StorageAsyncClient(new AzureBlobStorageBuilder() .url(Utility.stripLastPathSegment(getContainerUrl()).toString()) - .pipeline(containerAsyncRawClient.azureBlobStorage.httpPipeline())); + .pipeline(azureBlobStorage.httpPipeline())); } /** * Gets the URL of the container represented by this client. + * * @return the URL. * @throws RuntimeException If the container has a malformed URL. */ public URL getContainerUrl() { try { - return new URL(containerAsyncRawClient.azureBlobStorage.url()); + return new URL(azureBlobStorage.url()); } catch (MalformedURLException e) { - throw new RuntimeException(String.format("Invalid URL on %s: %s" + getClass().getSimpleName(), containerAsyncRawClient.azureBlobStorage.url()), e); + throw new RuntimeException(String.format("Invalid URL on %s: %s" + getClass().getSimpleName(), azureBlobStorage.url()), e); } } /** * Gets if the container this client represents exists in the cloud. * - * @return - * true if the container exists, false if it doesn't + * @return true if the container exists, false if it doesn't */ public Mono> exists() { return this.getProperties(null) @@ -262,8 +249,7 @@ public Mono> exists() { * fails. For more information, see the * Azure Docs. * - * @return - * A reactive response signalling completion. + * @return A reactive response signalling completion. */ public Mono create() { return this.create(null, null); @@ -274,47 +260,52 @@ public Mono create() { * fails. For more information, see the * Azure Docs. * - * @param metadata - * {@link Metadata} - * @param accessType - * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header - * in the Azure Docs for more information. Pass null for no public access. - * - * @return - * A reactive response signalling completion. + * @param metadata {@link Metadata} + * @param accessType Specifies how the data in this container is available to the public. See the + * x-ms-blob-public-access header in the Azure Docs for more information. Pass null for no public access. + * @return A reactive response signalling completion. */ public Mono create(Metadata metadata, PublicAccessType accessType) { - return containerAsyncRawClient - .create(metadata, accessType) + metadata = metadata == null ? new Metadata() : metadata; + + return postProcessResponse(this.azureBlobStorage.containers().createWithRestResponseAsync( + null, null, metadata, accessType, null, Context.NONE)) .map(VoidResponse::new); } /** - * Marks the specified container for deletion. The container and any blobs contained within it are later - * deleted during garbage collection. For more information, see the + * Marks the specified container for deletion. The container and any blobs contained within it are later deleted + * during garbage collection. For more information, see the * Azure Docs. * - * @return - * A reactive response signalling completion. + * @return A reactive response signalling completion. */ public Mono delete() { return this.delete(null); } /** - * Marks the specified container for deletion. The container and any blobs contained within it are later - * deleted during garbage collection. For more information, see the + * Marks the specified container for deletion. The container and any blobs contained within it are later deleted + * during garbage collection. For more information, see the * Azure Docs. * - * @param accessConditions - * {@link ContainerAccessConditions} - * - * @return - * A reactive response signalling completion. + * @param accessConditions {@link ContainerAccessConditions} + * @return A reactive response signalling completion. + * @throws UnsupportedOperationException If {@link ContainerAccessConditions#modifiedAccessConditions()} has either + * {@link ModifiedAccessConditions#ifMatch()} or {@link ModifiedAccessConditions#ifNoneMatch()} set. */ public Mono delete(ContainerAccessConditions accessConditions) { - return containerAsyncRawClient - .delete(accessConditions) + accessConditions = accessConditions == null ? new ContainerAccessConditions() : accessConditions; + + if (!validateNoEtag(accessConditions.modifiedAccessConditions())) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new UnsupportedOperationException("ETag access conditions are not supported for this API."); + } + + return postProcessResponse(this.azureBlobStorage.containers() + .deleteWithRestResponseAsync(null, null, null, + accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)) .map(VoidResponse::new); } @@ -322,8 +313,7 @@ public Mono delete(ContainerAccessConditions accessConditions) { * Returns the container's metadata and system properties. For more information, see the * Azure Docs. * - * @return - * A reactive response containing the container properties. + * @return A reactive response containing the container properties. */ public Mono> getProperties() { return this.getProperties(null); @@ -333,16 +323,14 @@ public Mono> getProperties() { * Returns the container's metadata and system properties. For more information, see the * Azure Docs. * - * @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 containing the container properties. + * @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 containing the container properties. */ public Mono> getProperties(LeaseAccessConditions leaseAccessConditions) { - return containerAsyncRawClient - .getProperties(leaseAccessConditions) + return postProcessResponse(this.azureBlobStorage.containers() + .getPropertiesWithRestResponseAsync(null, null, null, + leaseAccessConditions, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, new ContainerProperties(rb.deserializedHeaders()))); } @@ -350,11 +338,8 @@ public Mono> getProperties(LeaseAccessConditions l * Sets the container's metadata. For more information, see the * Azure Docs. * - * @param metadata - * {@link Metadata} - * - * @return - * A reactive response signalling completion. + * @param metadata {@link Metadata} + * @return A reactive response signalling completion. */ public Mono setMetadata(Metadata metadata) { return this.setMetadata(metadata, null); @@ -364,18 +349,27 @@ public Mono setMetadata(Metadata metadata) { * Sets the container's metadata. For more information, see the * Azure Docs. * - * @param metadata - * {@link Metadata} - * @param accessConditions - * {@link ContainerAccessConditions} - * - * @return - * A reactive response signalling completion. + * @param metadata {@link Metadata} + * @param accessConditions {@link ContainerAccessConditions} + * @return A reactive response signalling completion. + * @throws UnsupportedOperationException If {@link ContainerAccessConditions#modifiedAccessConditions()} has + * anything set other than {@link ModifiedAccessConditions#ifModifiedSince()}. */ public Mono setMetadata(Metadata metadata, - ContainerAccessConditions accessConditions) { - return containerAsyncRawClient - .setMetadata(metadata, accessConditions) + ContainerAccessConditions accessConditions) { + metadata = metadata == null ? new Metadata() : metadata; + accessConditions = accessConditions == null ? new ContainerAccessConditions() : accessConditions; + if (!validateNoEtag(accessConditions.modifiedAccessConditions()) + || accessConditions.modifiedAccessConditions().ifUnmodifiedSince() != null) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new UnsupportedOperationException( + "If-Modified-Since is the only HTTP access condition supported for this API"); + } + + return postProcessResponse(this.azureBlobStorage.containers() + .setMetadataWithRestResponseAsync(null, null, metadata, null, + accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)) .map(VoidResponse::new); } @@ -384,8 +378,7 @@ public Mono setMetadata(Metadata metadata, * For more information, see the * Azure Docs. * - * @return - * A reactive response containing the container access policy. + * @return A reactive response containing the container access policy. */ public Mono> getAccessPolicy() { return this.getAccessPolicy(null); @@ -396,15 +389,13 @@ public Mono> getAccessPolicy() { * For more information, see the * Azure Docs. * - * @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 containing the container access policy. + * @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 containing the container access policy. */ public Mono> getAccessPolicy(LeaseAccessConditions leaseAccessConditions) { - return containerAsyncRawClient.getAccessPolicy(leaseAccessConditions); + return postProcessResponse(this.azureBlobStorage.containers().getAccessPolicyWithRestResponseAsync(null, null, null, leaseAccessConditions, Context.NONE) + .map(response -> new SimpleResponse<>(response, new ContainerAccessPolicies(response.deserializedHeaders().blobPublicAccess(), response.value())))); } /** @@ -413,19 +404,16 @@ public Mono> getAccessPolicy(LeaseAccessCondit * ensure the time formatting is compatible with the service. For more information, see the * Azure Docs. * - * @param accessType - * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header - * in the Azure Docs for more information. Pass null for no public access. - * @param identifiers - * A list of {@link SignedIdentifier} objects that specify the permissions for the container. Please see - * here - * for more information. Passing null will clear all access policies. - * - * @return - * A reactive response signalling completion. + * @param accessType Specifies how the data in this container is available to the public. See the + * x-ms-blob-public-access header in the Azure Docs for more information. Pass null for no public access. + * @param identifiers A list of {@link SignedIdentifier} objects that specify the permissions for the container. + * Please see + * here + * for more information. Passing null will clear all access policies. + * @return A reactive response signalling completion. */ public Mono setAccessPolicy(PublicAccessType accessType, - List identifiers) { + List identifiers) { return this.setAccessPolicy(accessType, identifiers, null); } @@ -435,79 +423,129 @@ public Mono setAccessPolicy(PublicAccessType accessType, * ensure the time formatting is compatible with the service. For more information, see the * Azure Docs. * - * @param accessType - * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header - * in the Azure Docs for more information. Pass null for no public access. - * @param identifiers - * A list of {@link SignedIdentifier} objects that specify the permissions for the container. Please see - * here - * for more information. Passing null will clear all access policies. - * @param accessConditions - * {@link ContainerAccessConditions} - * - * @return - * A reactive response signalling completion. + * @param accessType Specifies how the data in this container is available to the public. See the + * x-ms-blob-public-access header in the Azure Docs for more information. Pass null for no public access. + * @param identifiers A list of {@link SignedIdentifier} objects that specify the permissions for the container. + * Please see + * here + * for more information. Passing null will clear all access policies. + * @param accessConditions {@link ContainerAccessConditions} + * @return A reactive response signalling completion. + * @throws UnsupportedOperationException If {@link ContainerAccessConditions#modifiedAccessConditions()} has either + * {@link ModifiedAccessConditions#ifMatch()} or {@link ModifiedAccessConditions#ifNoneMatch()} set. */ public Mono setAccessPolicy(PublicAccessType accessType, - List identifiers, ContainerAccessConditions accessConditions) { - return containerAsyncRawClient - .setAccessPolicy(accessType, identifiers, accessConditions) + List identifiers, ContainerAccessConditions accessConditions) { + accessConditions = accessConditions == null ? new ContainerAccessConditions() : accessConditions; + + if (!validateNoEtag(accessConditions.modifiedAccessConditions())) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new UnsupportedOperationException("ETag access conditions are not supported for this API."); + } + + /* + We truncate to seconds because the service only supports nanoseconds or seconds, but doing an + OffsetDateTime.now will only give back milliseconds (more precise fields are zeroed and not serialized). This + allows for proper serialization with no real detriment to users as sub-second precision on active time for + signed identifiers is not really necessary. + */ + if (identifiers != null) { + for (SignedIdentifier identifier : identifiers) { + if (identifier.accessPolicy() != null && identifier.accessPolicy().start() != null) { + identifier.accessPolicy().start( + identifier.accessPolicy().start().truncatedTo(ChronoUnit.SECONDS)); + } + if (identifier.accessPolicy() != null && identifier.accessPolicy().expiry() != null) { + identifier.accessPolicy().expiry( + identifier.accessPolicy().expiry().truncatedTo(ChronoUnit.SECONDS)); + } + } + } + + return postProcessResponse(this.azureBlobStorage.containers() + .setAccessPolicyWithRestResponseAsync(null, identifiers, null, accessType, + null, accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), + Context.NONE)) .map(VoidResponse::new); } /** - * Returns a reactive Publisher emitting all the blobs in this container lazily as needed. - * The directories are flattened and only actual blobs and no directories are returned. + * Returns a reactive Publisher emitting all the blobs in this container lazily as needed. The directories are + * flattened and only actual blobs and no directories are returned. * *

* Blob names are returned in lexicographic order. For more information, see the * Azure Docs. * *

- * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob - * on the root level 'bar', will return + * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob on the + * root level 'bar', will return * *

    - *
  • foo/foo1 - *
  • foo/foo2 - *
  • bar + *
  • foo/foo1 + *
  • foo/foo2 + *
  • bar *
* - * @return - * A reactive response emitting the flattened blobs. + * @return A reactive response emitting the flattened blobs. */ public Flux listBlobsFlat() { return this.listBlobsFlat(new ListBlobsOptions()); } /** - * Returns a reactive Publisher emitting all the blobs in this container lazily as needed. - * The directories are flattened and only actual blobs and no directories are returned. + * Returns a reactive Publisher emitting all the blobs in this container lazily as needed. The directories are + * flattened and only actual blobs and no directories are returned. * *

* Blob names are returned in lexicographic order. For more information, see the * Azure Docs. * *

- * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob - * on the root level 'bar', will return + * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob on the + * root level 'bar', will return * *

    - *
  • foo/foo1 - *
  • foo/foo2 - *
  • bar + *
  • foo/foo1 + *
  • foo/foo2 + *
  • bar *
* + * @param options {@link ListBlobsOptions} + * @return A reactive response emitting the listed blobs, flattened. + */ + public Flux listBlobsFlat(ListBlobsOptions options) { + return listBlobsFlatSegment(null, options).flatMapMany(response -> listBlobsFlatHelper(options, response)); + } + + /* + * Returns a single segment of blobs starting from the specified Marker. Use an empty + * marker to start enumeration from the beginning. Blob names are returned in lexicographic order. + * After getting a segment, process it, and then call ListBlobs again (passing the the previously-returned + * Marker) to get the next segment. For more information, see the + * Azure Docs. + * + * @param marker + * Identifies the portion of the list to be returned with the next list operation. + * This value is returned in the response of a previous list operation as the + * ListBlobsFlatSegmentResponse.body().nextMarker(). Set to null to list the first segment. * @param options * {@link ListBlobsOptions} * - * @return - * A reactive response emitting the listed blobs, flattened. + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_flat "Sample code for ContainerAsyncClient.listBlobsFlatSegment")] \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_flat_helper "helper code for ContainerAsyncClient.listBlobsFlatSegment")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) */ - public Flux listBlobsFlat(ListBlobsOptions options) { - return containerAsyncRawClient - .listBlobsFlatSegment(null, options) - .flatMapMany(response -> listBlobsFlatHelper(options, response)); + private Mono listBlobsFlatSegment(String marker, ListBlobsOptions options) { + options = options == null ? new ListBlobsOptions() : options; + + return postProcessResponse(this.azureBlobStorage.containers() + .listBlobFlatSegmentWithRestResponseAsync(null, options.prefix(), marker, + options.maxResults(), options.details().toList(), null, null, Context.NONE)); } private Flux listBlobsFlatHelper(ListBlobsOptions options, ContainersListBlobFlatSegmentResponse response) { @@ -521,7 +559,7 @@ private Flux listBlobsFlatHelper(ListBlobsOptions options, ContainersL if (response.value().nextMarker() != null) { // Recursively add the continuation items to the observable. - result = result.concatWith(containerAsyncRawClient.listBlobsFlatSegment(response.value().nextMarker(), options) + result = result.concatWith(listBlobsFlatSegment(response.value().nextMarker(), options) .flatMapMany(r -> listBlobsFlatHelper(options, r))); } @@ -529,80 +567,109 @@ private Flux listBlobsFlatHelper(ListBlobsOptions options, ContainersL } /** - * Returns a reactive Publisher emitting all the blobs and directories (prefixes) under - * the given directory (prefix). Directories will have {@link BlobItem#isPrefix()} set to - * true. + * Returns a reactive Publisher emitting all the blobs and directories (prefixes) under the given directory + * (prefix). Directories will have {@link BlobItem#isPrefix()} set to true. * *

* Blob names are returned in lexicographic order. For more information, see the * Azure Docs. * *

- * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob - * on the root level 'bar', will return the following results when prefix=null: + * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob on the + * root level 'bar', will return the following results when prefix=null: * *

    - *
  • foo/ (isPrefix = true) - *
  • bar (isPrefix = false) + *
  • foo/ (isPrefix = true) + *
  • bar (isPrefix = false) *
*

* will return the following results when prefix="foo/": * *

    - *
  • foo/foo1 (isPrefix = false) - *
  • foo/foo2 (isPrefix = false) + *
  • foo/foo1 (isPrefix = false) + *
  • foo/foo2 (isPrefix = false) *
* - * @param directory - * The directory to list blobs underneath - * - * @return - * A reactive response emitting the prefixes and blobs. + * @param directory The directory to list blobs underneath + * @return A reactive response emitting the prefixes and blobs. */ public Flux listBlobsHierarchy(String directory) { return this.listBlobsHierarchy("/", new ListBlobsOptions().prefix(directory)); } /** - * Returns a reactive Publisher emitting all the blobs and prefixes (directories) under - * the given prefix (directory). Directories will have {@link BlobItem#isPrefix()} set to - * true. + * Returns a reactive Publisher emitting all the blobs and prefixes (directories) under the given prefix + * (directory). Directories will have {@link BlobItem#isPrefix()} set to true. * *

* Blob names are returned in lexicographic order. For more information, see the * Azure Docs. * *

- * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob - * on the root level 'bar', will return the following results when prefix=null: + * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob on the + * root level 'bar', will return the following results when prefix=null: * *

    - *
  • foo/ (isPrefix = true) - *
  • bar (isPrefix = false) + *
  • foo/ (isPrefix = true) + *
  • bar (isPrefix = false) *
*

* will return the following results when prefix="foo/": * *

    - *
  • foo/foo1 (isPrefix = false) - *
  • foo/foo2 (isPrefix = false) + *
  • foo/foo1 (isPrefix = false) + *
  • foo/foo2 (isPrefix = false) *
* + * @param delimiter The delimiter for blob hierarchy, "/" for hierarchy based on directories + * @param options {@link ListBlobsOptions} + * @return A reactive response emitting the prefixes and blobs. + */ + public Flux listBlobsHierarchy(String delimiter, ListBlobsOptions options) { + return listBlobsHierarchySegment(null, delimiter, options) + .flatMapMany(response -> listBlobsHierarchyHelper(delimiter, options, Context.NONE, response)); + } + + /* + * Returns a single segment of blobs and blob prefixes starting from the specified Marker. Use an empty + * marker to start enumeration from the beginning. Blob names are returned in lexicographic order. + * After getting a segment, process it, and then call ListBlobs again (passing the the previously-returned + * Marker) to get the next segment. For more information, see the + * Azure Docs. + * + * @param marker + * Identifies the portion of the list to be returned with the next list operation. + * This value is returned in the response of a previous list operation as the + * ListBlobsHierarchySegmentResponse.body().nextMarker(). Set to null to list the first segment. * @param delimiter - * The delimiter for blob hierarchy, "/" for hierarchy based on directories + * The operation returns a BlobPrefix element in the response body that acts as a placeholder for all blobs + * whose names begin with the same substring up to the appearance of the delimiter character. The delimiter may + * be a single character or a string. * @param options * {@link ListBlobsOptions} * - * @return - * A reactive response emitting the prefixes and blobs. + * @return Emits the successful response. + * @throws UnsupportedOperationException If {@link ListBlobsOptions#details()} has {@link BlobListDetails#snapshots()} + * set. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy "Sample code for ContainerAsyncClient.listBlobsHierarchySegment")] \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy_helper "helper code for ContainerAsyncClient.listBlobsHierarchySegment")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) */ - public Flux listBlobsHierarchy(String delimiter, ListBlobsOptions options) { - return containerAsyncRawClient.listBlobsHierarchySegment(null, delimiter, options) - .flatMapMany(response -> listBlobsHierarchyHelper(delimiter, options, Context.NONE, response)); + private Mono listBlobsHierarchySegment(String marker, String delimiter, ListBlobsOptions options) { + options = options == null ? new ListBlobsOptions() : options; + if (options.details().snapshots()) { + throw new UnsupportedOperationException("Including snapshots in a hierarchical listing is not supported."); + } + + return postProcessResponse(this.azureBlobStorage.containers() + .listBlobHierarchySegmentWithRestResponseAsync(null, delimiter, options.prefix(), marker, + options.maxResults(), options.details().toList(), null, null, Context.NONE)); } private Flux listBlobsHierarchyHelper(String delimiter, ListBlobsOptions options, - Context context, ContainersListBlobHierarchySegmentResponse response) { + Context context, ContainersListBlobHierarchySegmentResponse response) { Flux blobs; Flux prefixes; BlobHierarchyListSegment segment = response.value().segment(); @@ -620,7 +687,7 @@ private Flux listBlobsHierarchyHelper(String delimiter, ListBlobsOptio if (response.value().nextMarker() != null) { // Recursively add the continuation items to the observable. - result = result.concatWith(containerAsyncRawClient.listBlobsHierarchySegment(response.value().nextMarker(), delimiter, options) + result = result.concatWith(listBlobsHierarchySegment(response.value().nextMarker(), delimiter, options) .flatMapMany(r -> listBlobsHierarchyHelper(delimiter, options, context, r))); } @@ -699,14 +766,10 @@ private Flux listBlobsHierarchyHelper(String delimiter, ListBlobsOptio * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 * seconds, or infinite (-1). * - * @param proposedId - * A {@code String} in any valid GUID format. May be null. - * @param duration - * The duration of the lease, in seconds, or negative one (-1) for a lease that - * never expires. A non-infinite lease can be between 15 and 60 seconds. - * - * @return - * A reactive response containing the lease ID. + * @param proposedId A {@code String} in any valid GUID format. May be null. + * @param duration The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A + * non-infinite lease can be between 15 and 60 seconds. + * @return A reactive response containing the lease ID. */ public Mono> acquireLease(String proposedId, int duration) { return this.acquireLease(proposedId, duration, null); @@ -716,33 +779,34 @@ public Mono> acquireLease(String proposedId, int duration) { * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 * seconds, or infinite (-1). * - * @param proposedID - * A {@code String} in any valid GUID format. May be null. - * @param duration - * The duration of the lease, in seconds, or negative one (-1) for a lease that - * never expires. A non-infinite lease can be between 15 and 60 seconds. - * @param modifiedAccessConditions - * 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. - * - * @return - * A reactive response containing the lease ID. + * @param proposedID A {@code String} in any valid GUID format. May be null. + * @param duration The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A + * non-infinite lease can be between 15 and 60 seconds. + * @param modifiedAccessConditions 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. + * @return A reactive response containing the lease ID. + * @throws UnsupportedOperationException If either {@link ModifiedAccessConditions#ifMatch()} or {@link + * ModifiedAccessConditions#ifNoneMatch()} is set. */ public Mono> acquireLease(String proposedID, int duration, ModifiedAccessConditions modifiedAccessConditions) { - return containerAsyncRawClient - .acquireLease(proposedID, duration, modifiedAccessConditions) + if (!this.validateNoEtag(modifiedAccessConditions)) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new UnsupportedOperationException( + "ETag access conditions are not supported for this API."); + } + + return postProcessResponse(this.azureBlobStorage.containers().acquireLeaseWithRestResponseAsync( + null, null, duration, proposedID, null, modifiedAccessConditions, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseId())); } /** * Renews the blob's previously-acquired lease. * - * @param leaseID - * The leaseId of the active lease on the blob. - * - * @return - * A reactive response containing the renewed lease ID. + * @param leaseID The leaseId of the active lease on the blob. + * @return A reactive response containing the renewed lease ID. */ public Mono> renewLease(String leaseID) { return this.renewLease(leaseID, null); @@ -751,30 +815,32 @@ public Mono> renewLease(String leaseID) { /** * Renews the blob's previously-acquired lease. * - * @param leaseID - * The leaseId of the active lease on the blob. - * @param modifiedAccessConditions - * 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. - * - * @return - * A reactive response containing the renewed lease ID. + * @param leaseID The leaseId of the active lease on the blob. + * @param modifiedAccessConditions 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. + * @return A reactive response containing the renewed lease ID. + * @throws UnsupportedOperationException If either {@link ModifiedAccessConditions#ifMatch()} or {@link + * ModifiedAccessConditions#ifNoneMatch()} is set. */ public Mono> renewLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions) { - return containerAsyncRawClient - .renewLease(leaseID, modifiedAccessConditions) + if (!this.validateNoEtag(modifiedAccessConditions)) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new UnsupportedOperationException( + "ETag access conditions are not supported for this API."); + } + + return postProcessResponse(this.azureBlobStorage.containers().renewLeaseWithRestResponseAsync(null, + leaseID, null, null, modifiedAccessConditions, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseId())); } /** * Releases the blob's previously-acquired lease. * - * @param leaseID - * The leaseId of the active lease on the blob. - * - * @return - * A reactive response signalling completion. + * @param leaseID The leaseId of the active lease on the blob. + * @return A reactive response signalling completion. */ public Mono releaseLease(String leaseID) { return this.releaseLease(leaseID, null); @@ -783,19 +849,24 @@ public Mono releaseLease(String leaseID) { /** * Releases the blob's previously-acquired lease. * - * @param leaseID - * The leaseId of the active lease on the blob. - * @param modifiedAccessConditions - * 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. - * - * @return - * A reactive response signalling completion. + * @param leaseID The leaseId of the active lease on the blob. + * @param modifiedAccessConditions 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. + * @return A reactive response signalling completion. + * @throws UnsupportedOperationException If either {@link ModifiedAccessConditions#ifMatch()} or {@link + * ModifiedAccessConditions#ifNoneMatch()} is set. */ public Mono releaseLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions) { - return containerAsyncRawClient - .releaseLease(leaseID, modifiedAccessConditions) + if (!this.validateNoEtag(modifiedAccessConditions)) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new UnsupportedOperationException( + "ETag access conditions are not supported for this API."); + } + + return postProcessResponse(this.azureBlobStorage.containers().releaseLeaseWithRestResponseAsync( + null, leaseID, null, null, modifiedAccessConditions, Context.NONE)) .map(VoidResponse::new); } @@ -803,8 +874,7 @@ public Mono releaseLease(String leaseID, ModifiedAccessConditions * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant * to break a fixed-duration lease when it expires or an infinite lease immediately. * - * @return - * A reactive response containing the remaining time in the broken lease. + * @return A reactive response containing the remaining time in the broken lease. */ public Mono> breakLease() { return this.breakLease(null, null); @@ -814,58 +884,65 @@ public Mono> breakLease() { * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant * to break a fixed-duration lease when it expires or an infinite lease immediately. * - * @param breakPeriodInSeconds - * An optional {@code Integer} representing the proposed duration of seconds that the lease should continue - * before it is broken, between 0 and 60 seconds. This break period is only used if it is shorter than the - * time remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be - * available before the break period has expired, but the lease may be held for longer than the break - * period. - * @param modifiedAccessConditions - * 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. - * - * @return - * A reactive response containing the remaining time in the broken lease. + * @param breakPeriodInSeconds An optional {@code Integer} representing the proposed duration of seconds that the + * lease should continue before it is broken, between 0 and 60 seconds. This break period is only used if it is + * shorter than the time remaining on the lease. If longer, the time remaining on the lease is used. A new lease + * will not be available before the break period has expired, but the lease may be held for longer than the break + * period. + * @param modifiedAccessConditions 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. + * @return A reactive response containing the remaining time in the broken lease. + * @throws UnsupportedOperationException If either {@link ModifiedAccessConditions#ifMatch()} or {@link + * ModifiedAccessConditions#ifNoneMatch()} is set. */ public Mono> breakLease(Integer breakPeriodInSeconds, ModifiedAccessConditions modifiedAccessConditions) { - return containerAsyncRawClient - .breakLease(breakPeriodInSeconds, modifiedAccessConditions) + if (!this.validateNoEtag(modifiedAccessConditions)) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new UnsupportedOperationException( + "ETag access conditions are not supported for this API."); + } + + return postProcessResponse(this.azureBlobStorage.containers().breakLeaseWithRestResponseAsync(null, + null, breakPeriodInSeconds, null, modifiedAccessConditions, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, Duration.ofSeconds(rb.deserializedHeaders().leaseTime()))); } /** * ChangeLease changes the blob's lease ID. * - * @param leaseId - * The leaseId of the active lease on the blob. - * @param proposedID - * A {@code String} in any valid GUID format. - * - * @return - * A reactive response containing the new lease ID. + * @param leaseId The leaseId of the active lease on the blob. + * @param proposedID A {@code String} in any valid GUID format. + * @return A reactive response containing the new lease ID. */ public Mono> changeLease(String leaseId, String proposedID) { return this.changeLease(leaseId, proposedID, null); } /** - * ChangeLease changes the blob's lease ID. For more information, see the Azure Docs. - * - * @param leaseId - * The leaseId of the active lease on the blob. - * @param proposedID - * A {@code String} in any valid GUID format. - * @param modifiedAccessConditions - * 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. - * + * ChangeLease changes the blob's lease ID. For more information, see the Azure + * Docs. + * + * @param leaseId The leaseId of the active lease on the blob. + * @param proposedID A {@code String} in any valid GUID format. + * @param modifiedAccessConditions 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. * @return A reactive response containing the new lease ID. + * @throws UnsupportedOperationException If either {@link ModifiedAccessConditions#ifMatch()} or {@link + * ModifiedAccessConditions#ifNoneMatch()} is set. */ public Mono> changeLease(String leaseId, String proposedID, ModifiedAccessConditions modifiedAccessConditions) { - return containerAsyncRawClient - .changeLease(leaseId, proposedID, modifiedAccessConditions) + if (!this.validateNoEtag(modifiedAccessConditions)) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new UnsupportedOperationException( + "ETag access conditions are not supported for this API."); + } + + return postProcessResponse(this.azureBlobStorage.containers().changeLeaseWithRestResponseAsync(null, + leaseId, proposedID, null, null, modifiedAccessConditions, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseId())); } @@ -873,63 +950,52 @@ public Mono> changeLease(String leaseId, String proposedID, Mod * Returns the sku name and account kind for the account. For more information, please see the * Azure Docs. * - * @return - * A reactive response containing the account info. + * @return A reactive response containing the account info. */ public Mono> getAccountInfo() { - return containerAsyncRawClient - .getAccountInfo() + return postProcessResponse( + this.azureBlobStorage.containers().getAccountInfoWithRestResponseAsync(null, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, new StorageAccountInfo(rb.deserializedHeaders()))); } + private boolean validateNoEtag(ModifiedAccessConditions modifiedAccessConditions) { + if (modifiedAccessConditions == null) { + return true; + } + return modifiedAccessConditions.ifMatch() == null && modifiedAccessConditions.ifNoneMatch() == null; + } + /** * 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 + * @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, - ContainerSASPermission 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 */); + ContainerSASPermission permissions, OffsetDateTime expiryTime) { + return this.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime, null, null, + null, null, null, null, null, null, null); } /** * 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 + * @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, - ContainerSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, - SASProtocol sasProtocol, IPRange ipRange) { + ContainerSASPermission 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 */); @@ -938,40 +1004,25 @@ public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, Str /** * 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 - * @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 + * @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 + * @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, - ContainerSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, - SASProtocol sasProtocol, IPRange ipRange, String cacheControl, String contentDisposition, - String contentEncoding, String contentLanguage, String contentType) { + ContainerSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, + SASProtocol sasProtocol, IPRange ipRange, String cacheControl, String contentDisposition, + String contentEncoding, String contentLanguage, String contentType) { ServiceSASSignatureValues serviceSASSignatureValues = new ServiceSASSignatureValues(version, sasProtocol, startTime, expiryTime, permissions == null ? null : permissions.toString(), ipRange, null /* identifier*/, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); @@ -986,13 +1037,9 @@ public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, Str /** * Generates a SAS token with the specified parameters * - * @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 + * @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 generateSAS(ContainerSASPermission permissions, OffsetDateTime expiryTime) { return this.generateSAS(null, permissions, /* identifier */ expiryTime, null /* startTime */, null /* version @@ -1003,11 +1050,8 @@ public String generateSAS(ContainerSASPermission permissions, OffsetDateTime exp /** * 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 + * @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 @@ -1018,27 +1062,18 @@ public String generateSAS(String 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 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 + * @param identifier The {@code String} name of the access policy on the container this SAS references if any + * @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 generateSAS(String identifier, ContainerSASPermission permissions, OffsetDateTime expiryTime, - OffsetDateTime startTime, - String version, SASProtocol sasProtocol, IPRange ipRange) { + OffsetDateTime startTime, + String version, SASProtocol sasProtocol, IPRange ipRange) { return this.generateSAS(identifier, permissions, expiryTime, startTime, version, sasProtocol, ipRange, null /* cacheControl */, null /* contentDisposition */, null /* contentEncoding */, null /* contentLanguage */, null /*contentType*/); @@ -1047,43 +1082,29 @@ public String generateSAS(String identifier, ContainerSASPermission permissions, /** * 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 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 - * @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 + * @param identifier The {@code String} name of the access policy on the container this SAS references if any + * @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 + * @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, ContainerSASPermission permissions, OffsetDateTime expiryTime, - OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange, String cacheControl, - String contentDisposition, String contentEncoding, String contentLanguage, String contentType) { + OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange, String cacheControl, + String contentDisposition, String contentEncoding, String contentLanguage, String contentType) { ServiceSASSignatureValues serviceSASSignatureValues = new ServiceSASSignatureValues(version, sasProtocol, startTime, expiryTime, permissions == null ? null : permissions.toString(), ipRange, identifier, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); SharedKeyCredential sharedKeyCredential = - Utility.getSharedKeyCredential(this.containerAsyncRawClient.azureBlobStorage.httpPipeline()); + Utility.getSharedKeyCredential(this.azureBlobStorage.httpPipeline()); Utility.assertNotNull("sharedKeyCredential", sharedKeyCredential); @@ -1100,7 +1121,7 @@ public String generateSAS(String identifier, ContainerSASPermission permissions, */ private ServiceSASSignatureValues configureServiceSASSignatureValues(ServiceSASSignatureValues serviceSASSignatureValues, String accountName) { // Set canonical name - serviceSASSignatureValues.canonicalName(this.containerAsyncRawClient.azureBlobStorage.url(), accountName); + serviceSASSignatureValues.canonicalName(this.azureBlobStorage.url(), accountName); // Set snapshotId to null serviceSASSignatureValues.snapshotId(null); diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncRawClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncRawClient.java deleted file mode 100644 index e4106549b208c..0000000000000 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncRawClient.java +++ /dev/null @@ -1,708 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.storage.blob; - -import com.azure.core.http.rest.Response; -import com.azure.core.http.rest.SimpleResponse; -import com.azure.core.util.Context; -import com.azure.storage.blob.implementation.AzureBlobStorageImpl; -import com.azure.storage.blob.models.BlobListDetails; -import com.azure.storage.blob.models.ContainerAccessConditions; -import com.azure.storage.blob.models.ContainerAccessPolicies; -import com.azure.storage.blob.models.ContainersAcquireLeaseResponse; -import com.azure.storage.blob.models.ContainersBreakLeaseResponse; -import com.azure.storage.blob.models.ContainersChangeLeaseResponse; -import com.azure.storage.blob.models.ContainersCreateResponse; -import com.azure.storage.blob.models.ContainersDeleteResponse; -import com.azure.storage.blob.models.ContainersGetAccountInfoResponse; -import com.azure.storage.blob.models.ContainersGetPropertiesResponse; -import com.azure.storage.blob.models.ContainersListBlobFlatSegmentResponse; -import com.azure.storage.blob.models.ContainersListBlobHierarchySegmentResponse; -import com.azure.storage.blob.models.ContainersReleaseLeaseResponse; -import com.azure.storage.blob.models.ContainersRenewLeaseResponse; -import com.azure.storage.blob.models.ContainersSetAccessPolicyResponse; -import com.azure.storage.blob.models.ContainersSetMetadataResponse; -import com.azure.storage.blob.models.LeaseAccessConditions; -import com.azure.storage.blob.models.ListBlobsOptions; -import com.azure.storage.blob.models.Metadata; -import com.azure.storage.blob.models.ModifiedAccessConditions; -import com.azure.storage.blob.models.PublicAccessType; -import com.azure.storage.blob.models.SignedIdentifier; -import reactor.core.publisher.Mono; - -import java.time.temporal.ChronoUnit; -import java.util.List; - -import static com.azure.storage.blob.Utility.postProcessResponse; - -/** - * Represents a URL to a container. It may be obtained by direct construction or via the create method on a - * {@link StorageAsyncRawClient} object. This class does not hold any state about a particular blob but is instead a convenient way - * of sending off appropriate requests to the resource on the service. It may also be used to construct URLs to blobs. - * Please refer to the - * Azure Docs - * for more information on containers. - */ -final class ContainerAsyncRawClient { - - public static final String ROOT_CONTAINER_NAME = "$root"; - - public static final String STATIC_WEBSITE_CONTAINER_NAME = "$web"; - - public static final String LOG_CONTAINER_NAME = "$logs"; - - AzureBlobStorageImpl azureBlobStorage; - - /** - * Creates a {@code ContainerAsyncClient} object pointing to the account specified by the URL and using the provided - * pipeline to make HTTP requests. - */ - ContainerAsyncRawClient(AzureBlobStorageImpl azureBlobStorage) { - this.azureBlobStorage = azureBlobStorage; - } - - /** - * Creates a new container within a storage account. If a container with the same name already exists, the operation - * fails. For more information, see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.create")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono create() { - return this.create(null, null); - } - - /** - * Creates a new container within a storage account. If a container with the same name already exists, the operation - * fails. For more information, see the - * Azure Docs. - * - * @param metadata - * {@link Metadata} - * @param accessType - * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header - * in the Azure Docs for more information. Pass null for no public access. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.create")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono create(Metadata metadata, PublicAccessType accessType) { - metadata = metadata == null ? new Metadata() : metadata; - - return postProcessResponse(this.azureBlobStorage.containers().createWithRestResponseAsync( - null, null, metadata, accessType, null, Context.NONE)); - - } - - /** - * Marks the specified container for deletion. The container and any blobs contained within it are later - * deleted during garbage collection. For more information, see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.delete")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono delete() { - return this.delete(null); - } - - /** - * Marks the specified container for deletion. The container and any blobs contained within it are later - * deleted during garbage collection. For more information, see the - * Azure Docs. - * - * @param accessConditions - * {@link ContainerAccessConditions} - * - * @return Emits the successful response. - * @throws UnsupportedOperationException If {@link ContainerAccessConditions#modifiedAccessConditions()} has either - * {@link ModifiedAccessConditions#ifMatch()} or {@link ModifiedAccessConditions#ifNoneMatch()} set. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.delete")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono delete(ContainerAccessConditions accessConditions) { - accessConditions = accessConditions == null ? new ContainerAccessConditions() : accessConditions; - - if (!validateNoEtag(accessConditions.modifiedAccessConditions())) { - // Throwing is preferred to Single.error because this will error out immediately instead of waiting until - // subscription. - throw new UnsupportedOperationException("ETag access conditions are not supported for this API."); - } - - return postProcessResponse(this.azureBlobStorage.containers() - .deleteWithRestResponseAsync(null, null, null, - accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)); - } - - /** - * Returns the container's metadata and system properties. For more information, see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.getProperties")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono getProperties() { - return this.getProperties(null); - } - - /** - * Returns the container's metadata and system properties. For more information, see the - * Azure Docs. - * - * @param leaseAccessConditions - * By setting lease access conditions, requests will fail if the provided lease does not match the active - * lease on the blob. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.getProperties")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono getProperties(LeaseAccessConditions leaseAccessConditions) { - return postProcessResponse(this.azureBlobStorage.containers() - .getPropertiesWithRestResponseAsync(null, null, null, - leaseAccessConditions, Context.NONE)); - } - - /** - * Sets the container's metadata. For more information, see the - * Azure Docs. - * - * @param metadata - * {@link Metadata} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.setMetadata")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono setMetadata(Metadata metadata) { - return this.setMetadata(metadata, null); - } - - /** - * Sets the container's metadata. For more information, see the - * Azure Docs. - * - * @param metadata - * {@link Metadata} - * @param accessConditions - * {@link ContainerAccessConditions} - * - * @return Emits the successful response. - * @throws UnsupportedOperationException If {@link ContainerAccessConditions#modifiedAccessConditions()} has anything - * set other than {@link ModifiedAccessConditions#ifModifiedSince()}. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.setMetadata")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono setMetadata(Metadata metadata, - ContainerAccessConditions accessConditions) { - metadata = metadata == null ? new Metadata() : metadata; - accessConditions = accessConditions == null ? new ContainerAccessConditions() : accessConditions; - if (!validateNoEtag(accessConditions.modifiedAccessConditions()) - || accessConditions.modifiedAccessConditions().ifUnmodifiedSince() != null) { - // Throwing is preferred to Single.error because this will error out immediately instead of waiting until - // subscription. - throw new UnsupportedOperationException( - "If-Modified-Since is the only HTTP access condition supported for this API"); - } - - return postProcessResponse(this.azureBlobStorage.containers() - .setMetadataWithRestResponseAsync(null, null, metadata, null, - accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)); - } - - /** - * Returns the container's permissions. The permissions indicate whether container's blobs may be accessed publicly. - * For more information, see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_policy "Sample code for ContainerAsyncClient.getAccessPolicy")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono> getAccessPolicy() { - return this.getAccessPolicy(null); - } - - /** - * Returns the container's permissions. The permissions indicate whether container's blobs may be accessed publicly. - * For more information, see the - * Azure Docs. - * - * @param leaseAccessConditions - * By setting lease access conditions, requests will fail if the provided lease does not match the active - * lease on the blob. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_policy "Sample code for ContainerAsyncClient.getAccessPolicy")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono> getAccessPolicy(LeaseAccessConditions leaseAccessConditions) { - return postProcessResponse(this.azureBlobStorage.containers().getAccessPolicyWithRestResponseAsync(null, null, null, leaseAccessConditions, Context.NONE) - .map(response -> new SimpleResponse<>(response, new ContainerAccessPolicies(response.deserializedHeaders().blobPublicAccess(), response.value())))); - } - - /** - * Sets the container's permissions. The permissions indicate whether blobs in a container may be accessed publicly. - * Note that, for each signed identifier, we will truncate the start and expiry times to the nearest second to - * ensure the time formatting is compatible with the service. For more information, see the - * Azure Docs. - * - * @param accessType - * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header - * in the Azure Docs for more information. Pass null for no public access. - * @param identifiers - * A list of {@link SignedIdentifier} objects that specify the permissions for the container. Please see - * here - * for more information. Passing null will clear all access policies. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_policy "Sample code for ContainerAsyncClient.setAccessPolicy")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono setAccessPolicy(PublicAccessType accessType, - List identifiers) { - return this.setAccessPolicy(accessType, identifiers, null); - } - - /** - * Sets the container's permissions. The permissions indicate whether blobs in a container may be accessed publicly. - * Note that, for each signed identifier, we will truncate the start and expiry times to the nearest second to - * ensure the time formatting is compatible with the service. For more information, see the - * Azure Docs. - * - * @param accessType - * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header - * in the Azure Docs for more information. Pass null for no public access. - * @param identifiers - * A list of {@link SignedIdentifier} objects that specify the permissions for the container. Please see - * here - * for more information. Passing null will clear all access policies. - * @param accessConditions - * {@link ContainerAccessConditions} - * - * @return Emits the successful response. - * @throws UnsupportedOperationException If {@link ContainerAccessConditions#modifiedAccessConditions()} has either - * {@link ModifiedAccessConditions#ifMatch()} or {@link ModifiedAccessConditions#ifNoneMatch()} set. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_policy "Sample code for ContainerAsyncClient.setAccessPolicy")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono setAccessPolicy(PublicAccessType accessType, - List identifiers, ContainerAccessConditions accessConditions) { - accessConditions = accessConditions == null ? new ContainerAccessConditions() : accessConditions; - - if (!validateNoEtag(accessConditions.modifiedAccessConditions())) { - // Throwing is preferred to Single.error because this will error out immediately instead of waiting until - // subscription. - throw new UnsupportedOperationException("ETag access conditions are not supported for this API."); - } - - /* - We truncate to seconds because the service only supports nanoseconds or seconds, but doing an - OffsetDateTime.now will only give back milliseconds (more precise fields are zeroed and not serialized). This - allows for proper serialization with no real detriment to users as sub-second precision on active time for - signed identifiers is not really necessary. - */ - if (identifiers != null) { - for (SignedIdentifier identifier : identifiers) { - if (identifier.accessPolicy() != null && identifier.accessPolicy().start() != null) { - identifier.accessPolicy().start( - identifier.accessPolicy().start().truncatedTo(ChronoUnit.SECONDS)); - } - if (identifier.accessPolicy() != null && identifier.accessPolicy().expiry() != null) { - identifier.accessPolicy().expiry( - identifier.accessPolicy().expiry().truncatedTo(ChronoUnit.SECONDS)); - } - } - } - - return postProcessResponse(this.azureBlobStorage.containers() - .setAccessPolicyWithRestResponseAsync(null, identifiers, null, accessType, - null, accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), - Context.NONE)); - - } - - private boolean validateNoEtag(ModifiedAccessConditions modifiedAccessConditions) { - if (modifiedAccessConditions == null) { - return true; - } - return modifiedAccessConditions.ifMatch() == null && modifiedAccessConditions.ifNoneMatch() == null; - } - - /** - * Acquires a lease on the container for delete operations. The lease duration must be between 15 to - * 60 seconds, or infinite (-1). For more information, see the - * Azure Docs. - * - * @apiNote - * ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.acquireLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/New-Storage-SDK-V10-Preview/src/test/java/com/microsoft/azure/storage/Samples.java) - * - * @param proposedId - * A {@code String} in any valid GUID format. - * @param duration - * The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. - * A non-infinite lease can be between 15 and 60 seconds. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.acquireLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono acquireLease(String proposedId, int duration) { - return this.acquireLease(proposedId, duration, null); - } - - /** - * Acquires a lease on the container for delete operations. The lease duration must be between 15 to - * 60 seconds, or infinite (-1). For more information, see the - * Azure Docs. - * - * @param proposedID - * A {@code String} in any valid GUID format. - * @param duration - * The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. - * A non-infinite lease can be between 15 and 60 seconds. - * @param modifiedAccessConditions - * 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. - * - * @return Emits the successful response. - * @throws UnsupportedOperationException If either {@link ModifiedAccessConditions#ifMatch()} or - * {@link ModifiedAccessConditions#ifNoneMatch()} is set. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.acquireLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono acquireLease(String proposedID, int duration, - ModifiedAccessConditions modifiedAccessConditions) { - if (!this.validateNoEtag(modifiedAccessConditions)) { - // Throwing is preferred to Single.error because this will error out immediately instead of waiting until - // subscription. - throw new UnsupportedOperationException( - "ETag access conditions are not supported for this API."); - } - - return postProcessResponse(this.azureBlobStorage.containers().acquireLeaseWithRestResponseAsync( - null, null, duration, proposedID, null, modifiedAccessConditions, Context.NONE)); - } - - /** - * Renews the container's previously-acquired lease. For more information, see the - * Azure Docs. - * - * @param leaseID - * The leaseId of the active lease on the container. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.renewLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono renewLease(String leaseID) { - return this.renewLease(leaseID, null); - } - - /** - * Renews the container's previously-acquired lease. For more information, see the - * Azure Docs. - * - * @param leaseID - * The leaseId of the active lease on the container. - * @param modifiedAccessConditions - * 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. - * - * @return Emits the successful response. - * @throws UnsupportedOperationException If either {@link ModifiedAccessConditions#ifMatch()} or - * {@link ModifiedAccessConditions#ifNoneMatch()} is set. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.renewLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono renewLease(String leaseID, - ModifiedAccessConditions modifiedAccessConditions) { - if (!this.validateNoEtag(modifiedAccessConditions)) { - // Throwing is preferred to Single.error because this will error out immediately instead of waiting until - // subscription. - throw new UnsupportedOperationException( - "ETag access conditions are not supported for this API."); - } - - return postProcessResponse(this.azureBlobStorage.containers().renewLeaseWithRestResponseAsync(null, - leaseID, null, null, modifiedAccessConditions, Context.NONE)); - } - - /** - * Releases the container's previously-acquired lease. For more information, see the - * Azure Docs. - * - * @param leaseID - * The leaseId of the active lease on the container. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.releaseLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono releaseLease(String leaseID) { - return this.releaseLease(leaseID, null); - } - - /** - * Releases the container's previously-acquired lease. For more information, see the - * Azure Docs. - * - * @param leaseID - * The leaseId of the active lease on the container. - * @param modifiedAccessConditions - * 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. - * - * @return Emits the successful response. - * @throws UnsupportedOperationException If either {@link ModifiedAccessConditions#ifMatch()} or - * {@link ModifiedAccessConditions#ifNoneMatch()} is set. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.releaseLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono releaseLease(String leaseID, - ModifiedAccessConditions modifiedAccessConditions) { - if (!this.validateNoEtag(modifiedAccessConditions)) { - // Throwing is preferred to Single.error because this will error out immediately instead of waiting until - // subscription. - throw new UnsupportedOperationException( - "ETag access conditions are not supported for this API."); - } - - return postProcessResponse(this.azureBlobStorage.containers().releaseLeaseWithRestResponseAsync( - null, leaseID, null, null, modifiedAccessConditions, Context.NONE)); - } - - /** - * Breaks the container's previously-acquired lease. For more information, see the - * Azure Docs. - * - * @apiNote - * ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.breakLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/New-Storage-SDK-V10-Preview/src/test/java/com/microsoft/azure/storage/Samples.java) - * - * @return Emits the successful response. - */ - public Mono breakLease() { - return this.breakLease(null, null); - } - - /** - * Breaks the container's previously-acquired lease. For more information, see the - * Azure Docs. - * - * @param breakPeriodInSeconds - * An optional {@code Integer} representing the proposed duration of seconds that the lease should continue - * before it is broken, between 0 and 60 seconds. This break period is only used if it is shorter than the time - * remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be - * available before the break period has expired, but the lease may be held for longer than the break period. - * @param modifiedAccessConditions - * 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. - * - * @return Emits the successful response. - * @throws UnsupportedOperationException If either {@link ModifiedAccessConditions#ifMatch()} or - * {@link ModifiedAccessConditions#ifNoneMatch()} is set. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.breakLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono breakLease(Integer breakPeriodInSeconds, - ModifiedAccessConditions modifiedAccessConditions) { - if (!this.validateNoEtag(modifiedAccessConditions)) { - // Throwing is preferred to Single.error because this will error out immediately instead of waiting until - // subscription. - throw new UnsupportedOperationException( - "ETag access conditions are not supported for this API."); - } - - return postProcessResponse(this.azureBlobStorage.containers().breakLeaseWithRestResponseAsync(null, - null, breakPeriodInSeconds, null, modifiedAccessConditions, Context.NONE)); - - } - - /** - * Changes the container's leaseAccessConditions. For more information, see the - * Azure Docs. - * - * @param leaseID - * The leaseId of the active lease on the container. - * @param proposedID - * A {@code String} in any valid GUID format. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.changeLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono changeLease(String leaseID, String proposedID) { - return this.changeLease(leaseID, proposedID, null); - } - - /** - * Changes the container's leaseAccessConditions. For more information, see the - * Azure Docs. - * - * @param leaseID - * The leaseId of the active lease on the container. - * @param proposedID - * A {@code String} in any valid GUID format. - * @param modifiedAccessConditions - * 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. - * - * @return Emits the successful response. - * @throws UnsupportedOperationException If either {@link ModifiedAccessConditions#ifMatch()} or - * {@link ModifiedAccessConditions#ifNoneMatch()} is set. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.changeLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono changeLease(String leaseID, String proposedID, - ModifiedAccessConditions modifiedAccessConditions) { - if (!this.validateNoEtag(modifiedAccessConditions)) { - // Throwing is preferred to Single.error because this will error out immediately instead of waiting until - // subscription. - throw new UnsupportedOperationException( - "ETag access conditions are not supported for this API."); - } - - return postProcessResponse(this.azureBlobStorage.containers().changeLeaseWithRestResponseAsync(null, - leaseID, proposedID, null, null, modifiedAccessConditions, Context.NONE)); - } - - /** - * Returns a single segment of blobs starting from the specified Marker. Use an empty - * marker to start enumeration from the beginning. Blob names are returned in lexicographic order. - * After getting a segment, process it, and then call ListBlobs again (passing the the previously-returned - * Marker) to get the next segment. For more information, see the - * Azure Docs. - * - * @param marker - * Identifies the portion of the list to be returned with the next list operation. - * This value is returned in the response of a previous list operation as the - * ListBlobsFlatSegmentResponse.body().nextMarker(). Set to null to list the first segment. - * @param options - * {@link ListBlobsOptions} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_flat "Sample code for ContainerAsyncClient.listBlobsFlatSegment")] \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_flat_helper "helper code for ContainerAsyncClient.listBlobsFlatSegment")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono listBlobsFlatSegment(String marker, ListBlobsOptions options) { - options = options == null ? new ListBlobsOptions() : options; - - return postProcessResponse(this.azureBlobStorage.containers() - .listBlobFlatSegmentWithRestResponseAsync(null, options.prefix(), marker, - options.maxResults(), options.details().toList(), null, null, Context.NONE)); - } - - /** - * Returns a single segment of blobs and blob prefixes starting from the specified Marker. Use an empty - * marker to start enumeration from the beginning. Blob names are returned in lexicographic order. - * After getting a segment, process it, and then call ListBlobs again (passing the the previously-returned - * Marker) to get the next segment. For more information, see the - * Azure Docs. - * - * @param marker - * Identifies the portion of the list to be returned with the next list operation. - * This value is returned in the response of a previous list operation as the - * ListBlobsHierarchySegmentResponse.body().nextMarker(). Set to null to list the first segment. - * @param delimiter - * The operation returns a BlobPrefix element in the response body that acts as a placeholder for all blobs - * whose names begin with the same substring up to the appearance of the delimiter character. The delimiter may - * be a single character or a string. - * @param options - * {@link ListBlobsOptions} - * - * @return Emits the successful response. - * @throws UnsupportedOperationException If {@link ListBlobsOptions#details()} has {@link BlobListDetails#snapshots()} - * set. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy "Sample code for ContainerAsyncClient.listBlobsHierarchySegment")] \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy_helper "helper code for ContainerAsyncClient.listBlobsHierarchySegment")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono listBlobsHierarchySegment(String marker, String delimiter, - ListBlobsOptions options) { - options = options == null ? new ListBlobsOptions() : options; - if (options.details().snapshots()) { - throw new UnsupportedOperationException("Including snapshots in a hierarchical listing is not supported."); - } - - return postProcessResponse(this.azureBlobStorage.containers() - .listBlobHierarchySegmentWithRestResponseAsync(null, delimiter, options.prefix(), marker, - options.maxResults(), options.details().toList(), null, null, Context.NONE)); - } - - /** - * Returns the sku name and account kind for the account. For more information, please see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=account_info "Sample code for ContainerAsyncClient.getAccountInfo")] \n - * For more samples, please see the [Samples file] (https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono getAccountInfo() { - return postProcessResponse( - this.azureBlobStorage.containers().getAccountInfoWithRestResponseAsync(null, Context.NONE)); - } -} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClient.java index c9733fd3a7f61..de5d4f1431f39 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClient.java @@ -25,47 +25,45 @@ import java.util.List; /** - * Client to a container. It may only be instantiated through a {@link ContainerClientBuilder} or via the method - * {@link StorageClient#getContainerClient(String)}. This class does not hold any - * state about a particular container but is instead a convenient way of sending off appropriate requests to - * the resource on the service. It may also be used to construct URLs to blobs. + * Client to a container. It may only be instantiated through a {@link ContainerClientBuilder} or via the method {@link + * StorageClient#getContainerClient(String)}. This class does not hold any state about a particular container but is + * instead a convenient way of sending off appropriate requests to the resource on the service. It may also be used to + * construct URLs to blobs. * *

* This client contains operations on a container. Operations on a blob are available on {@link BlobClient} through * {@link #getBlobClient(String)}, and operations on the service are available on {@link StorageClient}. * *

- * Please refer to the Azure Docs - * for more information on containers. + * Please refer to the Azure + * Docs for more information on containers. */ public final class ContainerClient { - private ContainerAsyncClient containerAsyncClient; - public static final String ROOT_CONTAINER_NAME = "$root"; + public static final String ROOT_CONTAINER_NAME = ContainerAsyncClient.ROOT_CONTAINER_NAME; - public static final String STATIC_WEBSITE_CONTAINER_NAME = "$web"; + public static final String STATIC_WEBSITE_CONTAINER_NAME = ContainerAsyncClient.STATIC_WEBSITE_CONTAINER_NAME; - public static final String LOG_CONTAINER_NAME = "$logs"; + public static final String LOG_CONTAINER_NAME = ContainerAsyncClient.LOG_CONTAINER_NAME; /** * Package-private constructor for use by {@link ContainerClientBuilder}. + * * @param containerAsyncClient the async container client */ ContainerClient(ContainerAsyncClient containerAsyncClient) { - this.containerAsyncClient = containerAsyncClient; + 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. - * - * @param blobName - * A {@code String} representing the name of the blob. + * 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. * + * @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) { @@ -73,17 +71,14 @@ public BlockBlobClient getBlockBlobClient(String 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. - * - * @param blobName - * A {@code String} representing the name of the blob. - * @param snapshot - * the snapshot identifier for the blob. + * 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. * + * @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) { @@ -91,15 +86,12 @@ public BlockBlobClient getBlockBlobClient(String blobName, String 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. - * - * @param blobName - * A {@code String} representing the name of the blob. + * 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. * + * @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) { @@ -107,17 +99,13 @@ public PageBlobClient getPageBlobClient(String 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. - * - * @param blobName - * A {@code String} representing the name of the blob. - * @param snapshot - * the snapshot identifier for the blob. + * 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. * + * @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) { @@ -125,31 +113,27 @@ public PageBlobClient getPageBlobClient(String blobName, String 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 + * 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. * - * @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. + * @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)); } /** - * 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 BlobClient and then call its WithPipeline method passing in the - * desired pipeline object. Or, call this package's getBlobAsyncClient instead of calling this object's - * getBlobAsyncClient method. - * - * @param blobName - * A {@code String} representing the name of the blob. + * 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 + * BlobClient and then call its WithPipeline method passing in the desired pipeline object. Or, call this package's + * getBlobAsyncClient instead of calling this object's getBlobAsyncClient method. * + * @param blobName A {@code String} representing the name of the blob. * @return A new {@link BlobClient} object which references the blob with the specified name in this container. */ public BlobClient getBlobClient(String blobName) { @@ -157,17 +141,13 @@ public BlobClient getBlobClient(String blobName) { } /** - * 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 BlobClient and then call its WithPipeline method passing in the - * desired pipeline object. Or, call this package's getBlobAsyncClient instead of calling this object's - * getBlobAsyncClient method. - * - * @param blobName - * A {@code String} representing the name of the blob. - * @param snapshot - * the snapshot identifier for the blob. + * 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 + * BlobClient and then call its WithPipeline method passing in the desired pipeline object. Or, call this package's + * getBlobAsyncClient instead of calling this object's getBlobAsyncClient method. * + * @param blobName A {@code String} representing the name of the blob. + * @param snapshot the snapshot identifier for the blob. * @return A new {@link BlobClient} object which references the blob with the specified name in this container. */ public BlobClient getBlobClient(String blobName, String snapshot) { @@ -177,8 +157,7 @@ public BlobClient getBlobClient(String blobName, String snapshot) { /** * Initializes a {@link StorageClient} object pointing to the storage account this container is in. * - * @return - * A {@link StorageClient} object pointing to the specified storage account + * @return A {@link StorageClient} object pointing to the specified storage account */ public StorageClient getStorageClient() { return new StorageClient(containerAsyncClient.getStorageAsyncClient()); @@ -186,6 +165,7 @@ public StorageClient getStorageClient() { /** * Gets the URL of the container represented by this client. + * * @return the URL. */ public URL getContainerUrl() { @@ -204,10 +184,8 @@ public Response exists() { /** * Gets if the container this client represents exists in the cloud. * - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * @return - * true if the container exists, false if it doesn't + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return true if the container exists, false if it doesn't */ public Response exists(Duration timeout) { Mono> response = containerAsyncClient.exists(); @@ -219,6 +197,7 @@ public Response exists(Duration timeout) { * Creates a new container within a storage account. If a container with the same name already exists, the operation * fails. For more information, see the * Azure Docs. + * * @return A response containing status code and HTTP headers */ public VoidResponse create() { @@ -230,13 +209,10 @@ public VoidResponse create() { * fails. For more information, see the * Azure Docs. * - * @param metadata - * {@link Metadata} - * @param accessType - * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header - * in the Azure Docs for more information. Pass null for no public access. - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @param metadata {@link Metadata} + * @param accessType Specifies how the data in this container is available to the public. See the + * x-ms-blob-public-access header in the Azure Docs for more information. Pass null for no public access. + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return A response containing status code and HTTP headers */ public VoidResponse create(Metadata metadata, PublicAccessType accessType, Duration timeout) { @@ -246,9 +222,10 @@ public VoidResponse create(Metadata metadata, PublicAccessType accessType, Durat } /** - * Marks the specified container for deletion. The container and any blobs contained within it are later - * deleted during garbage collection. For more information, see the + * Marks the specified container for deletion. The container and any blobs contained within it are later deleted + * during garbage collection. For more information, see the * Azure Docs. + * * @return A response containing status code and HTTP headers */ public VoidResponse delete() { @@ -256,14 +233,12 @@ public VoidResponse delete() { } /** - * Marks the specified container for deletion. The container and any blobs contained within it are later - * deleted during garbage collection. For more information, see the + * Marks the specified container for deletion. The container and any blobs contained within it are later deleted + * during garbage collection. For more information, see the * Azure Docs. * - * @param accessConditions - * {@link ContainerAccessConditions} - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @param accessConditions {@link ContainerAccessConditions} + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return A response containing status code and HTTP headers */ public VoidResponse delete(ContainerAccessConditions accessConditions, Duration timeout) { @@ -276,8 +251,7 @@ public VoidResponse delete(ContainerAccessConditions accessConditions, Duration * Returns the container's metadata and system properties. For more information, see the * Azure Docs. * - * @return - * The container properties. + * @return The container properties. */ public Response getProperties() { return this.getProperties(null, null); @@ -287,17 +261,13 @@ public Response getProperties() { * Returns the container's metadata and system properties. For more information, see the * Azure Docs. * - * @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. - * - * @return - * The container properties. + * @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. + * @return The container properties. */ public Response getProperties(LeaseAccessConditions leaseAccessConditions, - Duration timeout) { + Duration timeout) { Mono> response = containerAsyncClient.getProperties(leaseAccessConditions); return Utility.blockWithOptionalTimeout(response, timeout); @@ -307,8 +277,7 @@ public Response getProperties(LeaseAccessConditions leaseAc * Sets the container's metadata. For more information, see the * Azure Docs. * - * @param metadata - * {@link Metadata} + * @param metadata {@link Metadata} * @return A response containing status code and HTTP headers */ public VoidResponse setMetadata(Metadata metadata) { @@ -319,16 +288,13 @@ public VoidResponse setMetadata(Metadata metadata) { * Sets the container's metadata. For more information, see the * Azure Docs. * - * @param metadata - * {@link Metadata} - * @param accessConditions - * {@link ContainerAccessConditions} - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @param metadata {@link Metadata} + * @param accessConditions {@link ContainerAccessConditions} + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return A response containing status code and HTTP headers */ public VoidResponse setMetadata(Metadata metadata, - ContainerAccessConditions accessConditions, Duration timeout) { + ContainerAccessConditions accessConditions, Duration timeout) { Mono response = containerAsyncClient.setMetadata(metadata, accessConditions); return Utility.blockWithOptionalTimeout(response, timeout); @@ -339,8 +305,7 @@ public VoidResponse setMetadata(Metadata metadata, * For more information, see the * Azure Docs. * - * @return - * The container access policy. + * @return The container access policy. */ public Response getAccessPolicy() { return this.getAccessPolicy(null, null); @@ -351,14 +316,10 @@ public Response getAccessPolicy() { * For more information, see the * Azure Docs. * - * @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. - * - * @return - * The container access policy. + * @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. + * @return The container access policy. */ public Response getAccessPolicy(LeaseAccessConditions leaseAccessConditions, Duration timeout) { @@ -373,17 +334,16 @@ public Response getAccessPolicy(LeaseAccessConditions l * ensure the time formatting is compatible with the service. For more information, see the * Azure Docs. * - * @param accessType - * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header - * in the Azure Docs for more information. Pass null for no public access. - * @param identifiers - * A list of {@link SignedIdentifier} objects that specify the permissions for the container. Please see - * here - * for more information. Passing null will clear all access policies. + * @param accessType Specifies how the data in this container is available to the public. See the + * x-ms-blob-public-access header in the Azure Docs for more information. Pass null for no public access. + * @param identifiers A list of {@link SignedIdentifier} objects that specify the permissions for the container. + * Please see + * here + * for more information. Passing null will clear all access policies. * @return A response containing status code and HTTP headers */ public VoidResponse setAccessPolicy(PublicAccessType accessType, - List identifiers) { + List identifiers) { return this.setAccessPolicy(accessType, identifiers, null, null); } @@ -393,31 +353,27 @@ public VoidResponse setAccessPolicy(PublicAccessType accessType, * ensure the time formatting is compatible with the service. For more information, see the * Azure Docs. * - * @param accessType - * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header - * in the Azure Docs for more information. Pass null for no public access. - * @param identifiers - * A list of {@link SignedIdentifier} objects that specify the permissions for the container. Please see - * here - * for more information. Passing null will clear all access policies. - * @param accessConditions - * {@link ContainerAccessConditions} - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @param accessType Specifies how the data in this container is available to the public. See the + * x-ms-blob-public-access header in the Azure Docs for more information. Pass null for no public access. + * @param identifiers A list of {@link SignedIdentifier} objects that specify the permissions for the container. + * Please see + * here + * for more information. Passing null will clear all access policies. + * @param accessConditions {@link ContainerAccessConditions} + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return A response containing status code and HTTP headers */ public VoidResponse setAccessPolicy(PublicAccessType accessType, - List identifiers, ContainerAccessConditions accessConditions, - Duration timeout) { + List identifiers, ContainerAccessConditions accessConditions, + Duration timeout) { Mono response = containerAsyncClient.setAccessPolicy(accessType, identifiers, accessConditions); return Utility.blockWithOptionalTimeout(response, timeout); } /** - * Returns a lazy loaded list of blobs in this container, with folder structures flattened. - * The returned {@link Iterable} can be iterated through while new items are automatically - * retrieved as needed. + * Returns a lazy loaded list of blobs in this container, with folder structures flattened. The returned {@link + * Iterable} can be iterated through while new items are automatically retrieved as needed. * *

* Blob names are returned in lexicographic order. @@ -426,17 +382,15 @@ public VoidResponse setAccessPolicy(PublicAccessType accessType, * For more information, see the * Azure Docs. * - * @return - * The listed blobs, flattened. + * @return The listed blobs, flattened. */ public Iterable listBlobsFlat() { return this.listBlobsFlat(new ListBlobsOptions(), null); } /** - * Returns a lazy loaded list of blobs in this container, with folder structures flattened. - * The returned {@link Iterable} can be iterated through while new items are automatically - * retrieved as needed. + * Returns a lazy loaded list of blobs in this container, with folder structures flattened. The returned {@link + * Iterable} can be iterated through while new items are automatically retrieved as needed. * *

* Blob names are returned in lexicographic order. @@ -445,13 +399,9 @@ public Iterable listBlobsFlat() { * For more information, see the * Azure Docs. * - * @param options - * {@link ListBlobsOptions} - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * - * @return - * The listed blobs, flattened. + * @param options {@link ListBlobsOptions} + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return The listed blobs, flattened. */ public Iterable listBlobsFlat(ListBlobsOptions options, Duration timeout) { Flux response = containerAsyncClient.listBlobsFlat(options); @@ -460,74 +410,64 @@ public Iterable listBlobsFlat(ListBlobsOptions options, Duration timeo } /** - * Returns a reactive Publisher emitting all the blobs and directories (prefixes) under - * the given directory (prefix). Directories will have {@link BlobItem#isPrefix()} set to - * true. + * Returns a reactive Publisher emitting all the blobs and directories (prefixes) under the given directory + * (prefix). Directories will have {@link BlobItem#isPrefix()} set to true. * *

* Blob names are returned in lexicographic order. For more information, see the * Azure Docs. * *

- * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob - * on the root level 'bar', will return the following results when prefix=null: + * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob on the + * root level 'bar', will return the following results when prefix=null: * *

    - *
  • foo/ (isPrefix = true) - *
  • bar (isPrefix = false) + *
  • foo/ (isPrefix = true) + *
  • bar (isPrefix = false) *
*

* will return the following results when prefix="foo/": * *

    - *
  • foo/foo1 (isPrefix = false) - *
  • foo/foo2 (isPrefix = false) + *
  • foo/foo1 (isPrefix = false) + *
  • foo/foo2 (isPrefix = false) *
* - * @param directory - * The directory to list blobs underneath - * - * @return - * A reactive response emitting the prefixes and blobs. + * @param directory The directory to list blobs underneath + * @return A reactive response emitting the prefixes and blobs. */ public Iterable listBlobsHierarchy(String directory) { return this.listBlobsHierarchy("/", new ListBlobsOptions().prefix(directory), null); } /** - * Returns a reactive Publisher emitting all the blobs and prefixes (directories) under - * the given prefix (directory). Directories will have {@link BlobItem#isPrefix()} set to - * true. + * Returns a reactive Publisher emitting all the blobs and prefixes (directories) under the given prefix + * (directory). Directories will have {@link BlobItem#isPrefix()} set to true. * *

* Blob names are returned in lexicographic order. For more information, see the * Azure Docs. * *

- * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob - * on the root level 'bar', will return the following results when prefix=null: + * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob on the + * root level 'bar', will return the following results when prefix=null: * *

    - *
  • foo/ (isPrefix = true) - *
  • bar (isPrefix = false) + *
  • foo/ (isPrefix = true) + *
  • bar (isPrefix = false) *
*

* will return the following results when prefix="foo/": * *

    - *
  • foo/foo1 (isPrefix = false) - *
  • foo/foo2 (isPrefix = false) + *
  • foo/foo1 (isPrefix = false) + *
  • foo/foo2 (isPrefix = false) *
* - * @param delimiter - * The delimiter for blob hierarchy, "/" for hierarchy based on directories - * @param options - * {@link ListBlobsOptions} - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * - * @return - * A reactive response emitting the prefixes and blobs. + * @param delimiter The delimiter for blob hierarchy, "/" for hierarchy based on directories + * @param options {@link ListBlobsOptions} + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return A reactive response emitting the prefixes and blobs. */ public Iterable listBlobsHierarchy(String delimiter, ListBlobsOptions options, Duration timeout) { Flux response = containerAsyncClient.listBlobsHierarchy(delimiter, options); @@ -539,14 +479,10 @@ public Iterable listBlobsHierarchy(String delimiter, ListBlobsOptions * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 * seconds, or infinite (-1). * - * @param proposedId - * A {@code String} in any valid GUID format. May be null. - * @param duration - * The duration of the lease, in seconds, or negative one (-1) for a lease that - * never expires. A non-infinite lease can be between 15 and 60 seconds. - * - * @return - * The lease ID. + * @param proposedId A {@code String} in any valid GUID format. May be null. + * @param duration The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A + * non-infinite lease can be between 15 and 60 seconds. + * @return The lease ID. */ public Response acquireLease(String proposedId, int duration) { return this.acquireLease(proposedId, duration, null, null); @@ -556,23 +492,17 @@ public Response acquireLease(String proposedId, int duration) { * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 * seconds, or infinite (-1). * - * @param proposedID - * A {@code String} in any valid GUID format. May be null. - * @param duration - * The duration of the lease, in seconds, or negative one (-1) for a lease that - * never expires. A non-infinite lease can be between 15 and 60 seconds. - * @param modifiedAccessConditions - * 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 timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * - * @return - * The lease ID. + * @param proposedID A {@code String} in any valid GUID format. May be null. + * @param duration The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A + * non-infinite lease can be between 15 and 60 seconds. + * @param modifiedAccessConditions 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 timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return The lease ID. */ public Response acquireLease(String proposedID, int duration, - ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { Mono> response = containerAsyncClient .acquireLease(proposedID, duration, modifiedAccessConditions); @@ -582,11 +512,8 @@ public Response acquireLease(String proposedID, int duration, /** * Renews the blob's previously-acquired lease. * - * @param leaseID - * The leaseId of the active lease on the blob. - * - * @return - * The renewed lease ID. + * @param leaseID The leaseId of the active lease on the blob. + * @return The renewed lease ID. */ public Response renewLease(String leaseID) { return this.renewLease(leaseID, null, null); @@ -595,20 +522,15 @@ public Response renewLease(String leaseID) { /** * Renews the blob's previously-acquired lease. * - * @param leaseID - * The leaseId of the active lease on the blob. - * @param modifiedAccessConditions - * 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 timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * - * @return - * The renewed lease ID. + * @param leaseID The leaseId of the active lease on the blob. + * @param modifiedAccessConditions 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 timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return The renewed lease ID. */ public Response renewLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions, - Duration timeout) { + Duration timeout) { Mono> response = containerAsyncClient .renewLease(leaseID, modifiedAccessConditions); @@ -618,8 +540,7 @@ public Response renewLease(String leaseID, ModifiedAccessConditions modi /** * Releases the blob's previously-acquired lease. * - * @param leaseID - * The leaseId of the active lease on the blob. + * @param leaseID The leaseId of the active lease on the blob. * @return A response containing status code and HTTP headers */ public VoidResponse releaseLease(String leaseID) { @@ -629,18 +550,15 @@ public VoidResponse releaseLease(String leaseID) { /** * Releases the blob's previously-acquired lease. * - * @param leaseID - * The leaseId of the active lease on the blob. - * @param modifiedAccessConditions - * 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 timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @param leaseID The leaseId of the active lease on the blob. + * @param modifiedAccessConditions 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 timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return A response containing status code and HTTP headers. */ public VoidResponse releaseLease(String leaseID, - ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { Mono response = containerAsyncClient .releaseLease(leaseID, modifiedAccessConditions); @@ -651,8 +569,7 @@ public VoidResponse releaseLease(String leaseID, * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant * to break a fixed-duration lease when it expires or an infinite lease immediately. * - * @return - * The remaining time in the broken lease. + * @return The remaining time in the broken lease. */ public Response breakLease() { return this.breakLease(null, null, null); @@ -662,24 +579,19 @@ public Response breakLease() { * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant * to break a fixed-duration lease when it expires or an infinite lease immediately. * - * @param breakPeriodInSeconds - * An optional {@code Integer} representing the proposed duration of seconds that the lease should continue - * before it is broken, between 0 and 60 seconds. This break period is only used if it is shorter than the - * time remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be - * available before the break period has expired, but the lease may be held for longer than the break - * period. - * @param modifiedAccessConditions - * 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 timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * - * @return - * The remaining time in the broken lease. + * @param breakPeriodInSeconds An optional {@code Integer} representing the proposed duration of seconds that the + * lease should continue before it is broken, between 0 and 60 seconds. This break period is only used if it is + * shorter than the time remaining on the lease. If longer, the time remaining on the lease is used. A new lease + * will not be available before the break period has expired, but the lease may be held for longer than the break + * period. + * @param modifiedAccessConditions 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 timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return The remaining time in the broken lease. */ public Response breakLease(Integer breakPeriodInSeconds, - ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { Mono> response = containerAsyncClient .breakLease(breakPeriodInSeconds, modifiedAccessConditions); @@ -689,36 +601,28 @@ public Response breakLease(Integer breakPeriodInSeconds, /** * ChangeLease changes the blob's lease ID. * - * @param leaseId - * The leaseId of the active lease on the blob. - * @param proposedID - * A {@code String} in any valid GUID format. - * - * @return - * The new lease ID. + * @param leaseId The leaseId of the active lease on the blob. + * @param proposedID A {@code String} in any valid GUID format. + * @return The new lease ID. */ public Response changeLease(String leaseId, String proposedID) { return this.changeLease(leaseId, proposedID, null, null); } /** - * ChangeLease changes the blob's lease ID. For more information, see the Azure Docs. - * - * @param leaseId - * The leaseId of the active lease on the blob. - * @param proposedID - * A {@code String} in any valid GUID format. - * @param modifiedAccessConditions - * 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 timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * ChangeLease changes the blob's lease ID. For more information, see the Azure + * Docs. * + * @param leaseId The leaseId of the active lease on the blob. + * @param proposedID A {@code String} in any valid GUID format. + * @param modifiedAccessConditions 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 timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return The new lease ID. */ public Response changeLease(String leaseId, String proposedID, - ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { Mono> response = containerAsyncClient .changeLease(leaseId, proposedID, modifiedAccessConditions); @@ -729,11 +633,8 @@ public Response changeLease(String leaseId, String proposedID, * Returns the sku name and account kind for the account. For more information, please see the * Azure Docs. * - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * - * @return - * The account info. + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return The account info. */ public Response getAccountInfo(Duration timeout) { Mono> response = containerAsyncClient.getAccountInfo(); @@ -744,20 +645,14 @@ public Response getAccountInfo(Duration 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 ContainerSASPermissions} permission for the SAS - * @param expiryTime - * The {@code OffsetDateTime} expiry time for the SAS - * - * @return - * A string that represents the SAS token + * @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, - ContainerSASPermission permissions, OffsetDateTime expiryTime) { + ContainerSASPermission permissions, OffsetDateTime expiryTime) { return this.containerAsyncClient.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime); } @@ -765,29 +660,19 @@ public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, Str /** * 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 + * @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, - ContainerSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, - SASProtocol sasProtocol, IPRange ipRange) { + ContainerSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, + SASProtocol sasProtocol, IPRange ipRange) { return this.containerAsyncClient.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime, startTime, version, sasProtocol, ipRange); } @@ -795,40 +680,25 @@ public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, Str /** * 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 - * @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 + * @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 + * @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, - ContainerSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, - SASProtocol sasProtocol, IPRange ipRange, String cacheControl, String contentDisposition, - String contentEncoding, String contentLanguage, String contentType) { + ContainerSASPermission permissions, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, + SASProtocol sasProtocol, IPRange ipRange, String cacheControl, String contentDisposition, + String contentEncoding, String contentLanguage, String contentType) { return this.containerAsyncClient.generateUserDelegationSAS(userDelegationKey, accountName, permissions, expiryTime, startTime, version, sasProtocol, ipRange, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); @@ -837,13 +707,9 @@ public String generateUserDelegationSAS(UserDelegationKey userDelegationKey, Str /** * Generates a SAS token with the specified parameters * - * @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 + * @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 generateSAS(ContainerSASPermission permissions, OffsetDateTime expiryTime) { return this.containerAsyncClient.generateSAS(permissions, expiryTime); @@ -852,11 +718,8 @@ public String generateSAS(ContainerSASPermission permissions, OffsetDateTime exp /** * 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 + * @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.containerAsyncClient.generateSAS(identifier); @@ -865,26 +728,17 @@ public String generateSAS(String 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 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 + * @param identifier The {@code String} name of the access policy on the container this SAS references if any + * @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 generateSAS(String identifier, ContainerSASPermission permissions, OffsetDateTime expiryTime, - OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange) { + OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange) { return this.containerAsyncClient.generateSAS(identifier, permissions, expiryTime, startTime, version, sasProtocol, ipRange); } @@ -892,37 +746,23 @@ public String generateSAS(String identifier, ContainerSASPermission permissions, /** * 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 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 - * @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 + * @param identifier The {@code String} name of the access policy on the container this SAS references if any + * @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 + * @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, ContainerSASPermission permissions, OffsetDateTime expiryTime, - OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange, String cacheControl, - String contentDisposition, String contentEncoding, String contentLanguage, String contentType) { + OffsetDateTime startTime, String version, SASProtocol sasProtocol, IPRange ipRange, String cacheControl, + String contentDisposition, String contentEncoding, String contentLanguage, String contentType) { return this.containerAsyncClient.generateSAS(identifier, permissions, expiryTime, startTime, version, sasProtocol, ipRange, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType); } diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerRawClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerRawClient.java deleted file mode 100644 index 19d10f5444ee5..0000000000000 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerRawClient.java +++ /dev/null @@ -1,652 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.storage.blob; - -import com.azure.core.http.rest.Response; -import com.azure.storage.blob.implementation.AzureBlobStorageImpl; -import com.azure.storage.blob.models.ContainerAccessConditions; -import com.azure.storage.blob.models.ContainerAccessPolicies; -import com.azure.storage.blob.models.ContainersAcquireLeaseResponse; -import com.azure.storage.blob.models.ContainersBreakLeaseResponse; -import com.azure.storage.blob.models.ContainersChangeLeaseResponse; -import com.azure.storage.blob.models.ContainersCreateResponse; -import com.azure.storage.blob.models.ContainersDeleteResponse; -import com.azure.storage.blob.models.ContainersGetAccountInfoResponse; -import com.azure.storage.blob.models.ContainersGetPropertiesResponse; -import com.azure.storage.blob.models.ContainersListBlobFlatSegmentResponse; -import com.azure.storage.blob.models.ContainersListBlobHierarchySegmentResponse; -import com.azure.storage.blob.models.ContainersReleaseLeaseResponse; -import com.azure.storage.blob.models.ContainersRenewLeaseResponse; -import com.azure.storage.blob.models.ContainersSetAccessPolicyResponse; -import com.azure.storage.blob.models.ContainersSetMetadataResponse; -import com.azure.storage.blob.models.LeaseAccessConditions; -import com.azure.storage.blob.models.ListBlobsOptions; -import com.azure.storage.blob.models.Metadata; -import com.azure.storage.blob.models.ModifiedAccessConditions; -import com.azure.storage.blob.models.PublicAccessType; -import com.azure.storage.blob.models.SignedIdentifier; -import reactor.core.publisher.Mono; - -import java.time.Duration; -import java.util.List; - -/** - * Represents a URL to a container. It may be obtained by direct construction or via the create method on a - * {@link StorageAsyncRawClient} object. This class does not hold any state about a particular blob but is instead a convenient way - * of sending off appropriate requests to the resource on the service. It may also be used to construct URLs to blobs. - * Please refer to the - * Azure Docs - * for more information on containers. - */ -final class ContainerRawClient { - - private ContainerAsyncRawClient containerAsyncRawClient; - - public static final String ROOT_CONTAINER_NAME = "$root"; - - public static final String STATIC_WEBSITE_CONTAINER_NAME = "$web"; - - public static final String LOG_CONTAINER_NAME = "$logs"; - - - /** - * Creates a {@code ContainerAsyncClient} object pointing to the account specified by the URL and using the provided - * pipeline to make HTTP requests. - */ - ContainerRawClient(AzureBlobStorageImpl azureBlobStorage) { - this.containerAsyncRawClient = new ContainerAsyncRawClient(azureBlobStorage); - } - - /** - * Creates a new container within a storage account. If a container with the same name already exists, the operation - * fails. For more information, see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.create")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersCreateResponse create() { - return this.create(null, null, null); - } - - /** - * Creates a new container within a storage account. If a container with the same name already exists, the operation - * fails. For more information, see the - * Azure Docs. - * - * @param metadata - * {@link Metadata} - * @param accessType - * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header - * in the Azure Docs for more information. Pass null for no public access. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.create")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersCreateResponse create(Metadata metadata, PublicAccessType accessType, Duration timeout) { - Mono response = containerAsyncRawClient.create(metadata, accessType); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Marks the specified container for deletion. The container and any blobs contained within it are later - * deleted during garbage collection. For more information, see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.delete")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersDeleteResponse delete() { - return this.delete(null, null); - } - - /** - * Marks the specified container for deletion. The container and any blobs contained within it are later - * deleted during garbage collection. For more information, see the - * Azure Docs. - * - * @param accessConditions - * {@link ContainerAccessConditions} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.delete")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersDeleteResponse delete(ContainerAccessConditions accessConditions, Duration timeout) { - Mono response = containerAsyncRawClient.delete(accessConditions); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Returns the container's metadata and system properties. For more information, see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.getProperties")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersGetPropertiesResponse getProperties() { - return this.getProperties(null, null); - } - - /** - * Returns the container's metadata and system properties. For more information, see the - * Azure Docs. - * - * @param leaseAccessConditions - * By setting lease access conditions, requests will fail if the provided lease does not match the active - * lease on the blob. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.getProperties")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersGetPropertiesResponse getProperties(LeaseAccessConditions leaseAccessConditions, - Duration timeout) { - Mono response = containerAsyncRawClient.getProperties(leaseAccessConditions); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Sets the container's metadata. For more information, see the - * Azure Docs. - * - * @param metadata - * {@link Metadata} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.setMetadata")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersSetMetadataResponse setMetadata(Metadata metadata) { - return this.setMetadata(metadata, null, null); - } - - /** - * Sets the container's metadata. For more information, see the - * Azure Docs. - * - * @param metadata - * {@link Metadata} - * @param accessConditions - * {@link ContainerAccessConditions} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.setMetadata")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersSetMetadataResponse setMetadata(Metadata metadata, - ContainerAccessConditions accessConditions, Duration timeout) { - Mono response = containerAsyncRawClient.setMetadata(metadata, accessConditions); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Returns the container's permissions. The permissions indicate whether container's blobs may be accessed publicly. - * For more information, see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_policy "Sample code for ContainerAsyncClient.getAccessPolicy")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Response getAccessPolicy() { - return this.getAccessPolicy(null, null); - } - - /** - * Returns the container's permissions. The permissions indicate whether container's blobs may be accessed publicly. - * For more information, see the - * Azure Docs. - * - * @param leaseAccessConditions - * By setting lease access conditions, requests will fail if the provided lease does not match the active - * lease on the blob. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_policy "Sample code for ContainerAsyncClient.getAccessPolicy")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Response getAccessPolicy(LeaseAccessConditions leaseAccessConditions, - Duration timeout) { - Mono> response = containerAsyncRawClient.getAccessPolicy(leaseAccessConditions); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Sets the container's permissions. The permissions indicate whether blobs in a container may be accessed publicly. - * Note that, for each signed identifier, we will truncate the start and expiry times to the nearest second to - * ensure the time formatting is compatible with the service. For more information, see the - * Azure Docs. - * - * @param accessType - * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header - * in the Azure Docs for more information. Pass null for no public access. - * @param identifiers - * A list of {@link SignedIdentifier} objects that specify the permissions for the container. Please see - * here - * for more information. Passing null will clear all access policies. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_policy "Sample code for ContainerAsyncClient.setAccessPolicy")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersSetAccessPolicyResponse setAccessPolicy(PublicAccessType accessType, - List identifiers) { - return this.setAccessPolicy(accessType, identifiers, null, null); - } - - /** - * Sets the container's permissions. The permissions indicate whether blobs in a container may be accessed publicly. - * Note that, for each signed identifier, we will truncate the start and expiry times to the nearest second to - * ensure the time formatting is compatible with the service. For more information, see the - * Azure Docs. - * - * @param accessType - * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header - * in the Azure Docs for more information. Pass null for no public access. - * @param identifiers - * A list of {@link SignedIdentifier} objects that specify the permissions for the container. Please see - * here - * for more information. Passing null will clear all access policies. - * @param accessConditions - * {@link ContainerAccessConditions} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_policy "Sample code for ContainerAsyncClient.setAccessPolicy")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersSetAccessPolicyResponse setAccessPolicy(PublicAccessType accessType, - List identifiers, ContainerAccessConditions accessConditions, Duration timeout) { - Mono response = containerAsyncRawClient.setAccessPolicy(accessType, identifiers, accessConditions); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Acquires a lease on the container for delete operations. The lease duration must be between 15 to - * 60 seconds, or infinite (-1). For more information, see the - * Azure Docs. - * - * @apiNote - * ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.acquireLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/New-Storage-SDK-V10-Preview/src/test/java/com/microsoft/azure/storage/Samples.java) - * - * @param proposedId - * A {@code String} in any valid GUID format. - * @param duration - * The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. - * A non-infinite lease can be between 15 and 60 seconds. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.acquireLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersAcquireLeaseResponse acquireLease(String proposedId, int duration) { - return this.acquireLease(proposedId, duration, null, null); - } - - /** - * Acquires a lease on the container for delete operations. The lease duration must be between 15 to - * 60 seconds, or infinite (-1). For more information, see the - * Azure Docs. - * - * @param proposedID - * A {@code String} in any valid GUID format. - * @param duration - * The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. - * A non-infinite lease can be between 15 and 60 seconds. - * @param modifiedAccessConditions - * 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. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.acquireLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersAcquireLeaseResponse acquireLease(String proposedID, int duration, - ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { - Mono response = containerAsyncRawClient.acquireLease(proposedID, duration, modifiedAccessConditions); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Renews the container's previously-acquired lease. For more information, see the - * Azure Docs. - * - * @param leaseID - * The leaseId of the active lease on the container. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.renewLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersRenewLeaseResponse renewLease(String leaseID) { - return this.renewLease(leaseID, null, null); - } - - /** - * Renews the container's previously-acquired lease. For more information, see the - * Azure Docs. - * - * @param leaseID - * The leaseId of the active lease on the container. - * @param modifiedAccessConditions - * 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. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.renewLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersRenewLeaseResponse renewLease(String leaseID, - ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { - Mono response = containerAsyncRawClient.renewLease(leaseID, modifiedAccessConditions); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Releases the container's previously-acquired lease. For more information, see the - * Azure Docs. - * - * @param leaseID - * The leaseId of the active lease on the container. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.releaseLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersReleaseLeaseResponse releaseLease(String leaseID) { - return this.releaseLease(leaseID, null, null); - } - - /** - * Releases the container's previously-acquired lease. For more information, see the - * Azure Docs. - * - * @param leaseID - * The leaseId of the active lease on the container. - * @param modifiedAccessConditions - * 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. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.releaseLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersReleaseLeaseResponse releaseLease(String leaseID, - ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { - Mono response = containerAsyncRawClient.releaseLease(leaseID, modifiedAccessConditions); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Breaks the container's previously-acquired lease. For more information, see the - * Azure Docs. - * - * @apiNote - * ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.breakLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/New-Storage-SDK-V10-Preview/src/test/java/com/microsoft/azure/storage/Samples.java) - * - * @return Emits the successful response. - */ - public ContainersBreakLeaseResponse breakLease() { - return this.breakLease(null, null, null); - } - - /** - * Breaks the container's previously-acquired lease. For more information, see the - * Azure Docs. - * - * @param breakPeriodInSeconds - * An optional {@code Integer} representing the proposed duration of seconds that the lease should continue - * before it is broken, between 0 and 60 seconds. This break period is only used if it is shorter than the time - * remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be - * available before the break period has expired, but the lease may be held for longer than the break period. - * @param modifiedAccessConditions - * 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. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.breakLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersBreakLeaseResponse breakLease(Integer breakPeriodInSeconds, - ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { - Mono response = containerAsyncRawClient.breakLease(breakPeriodInSeconds, modifiedAccessConditions); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Changes the container's leaseAccessConditions. For more information, see the - * Azure Docs. - * - * @param leaseID - * The leaseId of the active lease on the container. - * @param proposedID - * A {@code String} in any valid GUID format. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.changeLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersChangeLeaseResponse changeLease(String leaseID, String proposedID) { - return this.changeLease(leaseID, proposedID, null, null); - } - - /** - * Changes the container's leaseAccessConditions. For more information, see the - * Azure Docs. - * - * @param leaseID - * The leaseId of the active lease on the container. - * @param proposedID - * A {@code String} in any valid GUID format. - * @param modifiedAccessConditions - * 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. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.changeLease")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersChangeLeaseResponse changeLease(String leaseID, String proposedID, - ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { - Mono response = containerAsyncRawClient.changeLease(leaseID, proposedID, modifiedAccessConditions); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Returns a single segment of blobs starting from the specified Marker. Use an empty - * marker to start enumeration from the beginning. Blob names are returned in lexicographic order. - * After getting a segment, process it, and then call ListBlobs again (passing the the previously-returned - * Marker) to get the next segment. For more information, see the - * Azure Docs. - * - * @param marker - * Identifies the portion of the list to be returned with the next list operation. - * This value is returned in the response of a previous list operation as the - * ListBlobsFlatSegmentResponse.body().nextMarker(). Set to null to list the first segment. - * @param options - * {@link ListBlobsOptions} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_flat "Sample code for ContainerAsyncClient.listBlobsFlatSegment")] \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_flat_helper "helper code for ContainerAsyncClient.listBlobsFlatSegment")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersListBlobFlatSegmentResponse listBlobsFlatSegment(String marker, ListBlobsOptions options) { - return this.listBlobsFlatSegment(marker, options, null); - } - - /** - * Returns a single segment of blobs starting from the specified Marker. Use an empty - * marker to start enumeration from the beginning. Blob names are returned in lexicographic order. - * After getting a segment, process it, and then call ListBlobs again (passing the the previously-returned - * Marker) to get the next segment. For more information, see the - * Azure Docs. - * - * @param marker - * Identifies the portion of the list to be returned with the next list operation. - * This value is returned in the response of a previous list operation as the - * ListBlobsFlatSegmentResponse.body().nextMarker(). Set to null to list the first segment. - * @param options - * {@link ListBlobsOptions} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_flat "Sample code for ContainerAsyncClient.listBlobsFlatSegment")] \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_flat_helper "helper code for ContainerAsyncClient.listBlobsFlatSegment")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersListBlobFlatSegmentResponse listBlobsFlatSegment(String marker, ListBlobsOptions options, - Duration timeout) { - Mono response = containerAsyncRawClient.listBlobsFlatSegment(marker, options); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Returns a single segment of blobs and blob prefixes starting from the specified Marker. Use an empty - * marker to start enumeration from the beginning. Blob names are returned in lexicographic order. - * After getting a segment, process it, and then call ListBlobs again (passing the the previously-returned - * Marker) to get the next segment. For more information, see the - * Azure Docs. - * - * @param marker - * Identifies the portion of the list to be returned with the next list operation. - * This value is returned in the response of a previous list operation as the - * ListBlobsHierarchySegmentResponse.body().nextMarker(). Set to null to list the first segment. - * @param delimiter - * The operation returns a BlobPrefix element in the response body that acts as a placeholder for all blobs - * whose names begin with the same substring up to the appearance of the delimiter character. The delimiter may - * be a single character or a string. - * @param options - * {@link ListBlobsOptions} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy "Sample code for ContainerAsyncClient.listBlobsHierarchySegment")] \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy_helper "helper code for ContainerAsyncClient.listBlobsHierarchySegment")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersListBlobHierarchySegmentResponse listBlobsHierarchySegment(String marker, String delimiter, - ListBlobsOptions options) { - return this.listBlobsHierarchySegment(marker, delimiter, options, null); - } - - /** - * Returns a single segment of blobs and blob prefixes starting from the specified Marker. Use an empty - * marker to start enumeration from the beginning. Blob names are returned in lexicographic order. - * After getting a segment, process it, and then call ListBlobs again (passing the the previously-returned - * Marker) to get the next segment. For more information, see the - * Azure Docs. - * - * @param marker - * Identifies the portion of the list to be returned with the next list operation. - * This value is returned in the response of a previous list operation as the - * ListBlobsHierarchySegmentResponse.body().nextMarker(). Set to null to list the first segment. - * @param delimiter - * The operation returns a BlobPrefix element in the response body that acts as a placeholder for all blobs - * whose names begin with the same substring up to the appearance of the delimiter character. The delimiter may - * be a single character or a string. - * @param options - * {@link ListBlobsOptions} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy "Sample code for ContainerAsyncClient.listBlobsHierarchySegment")] \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy_helper "helper code for ContainerAsyncClient.listBlobsHierarchySegment")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersListBlobHierarchySegmentResponse listBlobsHierarchySegment(String marker, String delimiter, - ListBlobsOptions options, Duration timeout) { - Mono response = containerAsyncRawClient.listBlobsHierarchySegment(marker, delimiter, options); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Returns the sku name and account kind for the account. For more information, please see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=account_info "Sample code for ContainerAsyncClient.getAccountInfo")] \n - * For more samples, please see the [Samples file] (https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersGetAccountInfoResponse getAccountInfo() { - return this.getAccountInfo(null); - } - - /** - * Returns the sku name and account kind for the account. For more information, please see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=account_info "Sample code for ContainerAsyncClient.getAccountInfo")] \n - * For more samples, please see the [Samples file] (https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ContainersGetAccountInfoResponse getAccountInfo(Duration timeout) { - Mono response = containerAsyncRawClient.getAccountInfo(); - return Utility.blockWithOptionalTimeout(response, timeout); - } -} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobAsyncClient.java index 073df29744582..72f052fd27573 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobAsyncClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobAsyncClient.java @@ -5,6 +5,8 @@ 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.util.Context; import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; import com.azure.storage.blob.models.BlobAccessConditions; import com.azure.storage.blob.models.BlobHTTPHeaders; @@ -17,12 +19,14 @@ import com.azure.storage.blob.models.PageRange; import com.azure.storage.blob.models.SequenceNumberActionType; import com.azure.storage.blob.models.SourceModifiedAccessConditions; -import io.netty.buffer.Unpooled; +import io.netty.buffer.ByteBuf; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.net.MalformedURLException; import java.net.URL; -import java.nio.ByteBuffer; + +import static com.azure.storage.blob.Utility.postProcessResponse; /** * Client to a page blob. It may only be instantiated through a {@link PageBlobClientBuilder}, via @@ -48,9 +52,6 @@ * object through {@link Mono#toFuture()}. */ public final class PageBlobAsyncClient extends BlobAsyncClient { - - final PageBlobAsyncRawClient pageBlobAsyncRawClient; - /** * Indicates the number of bytes in a page. */ @@ -67,7 +68,6 @@ public final class PageBlobAsyncClient extends BlobAsyncClient { */ PageBlobAsyncClient(AzureBlobStorageBuilder azureBlobStorageBuilder, String snapshot) { super(azureBlobStorageBuilder, snapshot); - this.pageBlobAsyncRawClient = new PageBlobAsyncRawClient(azureBlobStorageBuilder.build(), snapshot); } /** @@ -104,13 +104,30 @@ public Mono> create(long size) { * @param accessConditions * {@link BlobAccessConditions} * - * @return - * A reactive response containing the information of the created page blob. + * @return A reactive response containing the information of the created page blob. + * @throws IllegalArgumentException If {@code size} isn't a multiple of {@link PageBlobAsyncClient#PAGE_BYTES} + * or {@code sequenceNumber} isn't null and is less than 0. */ public Mono> create(long size, Long sequenceNumber, BlobHTTPHeaders headers, Metadata metadata, BlobAccessConditions accessConditions) { - return pageBlobAsyncRawClient - .create(size, sequenceNumber, headers, metadata, accessConditions) + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + if (size % PAGE_BYTES != 0) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new IllegalArgumentException("size must be a multiple of PageBlobAsyncClient.PAGE_BYTES."); + } + if (sequenceNumber != null && sequenceNumber < 0) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new IllegalArgumentException("SequenceNumber must be greater than or equal to 0."); + } + metadata = metadata == null ? new Metadata() : metadata; + + return postProcessResponse(this.azureBlobStorage.pageBlobs().createWithRestResponseAsync(null, + null, 0, size, null, metadata, null, null, + null, sequenceNumber, null, headers, accessConditions.leaseAccessConditions(), + accessConditions.modifiedAccessConditions(), Context.NONE)) .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders()))); } @@ -133,7 +150,7 @@ public Mono> create(long size, Long sequenceNumber, BlobH * @return * A reactive response containing the information of the uploaded pages. */ - public Mono> uploadPages(PageRange pageRange, Flux body) { + public Mono> uploadPages(PageRange pageRange, Flux body) { return this.uploadPages(pageRange, body, null); } @@ -155,13 +172,25 @@ public Mono> uploadPages(PageRange pageRange, Flux> uploadPages(PageRange pageRange, Flux body, + public Mono> uploadPages(PageRange pageRange, Flux body, PageBlobAccessConditions pageBlobAccessConditions) { - return pageBlobAsyncRawClient - .uploadPages(pageRange, body.map(Unpooled::wrappedBuffer), pageBlobAccessConditions) + pageBlobAccessConditions = pageBlobAccessConditions == null ? new PageBlobAccessConditions() : pageBlobAccessConditions; + + if (pageRange == null) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new IllegalArgumentException("pageRange cannot be null."); + } + String pageRangeStr = pageRangeToString(pageRange); + + return postProcessResponse(this.azureBlobStorage.pageBlobs().uploadPagesWithRestResponseAsync(null, + null, body, pageRange.end() - pageRange.start() + 1, null, + null, pageRangeStr, null, null, null, null, + pageBlobAccessConditions.leaseAccessConditions(), pageBlobAccessConditions.sequenceNumberAccessConditions(), + pageBlobAccessConditions.modifiedAccessConditions(), Context.NONE)) .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders()))); } @@ -218,15 +247,33 @@ public Mono> uploadPagesFromURL(PageRange range, URL sour * @param sourceAccessConditions * {@link SourceModifiedAccessConditions} * - * @return - * A reactive response containing the information of the uploaded pages. + * @return A reactive response containing the information of the uploaded pages. + * @throws IllegalArgumentException If {@code range} is {@code null} */ public Mono> uploadPagesFromURL(PageRange range, URL sourceURL, Long sourceOffset, byte[] sourceContentMD5, PageBlobAccessConditions destAccessConditions, SourceModifiedAccessConditions sourceAccessConditions) { + if (range == null) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new IllegalArgumentException("range cannot be null."); + } + + String rangeString = pageRangeToString(range); - return pageBlobAsyncRawClient - .uploadPagesFromURL(range, sourceURL, sourceOffset, sourceContentMD5, destAccessConditions, sourceAccessConditions) + if (sourceOffset == null) { + sourceOffset = 0L; + } + + String sourceRangeString = pageRangeToString(new PageRange().start(sourceOffset).end(sourceOffset + (range.end() - range.start()))); + + destAccessConditions = destAccessConditions == null ? new PageBlobAccessConditions() : destAccessConditions; + + return postProcessResponse(this.azureBlobStorage.pageBlobs().uploadPagesFromURLWithRestResponseAsync( + null, null, sourceURL, sourceRangeString, 0, rangeString, sourceContentMD5, + null, null, destAccessConditions.leaseAccessConditions(), + destAccessConditions.sequenceNumberAccessConditions(), destAccessConditions.modifiedAccessConditions(), + sourceAccessConditions, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders()))); } @@ -259,13 +306,23 @@ public Mono> clearPages(PageRange pageRange) { * @param pageBlobAccessConditions * {@link PageBlobAccessConditions} * - * @return - * A reactive response containing the information of the cleared pages. + * @return A reactive response containing the information of the cleared pages. + * @throws IllegalArgumentException If {@code pageRange} is {@code null} */ public Mono> clearPages(PageRange pageRange, PageBlobAccessConditions pageBlobAccessConditions) { - return pageBlobAsyncRawClient - .clearPages(pageRange, pageBlobAccessConditions) + pageBlobAccessConditions = pageBlobAccessConditions == null ? new PageBlobAccessConditions() : pageBlobAccessConditions; + if (pageRange == null) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new IllegalArgumentException("pageRange cannot be null."); + } + String pageRangeStr = pageRangeToString(pageRange); + + return postProcessResponse(this.azureBlobStorage.pageBlobs().clearPagesWithRestResponseAsync(null, + null, 0, null, pageRangeStr, null, + pageBlobAccessConditions.leaseAccessConditions(), pageBlobAccessConditions.sequenceNumberAccessConditions(), + pageBlobAccessConditions.modifiedAccessConditions(), Context.NONE)) .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders()))); } @@ -295,10 +352,14 @@ public Flux getPageRanges(BlobRange blobRange) { * @return * A reactive response emitting all the page ranges. */ - public Flux getPageRanges(BlobRange blobRange, - BlobAccessConditions accessConditions) { - return pageBlobAsyncRawClient - .getPageRanges(blobRange, accessConditions) + public Flux getPageRanges(BlobRange blobRange, BlobAccessConditions accessConditions) { + blobRange = blobRange == null ? new BlobRange(0) : blobRange; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.pageBlobs().getPageRangesWithRestResponseAsync( + null, null, snapshot, null, null, blobRange.toHeaderValue(), + null, accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), + Context.NONE)) .flatMapMany(response -> Flux.fromIterable(response.value().pageRange())); } @@ -333,13 +394,21 @@ public Flux getPageRangesDiff(BlobRange blobRange, String prevSnapsho * @param accessConditions * {@link BlobAccessConditions} * - * @return - * A reactive response emitting all the different page ranges. + * @return A reactive response emitting all the different page ranges. + * @throws IllegalArgumentException If {@code prevSnapshot} is {@code null} */ - public Flux getPageRangesDiff(BlobRange blobRange, String prevSnapshot, - BlobAccessConditions accessConditions) { - return pageBlobAsyncRawClient - .getPageRangesDiff(blobRange, prevSnapshot, accessConditions) + public Flux getPageRangesDiff(BlobRange blobRange, String prevSnapshot, BlobAccessConditions accessConditions) { + blobRange = blobRange == null ? new BlobRange(0) : blobRange; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + if (prevSnapshot == null) { + throw new IllegalArgumentException("prevSnapshot cannot be null"); + } + + return postProcessResponse(this.azureBlobStorage.pageBlobs().getPageRangesDiffWithRestResponseAsync( + null, null, snapshot, null, null, prevSnapshot, + blobRange.toHeaderValue(), null, accessConditions.leaseAccessConditions(), + accessConditions.modifiedAccessConditions(), Context.NONE)) .flatMapMany(response -> Flux.fromIterable(response.value().pageRange())); } @@ -368,12 +437,20 @@ public Mono> resize(long size) { * @param accessConditions * {@link BlobAccessConditions} * - * @return - * A reactive response emitting the resized page blob. + * @return A reactive response emitting the resized page blob. + * @throws IllegalArgumentException If {@code size} isn't a multiple of {@link PageBlobAsyncClient#PAGE_BYTES} */ public Mono> resize(long size, BlobAccessConditions accessConditions) { - return pageBlobAsyncRawClient - .resize(size, accessConditions) + if (size % PAGE_BYTES != 0) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new IllegalArgumentException("size must be a multiple of PageBlobAsyncClient.PAGE_BYTES."); + } + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.pageBlobs().resizeWithRestResponseAsync(null, + null, size, null, null, accessConditions.leaseAccessConditions(), + accessConditions.modifiedAccessConditions(), Context.NONE)) .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders()))); } @@ -407,13 +484,22 @@ public Mono> updateSequenceNumber(SequenceNumberActionTyp * @param accessConditions * {@link BlobAccessConditions} * - * @return - * A reactive response emitting the updated page blob. + * @return A reactive response emitting the updated page blob. + * @throws IllegalArgumentException If {@code sequenceNumber} isn't null and is less than 0 */ - public Mono> updateSequenceNumber(SequenceNumberActionType action, - Long sequenceNumber, BlobAccessConditions accessConditions) { - return pageBlobAsyncRawClient - .updateSequenceNumber(action, sequenceNumber, accessConditions) + public Mono> updateSequenceNumber(SequenceNumberActionType action, Long sequenceNumber, BlobAccessConditions accessConditions) { + if (sequenceNumber != null && sequenceNumber < 0) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new IllegalArgumentException("SequenceNumber must be greater than or equal to 0."); + } + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + sequenceNumber = action == SequenceNumberActionType.INCREMENT ? null : sequenceNumber; + + return postProcessResponse( + this.azureBlobStorage.pageBlobs().updateSequenceNumberWithRestResponseAsync(null, + null, action, null, sequenceNumber, null, + accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)) .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders()))); } @@ -454,13 +540,37 @@ public Mono> copyIncremental(URL source, String snapsho * 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. + * @return A reactive response emitting the copy status. + * @throws Error If {@code source} and {@code snapshot} form a malformed URL. */ - public Mono> copyIncremental(URL source, String snapshot, - ModifiedAccessConditions modifiedAccessConditions) { - return pageBlobAsyncRawClient - .copyIncremental(source, snapshot, modifiedAccessConditions) + public Mono> copyIncremental(URL source, String snapshot, ModifiedAccessConditions modifiedAccessConditions) { + UrlBuilder builder = UrlBuilder.parse(source); + builder.setQueryParameter(Constants.SNAPSHOT_QUERY_PARAMETER, snapshot); + try { + 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); + } + return postProcessResponse(this.azureBlobStorage.pageBlobs().copyIncrementalWithRestResponseAsync( + null, null, source, null, null, modifiedAccessConditions, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().copyStatus())); } + + private static String pageRangeToString(PageRange pageRange) { + if (pageRange.start() < 0 || pageRange.end() <= 0) { + throw new IllegalArgumentException("PageRange's start and end values must be greater than or equal to " + + "0 if specified."); + } + if (pageRange.start() % PAGE_BYTES != 0) { + throw new IllegalArgumentException("PageRange's start value must be a multiple of 512."); + } + if (pageRange.end() % PAGE_BYTES != PAGE_BYTES - 1) { + throw new IllegalArgumentException("PageRange's end value must be 1 less than a multiple of 512."); + } + if (pageRange.end() <= pageRange.start()) { + throw new IllegalArgumentException("PageRange's End value must be after the start."); + } + return "bytes=" + pageRange.start() + '-' + pageRange.end(); + } } diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobAsyncRawClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobAsyncRawClient.java deleted file mode 100644 index fba55bd8d7455..0000000000000 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobAsyncRawClient.java +++ /dev/null @@ -1,620 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.storage.blob; - -import com.azure.core.implementation.http.UrlBuilder; -import com.azure.core.util.Context; -import com.azure.storage.blob.implementation.AzureBlobStorageImpl; -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.Metadata; -import com.azure.storage.blob.models.ModifiedAccessConditions; -import com.azure.storage.blob.models.PageBlobAccessConditions; -import com.azure.storage.blob.models.PageBlobsClearPagesResponse; -import com.azure.storage.blob.models.PageBlobsCopyIncrementalResponse; -import com.azure.storage.blob.models.PageBlobsCreateResponse; -import com.azure.storage.blob.models.PageBlobsGetPageRangesDiffResponse; -import com.azure.storage.blob.models.PageBlobsGetPageRangesResponse; -import com.azure.storage.blob.models.PageBlobsResizeResponse; -import com.azure.storage.blob.models.PageBlobsUpdateSequenceNumberResponse; -import com.azure.storage.blob.models.PageBlobsUploadPagesFromURLResponse; -import com.azure.storage.blob.models.PageBlobsUploadPagesResponse; -import com.azure.storage.blob.models.PageRange; -import com.azure.storage.blob.models.SequenceNumberActionType; -import com.azure.storage.blob.models.SourceModifiedAccessConditions; -import io.netty.buffer.ByteBuf; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.net.MalformedURLException; -import java.net.URL; - -import static com.azure.storage.blob.Utility.postProcessResponse; - -/** - * Represents a URL to a page blob. It may be obtained by direct construction or via the create method on a - * {@link ContainerAsyncClient} object. This class does not hold any state about a particular blob but is instead a convenient - * way of sending off appropriate requests to the resource on the service. Please refer to the - * Azure Docs - * for more information. - */ -final class PageBlobAsyncRawClient extends BlobAsyncRawClient { - - /** - * Indicates the number of bytes in a page. - */ - public static final int PAGE_BYTES = 512; - - /** - * Indicates the maximum number of bytes that may be sent in a call to putPage. - */ - public static final int MAX_PUT_PAGES_BYTES = 4 * Constants.MB; - - /** - * Creates a {@code PageBlobAsyncRawClient} object pointing to the account specified by the URL and using the provided - * pipeline to make HTTP requests. - * - */ - PageBlobAsyncRawClient(AzureBlobStorageImpl azureBlobStorage, String snapshot) { - super(azureBlobStorage, snapshot); - } - - private static String pageRangeToString(PageRange pageRange) { - if (pageRange.start() < 0 || pageRange.end() <= 0) { - throw new IllegalArgumentException("PageRange's start and end values must be greater than or equal to " - + "0 if specified."); - } - if (pageRange.start() % PageBlobAsyncRawClient.PAGE_BYTES != 0) { - throw new IllegalArgumentException("PageRange's start value must be a multiple of 512."); - } - if (pageRange.end() % PageBlobAsyncRawClient.PAGE_BYTES != PageBlobAsyncRawClient.PAGE_BYTES - 1) { - throw new IllegalArgumentException("PageRange's end value must be 1 less than a multiple of 512."); - } - if (pageRange.end() <= pageRange.start()) { - throw new IllegalArgumentException("PageRange's End value must be after the start."); - } - return new StringBuilder("bytes=").append(pageRange.start()).append('-').append(pageRange.end()).toString(); - } - - /** - * Creates a page blob of the specified length. Call PutPage to upload data data to a page blob. - * For more information, see the - * Azure Docs. - * - * @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. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.create")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono create(long size) { - return this.create(size, null, null, null, null); - } - - /** - * Creates a page blob of the specified length. Call PutPage to upload data data to a page blob. - * For more information, see the - * Azure Docs. - * - * @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. - * @param sequenceNumber - * A user-controlled value that you can use to track requests. The value of the sequence number must be - * between 0 and 2^63 - 1.The default value is 0. - * @param headers - * {@link BlobHTTPHeaders} - * @param metadata - * {@link Metadata} - * @param accessConditions - * {@link BlobAccessConditions} - * - * @return Emits the successful response. - * @throws IllegalArgumentException If {@code size} isn't a multiple of {@link PageBlobAsyncRawClient#PAGE_BYTES} - * or {@code sequenceNumber} isn't null and is less than 0. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.create")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono create(long size, Long sequenceNumber, BlobHTTPHeaders headers, - Metadata metadata, BlobAccessConditions accessConditions) { - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - if (size % PageBlobAsyncRawClient.PAGE_BYTES != 0) { - // Throwing is preferred to Single.error because this will error out immediately instead of waiting until - // subscription. - throw new IllegalArgumentException("size must be a multiple of PageBlobAsyncRawClient.PAGE_BYTES."); - } - if (sequenceNumber != null && sequenceNumber < 0) { - // Throwing is preferred to Single.error because this will error out immediately instead of waiting until - // subscription. - throw new IllegalArgumentException("SequenceNumber must be greater than or equal to 0."); - } - metadata = metadata == null ? new Metadata() : metadata; - - return postProcessResponse(this.azureBlobStorage.pageBlobs().createWithRestResponseAsync(null, - null, 0, size, null, metadata, null, null, - null, sequenceNumber, null, headers, accessConditions.leaseAccessConditions(), - accessConditions.modifiedAccessConditions(), Context.NONE)); - } - - /** - * Writes 1 or more pages to the page blob. The start and end offsets must be a multiple of 512. - * For more information, see the - * 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. - * - * @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 are - * 0-511, 512-1023, etc. - * @param body - * The data to upload. Note that this {@code Flux} must be replayable if retries are enabled - * (the default). In other words, the Flowable must produce the same data each time it is subscribed to. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.uploadPages")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono uploadPages(PageRange pageRange, Flux body) { - return this.uploadPages(pageRange, body, null); - } - - /** - * Writes 1 or more pages to the page blob. The start and end offsets must be a multiple of 512. - * For more information, see the - * 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. - * - * @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 - * are 0-511, 512-1023, etc. - * @param body - * The data to upload. Note that this {@code Flux} must be replayable if retries are enabled - * (the default). In other words, the Flowable must produce the same data each time it is subscribed to. - * @param pageBlobAccessConditions - * {@link PageBlobAccessConditions} - * - * @return Emits the successful response. - * @throws IllegalArgumentException If {@code pageRange} is {@code null} - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.uploadPages")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono uploadPages(PageRange pageRange, Flux body, - PageBlobAccessConditions pageBlobAccessConditions) { - pageBlobAccessConditions = pageBlobAccessConditions == null ? new PageBlobAccessConditions() - : pageBlobAccessConditions; - - if (pageRange == null) { - // Throwing is preferred to Single.error because this will error out immediately instead of waiting until - // subscription. - throw new IllegalArgumentException("pageRange cannot be null."); - } - String pageRangeStr = pageRangeToString(pageRange); - - return postProcessResponse(this.azureBlobStorage.pageBlobs().uploadPagesWithRestResponseAsync(null, - null, body, pageRange.end() - pageRange.start() + 1, null, - null, pageRangeStr, null, null, null, null, - pageBlobAccessConditions.leaseAccessConditions(), pageBlobAccessConditions.sequenceNumberAccessConditions(), - pageBlobAccessConditions.modifiedAccessConditions(), Context.NONE)); - } - - /** - * Writes 1 or more pages from the source page blob to this page blob. The start and end offsets must be a multiple - * of 512. - * For more information, see the - * Azure Docs. - *

- * - * @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 - * are 0-511, 512-1023, etc. - * @param sourceURL - * The url to the blob that will be the source of the copy. A source blob in the same storage account can be - * authenticated via Shared Key. However, if the source is a blob in another account, the source blob must - * either be public or must be authenticated via a shared access signature. If the source blob is public, no - * authentication is required to perform the operation. - * @param sourceOffset - * The source offset to copy from. Pass null or 0 to copy from the beginning of source page blob. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_from_url "Sample code for PageBlobAsyncRawClient.uploadPagesFromURL")] - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono uploadPagesFromURL(PageRange range, URL sourceURL, Long sourceOffset) { - return this.uploadPagesFromURL(range, sourceURL, sourceOffset, null, null, - null); - } - - /** - * Writes 1 or more pages from the source page blob to this page blob. The start and end offsets must be a multiple - * of 512. - * For more information, see the - * Azure Docs. - *

- * - * @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 ranges - * are 0-511, 512-1023, etc. - * @param sourceURL - * The url to the blob that will be the source of the copy. A source blob in the same storage account can be - * authenticated via Shared Key. However, if the source is a blob in another account, the source blob must - * either be public or must be authenticated via a shared access signature. If the source blob is public, no - * authentication is required to perform the operation. - * @param sourceOffset - * The source offset to copy from. Pass null or 0 to copy from the beginning of source blob. - * @param sourceContentMD5 - * An MD5 hash of the block content from the source blob. If specified, the service will calculate the MD5 - * of the received data and fail the request if it does not match the provided MD5. - * @param destAccessConditions - * {@link PageBlobAccessConditions} - * @param sourceAccessConditions - * {@link SourceModifiedAccessConditions} - * - * @return Emits the successful response. - * @throws IllegalArgumentException If {@code range} is {@code null} - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_from_url "Sample code for PageBlobAsyncRawClient.uploadPagesFromURL")] - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono uploadPagesFromURL(PageRange range, URL sourceURL, Long sourceOffset, - byte[] sourceContentMD5, PageBlobAccessConditions destAccessConditions, - SourceModifiedAccessConditions sourceAccessConditions) { - - if (range == null) { - // Throwing is preferred to Single.error because this will error out immediately instead of waiting until - // subscription. - throw new IllegalArgumentException("range cannot be null."); - } - - String rangeString = pageRangeToString(range); - - if (sourceOffset == null) { - sourceOffset = 0L; - } - - String sourceRangeString = pageRangeToString(new PageRange().start(sourceOffset).end(sourceOffset + (range.end() - range.start()))); - - destAccessConditions = destAccessConditions == null ? new PageBlobAccessConditions() : destAccessConditions; - - return postProcessResponse(this.azureBlobStorage.pageBlobs().uploadPagesFromURLWithRestResponseAsync( - null, null, sourceURL, sourceRangeString, 0, rangeString, sourceContentMD5, - null, null, destAccessConditions.leaseAccessConditions(), - destAccessConditions.sequenceNumberAccessConditions(), destAccessConditions.modifiedAccessConditions(), - sourceAccessConditions, Context.NONE)); - } - - /** - * Frees the specified pages from the page blob. - * For more information, see the - * Azure Docs. - * - * @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 - * are 0-511, 512-1023, etc. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.clearPages")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono clearPages(PageRange pageRange) { - return this.clearPages(pageRange, null); - } - - /** - * Frees the specified pages from the page blob. - * For more information, see the - * Azure Docs. - * - * @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 - * are 0-511, 512-1023, etc. - * @param pageBlobAccessConditions - * {@link PageBlobAccessConditions} - * - * @return Emits the successful response. - * @throws IllegalArgumentException If {@code pageRange} is {@code null} - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.clearPages")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono clearPages(PageRange pageRange, - PageBlobAccessConditions pageBlobAccessConditions) { - pageBlobAccessConditions = pageBlobAccessConditions == null ? new PageBlobAccessConditions() - : pageBlobAccessConditions; - if (pageRange == null) { - // Throwing is preferred to Single.error because this will error out immediately instead of waiting until - // subscription. - throw new IllegalArgumentException("pageRange cannot be null."); - } - String pageRangeStr = pageRangeToString(pageRange); - - return postProcessResponse(this.azureBlobStorage.pageBlobs().clearPagesWithRestResponseAsync(null, - null, 0, null, pageRangeStr, null, - pageBlobAccessConditions.leaseAccessConditions(), pageBlobAccessConditions.sequenceNumberAccessConditions(), - pageBlobAccessConditions.modifiedAccessConditions(), Context.NONE)); - } - - /** - * Returns the list of valid page ranges for a page blob or snapshot of a page blob. - * For more information, see the Azure Docs. - * - * @param blobRange - * {@link BlobRange} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.getPageRanges")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono getPageRanges(BlobRange blobRange) { - return this.getPageRanges(blobRange, null); - } - - /** - * Returns the list of valid page ranges for a page blob or snapshot of a page blob. - * For more information, see the Azure Docs. - * - * @param blobRange - * {@link BlobRange} - * @param accessConditions - * {@link BlobAccessConditions} - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.getPageRanges")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono getPageRanges(BlobRange blobRange, - BlobAccessConditions accessConditions) { - blobRange = blobRange == null ? new BlobRange(0) : blobRange; - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - return postProcessResponse(this.azureBlobStorage.pageBlobs().getPageRangesWithRestResponseAsync( - null, null, snapshot, null, null, blobRange.toHeaderValue(), - null, accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), - Context.NONE)); - } - - /** - * Gets the collection of page ranges that differ between a specified snapshot and this page blob. - * For more information, see the Azure Docs. - * - * @param blobRange - * {@link BlobRange} - * @param prevSnapshot - * Specifies that the response will contain only pages that were changed between target blob and previous - * snapshot. Changed pages include both updated and cleared pages. The target - * blob may be a snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_diff "Sample code for PageBlobAsyncRawClient.getPageRangesDiff")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono getPageRangesDiff(BlobRange blobRange, String prevSnapshot) { - return this.getPageRangesDiff(blobRange, prevSnapshot, null); - } - - /** - * Gets the collection of page ranges that differ between a specified snapshot and this page blob. - * For more information, see the Azure Docs. - * - * @param blobRange - * {@link BlobRange} - * @param prevSnapshot - * Specifies that the response will contain only pages that were changed between target blob and previous - * snapshot. Changed pages include both updated and cleared pages. The target - * blob may be a snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. - * @param accessConditions - * {@link BlobAccessConditions} - * - * @return Emits the successful response. - * @throws IllegalArgumentException If {@code prevSnapshot} is {@code null} - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_diff "Sample code for PageBlobAsyncRawClient.getPageRangesDiff")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono getPageRangesDiff(BlobRange blobRange, String prevSnapshot, - BlobAccessConditions accessConditions) { - blobRange = blobRange == null ? new BlobRange(0) : blobRange; - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - if (prevSnapshot == null) { - throw new IllegalArgumentException("prevSnapshot cannot be null"); - } - - return postProcessResponse(this.azureBlobStorage.pageBlobs().getPageRangesDiffWithRestResponseAsync( - null, null, snapshot, null, null, prevSnapshot, - blobRange.toHeaderValue(), null, accessConditions.leaseAccessConditions(), - accessConditions.modifiedAccessConditions(), Context.NONE)); - } - - /** - * Resizes the page blob to the specified size (which must be a multiple of 512). - * For more information, see the Azure Docs. - * - * @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. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.resize")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono resize(long size) { - return this.resize(size, null); - } - - /** - * Resizes the page blob to the specified size (which must be a multiple of 512). - * For more information, see the Azure Docs. - * - * @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. - * @param accessConditions - * {@link BlobAccessConditions} - * - * @return Emits the successful response. - * @throws IllegalArgumentException If {@code size} isn't a multiple of {@link PageBlobAsyncRawClient#PAGE_BYTES} - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.resize")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono resize(long size, BlobAccessConditions accessConditions) { - if (size % PageBlobAsyncRawClient.PAGE_BYTES != 0) { - // Throwing is preferred to Single.error because this will error out immediately instead of waiting until - // subscription. - throw new IllegalArgumentException("size must be a multiple of PageBlobAsyncRawClient.PAGE_BYTES."); - } - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - - return postProcessResponse(this.azureBlobStorage.pageBlobs().resizeWithRestResponseAsync(null, - null, size, null, null, accessConditions.leaseAccessConditions(), - accessConditions.modifiedAccessConditions(), Context.NONE)); - } - - /** - * Sets the page blob's sequence number. - * For more information, see the Azure Docs. - * - * @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 use to track - * requests and manage concurrency issues. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.updateSequenceNumber")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono updateSequenceNumber(SequenceNumberActionType action, - Long sequenceNumber) { - return this.updateSequenceNumber(action, sequenceNumber, null); - } - - /** - * Sets the page blob's sequence number. - * For more information, see the Azure Docs. - * - * @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 use to track - * requests and manage concurrency issues. - * @param accessConditions - * {@link BlobAccessConditions} - * - * @return Emits the successful response. - * @throws IllegalArgumentException If {@code sequenceNumber} isn't null and is less than 0 - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.updateSequenceNumber")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono updateSequenceNumber(SequenceNumberActionType action, - Long sequenceNumber, BlobAccessConditions accessConditions) { - if (sequenceNumber != null && sequenceNumber < 0) { - // Throwing is preferred to Single.error because this will error out immediately instead of waiting until - // subscription. - throw new IllegalArgumentException("SequenceNumber must be greater than or equal to 0."); - } - accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; - sequenceNumber = action == SequenceNumberActionType.INCREMENT ? null : sequenceNumber; - - return postProcessResponse( - this.azureBlobStorage.pageBlobs().updateSequenceNumberWithRestResponseAsync(null, - null, action, null, sequenceNumber, null, - accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)); - } - - /** - * Begins an operation to start an incremental copy from one page blob's snapshot to this page - * blob. The snapshot is copied such that only the differential changes between the previously copied snapshot are - * transferred to the destination. The copied snapshots are complete copies of the original snapshot and can be read - * or copied from as usual. For more information, see - * the Azure Docs here and - * here. - * - * @param source - * The source page blob. - * @param snapshot - * The snapshot on the copy source. - * - * @return Emits the successful response. - */ - public Mono copyIncremental(URL source, String snapshot) { - return this.copyIncremental(source, snapshot, null); - } - - /** - * Begins an operation to start an incremental copy from one page blob's snapshot to this page - * blob. The snapshot is copied such that only the differential changes between the previously copied snapshot are - * transferred to the destination. The copied snapshots are complete copies of the original snapshot and can be read - * or copied from as usual. For more information, see - * the Azure Docs here and - * here. - * - * @param source - * The source page blob. - * @param snapshot - * The snapshot on the copy source. - * @param modifiedAccessConditions - * 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. - * - * @return Emits the successful response. - * @throws Error If {@code source} and {@code snapshot} form a malformed URL. - */ - public Mono copyIncremental(URL source, String snapshot, - ModifiedAccessConditions modifiedAccessConditions) { - - UrlBuilder builder = UrlBuilder.parse(source); - builder.setQueryParameter(Constants.SNAPSHOT_QUERY_PARAMETER, snapshot); - try { - 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); - } - return postProcessResponse(this.azureBlobStorage.pageBlobs().copyIncrementalWithRestResponseAsync( - null, null, source, null, null, modifiedAccessConditions, Context.NONE)); - } -} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobClient.java index 284f74d0216ac..62d2146ea8d61 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobClient.java @@ -15,13 +15,14 @@ import com.azure.storage.blob.models.PageRange; import com.azure.storage.blob.models.SequenceNumberActionType; import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; import java.io.InputStream; import java.net.URL; -import java.nio.ByteBuffer; import java.time.Duration; /** @@ -45,12 +46,12 @@ public final class PageBlobClient extends BlobClient { /** * Indicates the number of bytes in a page. */ - public static final int PAGE_BYTES = 512; + public static final int PAGE_BYTES = PageBlobAsyncClient.PAGE_BYTES; /** * Indicates the maximum number of bytes that may be sent in a call to putPage. */ - public static final int MAX_PUT_PAGES_BYTES = 4 * Constants.MB; + public static final int MAX_PUT_PAGES_BYTES = PageBlobAsyncClient.MAX_PUT_PAGES_BYTES; /** * Package-private constructor for use by {@link PageBlobClientBuilder}. @@ -189,7 +190,7 @@ public Response uploadPages(PageRange pageRange, InputStream body) public Response uploadPages(PageRange pageRange, InputStream body, PageBlobAccessConditions pageBlobAccessConditions, Duration timeout) { long length = pageRange.end() - pageRange.start(); - Flux fbb = Flux.range(0, (int) Math.ceil((double) length / (double) PAGE_BYTES)) + Flux fbb = Flux.range(0, (int) Math.ceil((double) length / (double) PAGE_BYTES)) .map(i -> i * PAGE_BYTES) .concatMap(pos -> Mono.fromCallable(() -> { byte[] cache = new byte[PAGE_BYTES]; @@ -197,7 +198,8 @@ public Response uploadPages(PageRange pageRange, InputStream body, while (read < PAGE_BYTES) { read += body.read(cache, read, PAGE_BYTES - read); } - return ByteBuffer.wrap(cache); + + return ByteBufAllocator.DEFAULT.buffer(read).writeBytes(cache); })); Mono> response = pageBlobAsyncClient.uploadPages(pageRange, diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ServiceSASSignatureValues.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ServiceSASSignatureValues.java index 114c28eb71209..f6b4767cada56 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/ServiceSASSignatureValues.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ServiceSASSignatureValues.java @@ -12,10 +12,10 @@ import java.time.OffsetDateTime; /** - * ServiceSASSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage service. Once - * all the values here are set appropriately, call generateSASQueryParameters to obtain a representation of the SAS - * which can actually be applied to blob urls. Note: that both this class and {@link SASQueryParameters} exist because - * the former is mutable and a logical representation while the latter is immutable and used to generate actual REST + * ServiceSASSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage service. Once all + * the values here are set appropriately, call generateSASQueryParameters to obtain a representation of the SAS which + * can actually be applied to blob urls. Note: that both this class and {@link SASQueryParameters} exist because the + * former is mutable and a logical representation while the latter is immutable and used to generate actual REST * requests. *

* Please see here @@ -24,9 +24,9 @@ * Please see here for * more details on each value, including which are required. * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_sas "Sample code for ServiceSASSignatureValues")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + * @apiNote ## Sample Code \n [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_sas + * "Sample code for ServiceSASSignatureValues")] \n For more samples, please see the [Samples + * file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) */ final class ServiceSASSignatureValues { @@ -68,6 +68,7 @@ final class ServiceSASSignatureValues { /** * Creates an object with the specified expiry time and permissions + * * @param expiryTime * @param permissions */ @@ -78,6 +79,7 @@ final class ServiceSASSignatureValues { /** * Creates an object with the specified identifier + * * @param identifier */ ServiceSASSignatureValues(String identifier) { @@ -85,8 +87,8 @@ final class ServiceSASSignatureValues { } ServiceSASSignatureValues(String version, SASProtocol sasProtocol, OffsetDateTime startTime, - OffsetDateTime expiryTime, String permission, IPRange ipRange, String identifier, String cacheControl, - String contentDisposition, String contentEncoding, String contentLanguage, String contentType) { + OffsetDateTime expiryTime, String permission, IPRange ipRange, String identifier, String cacheControl, + String contentDisposition, String contentEncoding, String contentLanguage, String contentType) { if (version != null) { this.version = version; } @@ -229,6 +231,7 @@ public ServiceSASSignatureValues canonicalName(String canonicalName) { /** * The canonical name of the object the SAS user may access. + * * @throws RuntimeException If urlString is a malformed URL. */ public ServiceSASSignatureValues canonicalName(String urlString, String accountName) { @@ -359,9 +362,7 @@ public ServiceSASSignatureValues contentType(String contentType) { * Uses an account's shared key credential to sign these signature values to produce the proper SAS query * parameters. * - * @param sharedKeyCredentials - * A {@link SharedKeyCredential} object used to sign the SAS values. - * + * @param sharedKeyCredentials A {@link SharedKeyCredential} object used to sign the SAS values. * @return {@link SASQueryParameters} * @throws Error If the accountKey is not a valid Base64-encoded string. */ @@ -380,17 +381,15 @@ public SASQueryParameters generateSASQueryParameters(SharedKeyCredential sharedK } return new SASQueryParameters(this.version, null, null, - this.protocol, this.startTime, this.expiryTime, this.ipRange, this.identifier, resource, - this.permissions, signature, this.cacheControl, this.contentDisposition, this.contentEncoding, - this.contentLanguage, this.contentType, null /* delegate */); + this.protocol, this.startTime, this.expiryTime, this.ipRange, this.identifier, resource, + this.permissions, signature, this.cacheControl, this.contentDisposition, this.contentEncoding, + this.contentLanguage, this.contentType, null /* delegate */); } /** * Uses a user delegation key to sign these signature values to produce the proper SAS query parameters. * - * @param delegationKey - * A {@link UserDelegationKey} object used to sign the SAS values. - * + * @param delegationKey A {@link UserDelegationKey} object used to sign the SAS values. * @return {@link SASQueryParameters} * @throws Error If the accountKey is not a valid Base64-encoded string. */ @@ -409,9 +408,9 @@ public SASQueryParameters generateSASQueryParameters(UserDelegationKey delegatio } return new SASQueryParameters(this.version, null, null, - this.protocol, this.startTime, this.expiryTime, this.ipRange, null /* identifier */, resource, - this.permissions, signature, this.cacheControl, this.contentDisposition, this.contentEncoding, - this.contentLanguage, this.contentType, delegationKey); + this.protocol, this.startTime, this.expiryTime, this.ipRange, null /* identifier */, resource, + this.permissions, signature, this.cacheControl, this.contentDisposition, this.contentEncoding, + this.contentLanguage, this.contentType, delegationKey); } /** @@ -441,46 +440,46 @@ private void assertGenerateOK(boolean usingUserDelegation) { private String stringToSign() { return String.join("\n", - this.permissions == null ? "" : this.permissions, - this.startTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.startTime), - this.expiryTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.expiryTime), - this.canonicalName == null ? "" : this.canonicalName, - this.identifier == null ? "" : this.identifier, - this.ipRange == null ? (new IPRange()).toString() : this.ipRange.toString(), - this.protocol == null ? "" : protocol.toString(), - this.version == null ? "" : this.version, - this.resource == null ? "" : this.resource, - this.snapshotId == null ? "" : this.snapshotId, - this.cacheControl == null ? "" : this.cacheControl, - this.contentDisposition == null ? "" : this.contentDisposition, - this.contentEncoding == null ? "" : this.contentEncoding, - this.contentLanguage == null ? "" : this.contentLanguage, - this.contentType == null ? "" : this.contentType + this.permissions == null ? "" : this.permissions, + this.startTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.startTime), + this.expiryTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.expiryTime), + this.canonicalName == null ? "" : this.canonicalName, + this.identifier == null ? "" : this.identifier, + this.ipRange == null ? (new IPRange()).toString() : this.ipRange.toString(), + this.protocol == null ? "" : protocol.toString(), + this.version == null ? "" : this.version, + this.resource == null ? "" : this.resource, + this.snapshotId == null ? "" : this.snapshotId, + this.cacheControl == null ? "" : this.cacheControl, + this.contentDisposition == null ? "" : this.contentDisposition, + this.contentEncoding == null ? "" : this.contentEncoding, + this.contentLanguage == null ? "" : this.contentLanguage, + this.contentType == null ? "" : this.contentType ); } private String stringToSign(final UserDelegationKey key) { return String.join("\n", - this.permissions == null ? "" : this.permissions, - this.startTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.startTime), - this.expiryTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.expiryTime), - this.canonicalName == null ? "" : this.canonicalName, - key.signedOid() == null ? "" : key.signedOid(), - key.signedTid() == null ? "" : key.signedTid(), - key.signedStart() == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(key.signedStart()), - key.signedExpiry() == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(key.signedExpiry()), - key.signedService() == null ? "" : key.signedService(), - key.signedVersion() == null ? "" : key.signedVersion(), - this.ipRange == null ? new IPRange().toString() : this.ipRange.toString(), - this.protocol == null ? "" : this.protocol.toString(), - this.version == null ? "" : this.version, - this.resource == null ? "" : this.resource, - this.snapshotId == null ? "" : this.snapshotId, - this.cacheControl == null ? "" : this.cacheControl, - this.contentDisposition == null ? "" : this.contentDisposition, - this.contentEncoding == null ? "" : this.contentEncoding, - this.contentLanguage == null ? "" : this.contentLanguage, - this.contentType == null ? "" : this.contentType + this.permissions == null ? "" : this.permissions, + this.startTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.startTime), + this.expiryTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.expiryTime), + this.canonicalName == null ? "" : this.canonicalName, + key.signedOid() == null ? "" : key.signedOid(), + key.signedTid() == null ? "" : key.signedTid(), + key.signedStart() == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(key.signedStart()), + key.signedExpiry() == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(key.signedExpiry()), + key.signedService() == null ? "" : key.signedService(), + key.signedVersion() == null ? "" : key.signedVersion(), + this.ipRange == null ? new IPRange().toString() : this.ipRange.toString(), + this.protocol == null ? "" : this.protocol.toString(), + this.version == null ? "" : this.version, + this.resource == null ? "" : this.resource, + this.snapshotId == null ? "" : this.snapshotId, + this.cacheControl == null ? "" : this.cacheControl, + this.contentDisposition == null ? "" : this.contentDisposition, + this.contentEncoding == null ? "" : this.contentEncoding, + this.contentLanguage == null ? "" : this.contentLanguage, + this.contentType == null ? "" : this.contentType ); } } diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncClient.java index c6c48d7e5770d..b93ee7bd579e7 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncClient.java @@ -8,8 +8,11 @@ import com.azure.core.http.rest.Response; import com.azure.core.http.rest.SimpleResponse; import com.azure.core.http.rest.VoidResponse; +import com.azure.core.util.Context; import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; +import com.azure.storage.blob.implementation.AzureBlobStorageImpl; import com.azure.storage.blob.models.ContainerItem; +import com.azure.storage.blob.models.KeyInfo; import com.azure.storage.blob.models.ListContainersOptions; import com.azure.storage.blob.models.Metadata; import com.azure.storage.blob.models.PublicAccessType; @@ -26,11 +29,12 @@ import java.net.URL; import java.time.OffsetDateTime; +import static com.azure.storage.blob.Utility.postProcessResponse; + /** - * Client to a storage account. It may only be instantiated through a {@link StorageClientBuilder}. - * This class does not hold any state about a particular storage account but is - * instead a convenient way of sending off appropriate requests to the resource on the service. - * It may also be used to construct URLs to blobs and containers. + * Client to a storage account. It may only be instantiated through a {@link StorageClientBuilder}. This class does not + * hold any state about a particular storage account but is instead a convenient way of sending off appropriate requests + * to the resource on the service. It may also be used to construct URLs to blobs and containers. * *

* This client contains operations on a blob. Operations on a container are available on {@link ContainerAsyncClient} @@ -41,36 +45,35 @@ * information on containers. * *

- * 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()}. + * 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()}. */ public final class StorageAsyncClient { - StorageAsyncRawClient storageAsyncRawClient; + private final AzureBlobStorageImpl azureBlobStorage; /** * Package-private constructor for use by {@link StorageClientBuilder}. + * * @param azureBlobStorageBuilder the API client builder for blob storage API */ StorageAsyncClient(AzureBlobStorageBuilder azureBlobStorageBuilder) { - this.storageAsyncRawClient = new StorageAsyncRawClient(azureBlobStorageBuilder.build()); + this.azureBlobStorage = azureBlobStorageBuilder.build(); } /** - * Initializes a {@link ContainerAsyncClient} object pointing to the specified container. This method does not create a - * container. It simply constructs the URL to the container and offers access to methods relevant to containers. + * Initializes a {@link ContainerAsyncClient} object pointing to the specified container. This method does not + * create a container. It simply constructs the URL to the container and offers access to methods relevant to + * containers. * - * @param containerName - * The name of the container to point to. - * @return - * A {@link ContainerAsyncClient} object pointing to the specified container + * @param containerName The name of the container to point to. + * @return A {@link ContainerAsyncClient} object pointing to the specified container */ public ContainerAsyncClient getContainerAsyncClient(String containerName) { return new ContainerAsyncClient(new AzureBlobStorageBuilder() .url(Utility.appendToURLPath(getAccountUrl(), containerName).toString()) - .pipeline(storageAsyncRawClient.azureBlobStorage.httpPipeline())); + .pipeline(azureBlobStorage.httpPipeline())); } /** @@ -91,11 +94,9 @@ public Mono> createContainer(String containerName * Azure Docs. * * @param containerName Name of the container to create - * @param metadata - * {@link Metadata} - * @param accessType - * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header - * in the Azure Docs for more information. Pass null for no public access. + * @param metadata {@link Metadata} + * @param accessType Specifies how the data in this container is available to the public. See the + * x-ms-blob-public-access header in the Azure Docs for more information. Pass null for no public access. * @return A response containing a {@link ContainerAsyncClient} used to interact with the container created. */ public Mono> createContainer(String containerName, Metadata metadata, PublicAccessType accessType) { @@ -107,50 +108,76 @@ public Mono> createContainer(String containerName /** * Gets the URL of the storage account represented by this client. + * * @return the URL. * @throws RuntimeException If the account URL is malformed. */ public URL getAccountUrl() { try { - return new URL(storageAsyncRawClient.azureBlobStorage.url()); + return new URL(azureBlobStorage.url()); } catch (MalformedURLException e) { - throw new RuntimeException(String.format("Invalid URL on %s: %s" + getClass().getSimpleName(), storageAsyncRawClient.azureBlobStorage.url()), e); + throw new RuntimeException(String.format("Invalid URL on %s: %s" + getClass().getSimpleName(), azureBlobStorage.url()), e); } } /** - * Returns a reactive Publisher emitting all the containers in this account lazily as needed. For more information, see - * the Azure Docs. + * Returns a reactive Publisher emitting all the containers in this account lazily as needed. For more information, + * see the Azure Docs. * - * @return - * A reactive response emitting the list of containers. + * @return A reactive response emitting the list of containers. */ public Flux listContainers() { return this.listContainers(new ListContainersOptions()); } /** - * Returns a reactive Publisher emitting all the containers in this account lazily as needed. For more information, see + * Returns a reactive Publisher emitting all the containers in this account lazily as needed. For more information, + * see the Azure Docs. + * + * @param options A {@link ListContainersOptions} which specifies what data should be returned by the service. + * @return A reactive response emitting the list of containers. + */ + public Flux listContainers(ListContainersOptions options) { + return listContainersSegment(null, options) + .flatMapMany(response -> listContainersHelper(response.value().marker(), options, response)); + } + + /* + * Returns a Mono segment of containers starting from the specified Marker. + * Use an empty marker to start enumeration from the beginning. Container names are returned in lexicographic order. + * After getting a segment, process it, and then call ListContainers again (passing the the previously-returned + * Marker) to get the next segment. For more information, see * the Azure Docs. * + * @param marker + * Identifies the portion of the list to be returned with the next list operation. + * This value is returned in the response of a previous list operation as the + * ListContainersSegmentResponse.body().nextMarker(). Set to null to list the first segment. * @param options * A {@link ListContainersOptions} which specifies what data should be returned by the service. * - * @return - * A reactive response emitting the list of containers. + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_list "Sample code for ServiceURL.listContainersSegment")] \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_list_helper "Helper code for ServiceURL.listContainersSegment")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) */ - public Flux listContainers(ListContainersOptions options) { - return storageAsyncRawClient - .listContainersSegment(null, options) - .flatMapMany(response -> listContainersHelper(response.value().marker(), options, response)); + private Mono listContainersSegment(String marker, ListContainersOptions options) { + options = options == null ? new ListContainersOptions() : options; + + return postProcessResponse( + this.azureBlobStorage.services().listContainersSegmentWithRestResponseAsync( + options.prefix(), marker, options.maxResults(), options.details().toIncludeType(), null, + null, Context.NONE)); } private Flux listContainersHelper(String marker, ListContainersOptions options, - ServicesListContainersSegmentResponse response) { + ServicesListContainersSegmentResponse response) { Flux result = Flux.fromIterable(response.value().containerItems()); if (response.value().nextMarker() != null) { // Recursively add the continuation items to the observable. - result = result.concatWith(storageAsyncRawClient.listContainersSegment(marker, options) + result = result.concatWith(listContainersSegment(marker, options) .flatMapMany((r) -> listContainersHelper(response.value().nextMarker(), options, r))); } @@ -162,12 +189,11 @@ private Flux listContainersHelper(String marker, ListContainersOp * Gets the properties of a storage account’s Blob service. For more information, see the * Azure Docs. * - * @return - * A reactive response containing the storage account properties. + * @return A reactive response containing the storage account properties. */ public Mono> getProperties() { - return storageAsyncRawClient - .getProperties() + return postProcessResponse( + this.azureBlobStorage.services().getPropertiesWithRestResponseAsync(null, null, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, rb.value())); } @@ -177,48 +203,50 @@ public Mono> getProperties() { * Note that setting the default service version has no effect when using this client because this client explicitly * sets the version header on each request, overriding the default. * - * @param properties - * Configures the service. - * - * @return - * A reactive response containing the storage account properties. + * @param properties Configures the service. + * @return A reactive response containing the storage account properties. */ public Mono setProperties(StorageServiceProperties properties) { - return storageAsyncRawClient - .setProperties(properties) + return postProcessResponse( + this.azureBlobStorage.services().setPropertiesWithRestResponseAsync(properties, null, null, Context.NONE)) .map(VoidResponse::new); } /** - * Gets a user delegation key for use with this account's blob storage. - * Note: This method call is only valid when using {@link TokenCredential} in this object's {@link HttpPipeline}. - * - * @param start - * Start time for the key's validity. Null indicates immediate start. - * @param expiry - * Expiration of the key's validity. + * Gets a user delegation key for use with this account's blob storage. Note: This method call is only valid when + * using {@link TokenCredential} in this object's {@link HttpPipeline}. * - * @return - * A reactive response containing the user delegation key. + * @param start Start time for the key's validity. Null indicates immediate start. + * @param expiry Expiration of the key's validity. + * @return A reactive response containing the user delegation key. + * @throws IllegalArgumentException If {@code start} isn't null and is after {@code expiry}. */ public Mono> getUserDelegationKey(OffsetDateTime start, OffsetDateTime expiry) { - return storageAsyncRawClient - .getUserDelegationKey(start, expiry) - .map(rb -> new SimpleResponse<>(rb, rb.value())); + Utility.assertNotNull("expiry", expiry); + if (start != null && !start.isBefore(expiry)) { + throw new IllegalArgumentException("`start` must be null or a datetime before `expiry`."); + } + + return postProcessResponse( + this.azureBlobStorage.services().getUserDelegationKeyWithRestResponseAsync( + new KeyInfo() + .start(start == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(start)) + .expiry(Utility.ISO_8601_UTC_DATE_FORMATTER.format(expiry)), + null, null, Context.NONE) + ).map(rb -> new SimpleResponse<>(rb, rb.value())); } /** - * Retrieves statistics related to replication for the Blob service. It is only available on the secondary - * location endpoint when read-access geo-redundant replication is enabled for the storage account. For more - * information, see the + * Retrieves statistics related to replication for the Blob service. It is only available on the secondary location + * endpoint when read-access geo-redundant replication is enabled for the storage account. For more information, see + * the * Azure Docs. * - * @return - * A reactive response containing the storage account statistics. + * @return A reactive response containing the storage account statistics. */ public Mono> getStatistics() { - return storageAsyncRawClient - .getStatistics() + return postProcessResponse( + this.azureBlobStorage.services().getStatisticsWithRestResponseAsync(null, null, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, rb.value())); } @@ -226,32 +254,24 @@ public Mono> getStatistics() { * Returns the sku name and account kind for the account. For more information, please see the * Azure Docs. * - * @return - * A reactive response containing the storage account info. + * @return A reactive response containing the storage account info. */ public Mono> getAccountInfo() { - return storageAsyncRawClient - .getAccountInfo() + return postProcessResponse(this.azureBlobStorage.services().getAccountInfoWithRestResponseAsync(Context.NONE)) .map(rb -> new SimpleResponse<>(rb, new StorageAccountInfo(rb.deserializedHeaders()))); } /** * Generates an account SAS token with the specified parameters * - * @param accountSASService - * The {@code AccountSASService} services for the account SAS - * @param accountSASResourceType - * An optional {@code AccountSASResourceType} resources for the account SAS - * @param accountSASPermission - * The {@code AccountSASPermission} permission for the account SAS - * @param expiryTime - * The {@code OffsetDateTime} expiry time for the account SAS - * - * @return - * A string that represents the SAS token + * @param accountSASService The {@code AccountSASService} services for the account SAS + * @param accountSASResourceType An optional {@code AccountSASResourceType} resources for the account SAS + * @param accountSASPermission The {@code AccountSASPermission} permission for the account SAS + * @param expiryTime The {@code OffsetDateTime} expiry time for the account SAS + * @return A string that represents the SAS token */ public String generateAccountSAS(AccountSASService accountSASService, AccountSASResourceType accountSASResourceType, - AccountSASPermission accountSASPermission, OffsetDateTime expiryTime) { + AccountSASPermission accountSASPermission, OffsetDateTime expiryTime) { return this.generateAccountSAS(accountSASService, accountSASResourceType, accountSASPermission, expiryTime, null /* startTime */, null /* version */, null /* ipRange */, null /* sasProtocol */); } @@ -259,29 +279,19 @@ public String generateAccountSAS(AccountSASService accountSASService, AccountSAS /** * Generates an account SAS token with the specified parameters * - * @param accountSASService - * The {@code AccountSASService} services for the account SAS - * @param accountSASResourceType - * An optional {@code AccountSASResourceType} resources for the account SAS - * @param accountSASPermission - * The {@code AccountSASPermission} permission for the account SAS - * @param expiryTime - * The {@code OffsetDateTime} expiry time for the account SAS - * @param startTime - * The {@code OffsetDateTime} start time for the account SAS - * @param version - * The {@code String} version for the account SAS - * @param ipRange - * An optional {@code IPRange} ip address range for the SAS - * @param sasProtocol - * An optional {@code SASProtocol} protocol for the SAS - * - * @return - * A string that represents the SAS token + * @param accountSASService The {@code AccountSASService} services for the account SAS + * @param accountSASResourceType An optional {@code AccountSASResourceType} resources for the account SAS + * @param accountSASPermission The {@code AccountSASPermission} permission for the account SAS + * @param expiryTime The {@code OffsetDateTime} expiry time for the account SAS + * @param startTime The {@code OffsetDateTime} start time for the account SAS + * @param version The {@code String} version for the account SAS + * @param ipRange An optional {@code IPRange} ip address range for the SAS + * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS + * @return A string that represents the SAS token */ public String generateAccountSAS(AccountSASService accountSASService, AccountSASResourceType accountSASResourceType, - AccountSASPermission accountSASPermission, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, IPRange ipRange, - SASProtocol sasProtocol) { + AccountSASPermission accountSASPermission, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, IPRange ipRange, + SASProtocol sasProtocol) { AccountSASSignatureValues accountSASSignatureValues = new AccountSASSignatureValues(); accountSASSignatureValues.services(accountSASService == null ? null : accountSASService.toString()); @@ -297,7 +307,7 @@ public String generateAccountSAS(AccountSASService accountSASService, AccountSAS accountSASSignatureValues.ipRange(ipRange); accountSASSignatureValues.protocol(sasProtocol); - SharedKeyCredential sharedKeyCredential = Utility.getSharedKeyCredential(this.storageAsyncRawClient.azureBlobStorage.httpPipeline()); + SharedKeyCredential sharedKeyCredential = Utility.getSharedKeyCredential(this.azureBlobStorage.httpPipeline()); SASQueryParameters sasQueryParameters = accountSASSignatureValues.generateSASQueryParameters(sharedKeyCredential); diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncRawClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncRawClient.java deleted file mode 100644 index a2b6be965ed30..0000000000000 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncRawClient.java +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.storage.blob; - -import com.azure.core.credentials.TokenCredential; -import com.azure.core.http.HttpPipeline; -import com.azure.core.util.Context; -import com.azure.storage.blob.implementation.AzureBlobStorageImpl; -import com.azure.storage.blob.models.KeyInfo; -import com.azure.storage.blob.models.ListContainersOptions; -import com.azure.storage.blob.models.ServicesGetAccountInfoResponse; -import com.azure.storage.blob.models.ServicesGetPropertiesResponse; -import com.azure.storage.blob.models.ServicesGetStatisticsResponse; -import com.azure.storage.blob.models.ServicesGetUserDelegationKeyResponse; -import com.azure.storage.blob.models.ServicesListContainersSegmentResponse; -import com.azure.storage.blob.models.ServicesSetPropertiesResponse; -import com.azure.storage.blob.models.StorageServiceProperties; -import reactor.core.publisher.Mono; - -import java.time.OffsetDateTime; - -import static com.azure.storage.blob.Utility.postProcessResponse; - -/** - * Represents a URL to a storage service. This class does not hold any state about a particular storage account but is - * instead a convenient way of sending off appropriate requests to the resource on the service. - * It may also be used to construct URLs to blobs and containers. - * Please see here for more - * information on containers. - */ -final class StorageAsyncRawClient { - - final AzureBlobStorageImpl azureBlobStorage; - - /** - * Creates a {@code ServiceURL} object pointing to the account specified by the URL and using the provided pipeline - * to make HTTP requests. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_url "Sample code for ServiceURL constructor")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - StorageAsyncRawClient(AzureBlobStorageImpl azureBlobStorage) { - this.azureBlobStorage = azureBlobStorage; - } - - /** - * Returns a Mono segment of containers starting from the specified Marker. - * Use an empty marker to start enumeration from the beginning. Container names are returned in lexicographic order. - * After getting a segment, process it, and then call ListContainers again (passing the the previously-returned - * Marker) to get the next segment. For more information, see - * the Azure Docs. - * - * @param marker - * Identifies the portion of the list to be returned with the next list operation. - * This value is returned in the response of a previous list operation as the - * ListContainersSegmentResponse.body().nextMarker(). Set to null to list the first segment. - * @param options - * A {@link ListContainersOptions} which specifies what data should be returned by the service. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_list "Sample code for ServiceURL.listContainersSegment")] \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_list_helper "Helper code for ServiceURL.listContainersSegment")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono listContainersSegment(String marker, - ListContainersOptions options) { - options = options == null ? new ListContainersOptions() : options; - - return postProcessResponse( - this.azureBlobStorage.services().listContainersSegmentWithRestResponseAsync( - options.prefix(), marker, options.maxResults(), options.details().toIncludeType(), null, - null, Context.NONE)); - } - - /** - * Gets the properties of a storage account’s Blob service. For more information, see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_getsetprops "Sample code for ServiceURL.getProperties")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono getProperties() { - return postProcessResponse( - this.azureBlobStorage.services().getPropertiesWithRestResponseAsync(null, null, Context.NONE)); - } - - /** - * Sets properties for a storage account's Blob service endpoint. For more information, see the - * Azure Docs. - * Note that setting the default service version has no effect when using this client because this client explicitly - * sets the version header on each request, overriding the default. - * - * @param properties - * Configures the service. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_getsetprops "Sample code for ServiceURL.setProperties")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono setProperties(StorageServiceProperties properties) { - return postProcessResponse( - this.azureBlobStorage.services().setPropertiesWithRestResponseAsync(properties, null, null, Context.NONE)); - } - - /** - * Gets a user delegation key for use with this account's blob storage. - * Note: This method call is only valid when using {@link TokenCredential} in this object's {@link HttpPipeline}. - * - * @param start - * Start time for the key's validity. Null indicates immediate start. - * @param expiry - * Expiration of the key's validity. - * - * @return Emits the successful response. - * @throws IllegalArgumentException If {@code start} isn't null and is after {@code expiry}. - */ - public Mono getUserDelegationKey(OffsetDateTime start, OffsetDateTime expiry) { - Utility.assertNotNull("expiry", expiry); - if (start != null && !start.isBefore(expiry)) { - throw new IllegalArgumentException("`start` must be null or a datetime before `expiry`."); - } - - return postProcessResponse( - this.azureBlobStorage.services().getUserDelegationKeyWithRestResponseAsync( - new KeyInfo() - .start(start == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(start)) - .expiry(Utility.ISO_8601_UTC_DATE_FORMATTER.format(expiry)), - null, null, Context.NONE) - ); - } - - /** - * Retrieves statistics related to replication for the Blob service. It is only available on the secondary - * location endpoint when read-access geo-redundant replication is enabled for the storage account. For more - * information, see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_stats "Sample code for ServiceURL.getStats")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono getStatistics() { - return postProcessResponse( - this.azureBlobStorage.services().getStatisticsWithRestResponseAsync(null, null, Context.NONE)); - } - - /** - * Returns the sku name and account kind for the account. For more information, please see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=account_info "Sample code for ServiceURL.getAccountInfo")] \n - * For more samples, please see the [Samples file] (https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public Mono getAccountInfo() { - return postProcessResponse( - this.azureBlobStorage.services().getAccountInfoWithRestResponseAsync(Context.NONE)); - } -} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClient.java index c895cdda58bbc..1511726d653bb 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClient.java @@ -24,25 +24,24 @@ import java.time.OffsetDateTime; /** - * Client to a storage account. It may only be instantiated through a {@link StorageClientBuilder}. - * This class does not hold any state about a particular storage account but is - * instead a convenient way of sending off appropriate requests to the resource on the service. - * It may also be used to construct URLs to blobs and containers. + * Client to a storage account. It may only be instantiated through a {@link StorageClientBuilder}. This class does not + * hold any state about a particular storage account but is instead a convenient way of sending off appropriate requests + * to the resource on the service. It may also be used to construct URLs to blobs and containers. * *

- * This client contains operations on a blob. Operations on a container are available on {@link ContainerClient} - * through {@link #getContainerClient(String)}, and operations on a blob are available on {@link BlobClient}. + * This client contains operations on a blob. Operations on a container are available on {@link ContainerClient} through + * {@link #getContainerClient(String)}, and operations on a blob are available on {@link BlobClient}. * *

* Please see here for more * information on containers. */ public final class StorageClient { - - private StorageAsyncClient storageAsyncClient; + private final StorageAsyncClient storageAsyncClient; /** * Package-private constructor for use by {@link StorageClientBuilder}. + * * @param storageAsyncClient the async storage account client */ StorageClient(StorageAsyncClient storageAsyncClient) { @@ -53,10 +52,8 @@ public final class StorageClient { * Initializes a {@link ContainerClient} object pointing to the specified container. This method does not create a * container. It simply constructs the URL to the container and offers access to methods relevant to containers. * - * @param containerName - * The name of the container to point to. - * @return - * A {@link ContainerClient} object pointing to the specified container + * @param containerName The name of the container to point to. + * @return A {@link ContainerClient} object pointing to the specified container */ public ContainerClient getContainerClient(String containerName) { return new ContainerClient(storageAsyncClient.getContainerAsyncClient(containerName)); @@ -80,11 +77,9 @@ public Response createContainer(String containerName) { * Azure Docs. * * @param containerName Name of the container to create - * @param metadata - * {@link Metadata} - * @param accessType - * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header - * in the Azure Docs for more information. Pass null for no public access. + * @param metadata {@link Metadata} + * @param accessType Specifies how the data in this container is available to the public. See the + * x-ms-blob-public-access header in the Azure Docs for more information. Pass null for no public access. * @return A response containing a {@link ContainerClient} used to interact with the container created. */ public Response createContainer(String containerName, Metadata metadata, PublicAccessType accessType) { @@ -95,6 +90,7 @@ public Response createContainer(String containerName, Metadata /** * Gets the URL of the storage account represented by this client. + * * @return the URL. */ public URL getAccountUrl() { @@ -102,29 +98,24 @@ public URL getAccountUrl() { } /** - * Returns a lazy loaded list of containers in this account. The returned {@link Iterable} can be iterated - * through while new items are automatically retrieved as needed. For more information, see - * the Azure Docs. + * Returns a lazy loaded list of containers in this account. The returned {@link Iterable} can be iterated through + * while new items are automatically retrieved as needed. For more information, see the Azure Docs. * - * @return - * The list of containers. + * @return The list of containers. */ public Iterable listContainers() { return this.listContainers(new ListContainersOptions(), null); } /** - * Returns a lazy loaded list of containers in this account. The returned {@link Iterable} can be iterated - * through while new items are automatically retrieved as needed. For more information, see - * the Azure Docs. - * - * @param options - * A {@link ListContainersOptions} which specifies what data should be returned by the service. - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * Returns a lazy loaded list of containers in this account. The returned {@link Iterable} can be iterated through + * while new items are automatically retrieved as needed. For more information, see the Azure Docs. * - * @return - * The list of containers. + * @param options A {@link ListContainersOptions} which specifies what data should be returned by the service. + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return The list of containers. */ public Iterable listContainers(ListContainersOptions options, Duration timeout) { Flux response = storageAsyncClient.listContainers(options); @@ -136,8 +127,7 @@ public Iterable listContainers(ListContainersOptions options, Dur * Gets the properties of a storage account’s Blob service. For more information, see the * Azure Docs. * - * @return - * The storage account properties. + * @return The storage account properties. */ public Response getProperties() { return this.getProperties(null); @@ -147,11 +137,8 @@ public Response getProperties() { * Gets the properties of a storage account’s Blob service. For more information, see the * Azure Docs. * - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * - * @return - * The storage account properties. + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return The storage account properties. */ public Response getProperties(Duration timeout) { @@ -166,11 +153,8 @@ public Response getProperties(Duration timeout) { * Note that setting the default service version has no effect when using this client because this client explicitly * sets the version header on each request, overriding the default. * - * @param properties - * Configures the service. - * - * @return - * The storage account properties. + * @param properties Configures the service. + * @return The storage account properties. */ public VoidResponse setProperties(StorageServiceProperties properties) { return this.setProperties(properties, null); @@ -182,13 +166,9 @@ public VoidResponse setProperties(StorageServiceProperties properties) { * Note that setting the default service version has no effect when using this client because this client explicitly * sets the version header on each request, overriding the default. * - * @param properties - * Configures the service. - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * - * @return - * The storage account properties. + * @param properties Configures the service. + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return The storage account properties. */ public VoidResponse setProperties(StorageServiceProperties properties, Duration timeout) { Mono response = storageAsyncClient.setProperties(properties); @@ -197,66 +177,53 @@ public VoidResponse setProperties(StorageServiceProperties properties, Duration } /** - * Gets a user delegation key for use with this account's blob storage. - * Note: This method call is only valid when using {@link TokenCredential} in this object's {@link HttpPipeline}. + * Gets a user delegation key for use with this account's blob storage. Note: This method call is only valid when + * using {@link TokenCredential} in this object's {@link HttpPipeline}. * - * @param start - * Start time for the key's validity. Null indicates immediate start. - * @param expiry - * Expiration of the key's validity. - * - * @return - * The user delegation key. + * @param start Start time for the key's validity. Null indicates immediate start. + * @param expiry Expiration of the key's validity. + * @return The user delegation key. */ public Response getUserDelegationKey(OffsetDateTime start, OffsetDateTime expiry) { return this.getUserDelegationKey(start, expiry, null); } /** - * Gets a user delegation key for use with this account's blob storage. - * Note: This method call is only valid when using {@link TokenCredential} in this object's {@link HttpPipeline}. - * - * @param start - * Start time for the key's validity. Null indicates immediate start. - * @param expiry - * Expiration of the key's validity. - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * Gets a user delegation key for use with this account's blob storage. Note: This method call is only valid when + * using {@link TokenCredential} in this object's {@link HttpPipeline}. * - * @return - * The user delegation key. + * @param start Start time for the key's validity. Null indicates immediate start. + * @param expiry Expiration of the key's validity. + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return The user delegation key. */ public Response getUserDelegationKey(OffsetDateTime start, OffsetDateTime expiry, - Duration timeout) { + Duration timeout) { Mono> response = storageAsyncClient.getUserDelegationKey(start, expiry); return Utility.blockWithOptionalTimeout(response, timeout); } /** - * Retrieves statistics related to replication for the Blob service. It is only available on the secondary - * location endpoint when read-access geo-redundant replication is enabled for the storage account. For more - * information, see the + * Retrieves statistics related to replication for the Blob service. It is only available on the secondary location + * endpoint when read-access geo-redundant replication is enabled for the storage account. For more information, see + * the * Azure Docs. * - * @return - * The storage account statistics. + * @return The storage account statistics. */ public Response getStatistics() { return this.getStatistics(null); } /** - * Retrieves statistics related to replication for the Blob service. It is only available on the secondary - * location endpoint when read-access geo-redundant replication is enabled for the storage account. For more - * information, see the + * Retrieves statistics related to replication for the Blob service. It is only available on the secondary location + * endpoint when read-access geo-redundant replication is enabled for the storage account. For more information, see + * the * Azure Docs. * - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * - * @return - * The storage account statistics. + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return The storage account statistics. */ public Response getStatistics(Duration timeout) { Mono> response = storageAsyncClient.getStatistics(); @@ -268,8 +235,7 @@ public Response getStatistics(Duration timeout) { * Returns the sku name and account kind for the account. For more information, please see the * Azure Docs. * - * @return - * The storage account info. + * @return The storage account info. */ public Response getAccountInfo() { return this.getAccountInfo(null); @@ -279,11 +245,8 @@ public Response getAccountInfo() { * Returns the sku name and account kind for the account. For more information, please see the * Azure Docs. * - * @param timeout - * An optional timeout value beyond which a {@link RuntimeException} will be raised. - * - * @return - * The storage account info. + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return The storage account info. */ public Response getAccountInfo(Duration timeout) { Mono> response = storageAsyncClient.getAccountInfo(); @@ -294,49 +257,33 @@ public Response getAccountInfo(Duration timeout) { /** * Generates an account SAS token with the specified parameters * - * @param accountSASService - * The {@code AccountSASService} services for the account SAS - * @param accountSASResourceType - * An optional {@code AccountSASResourceType} resources for the account SAS - * @param accountSASPermission - * The {@code AccountSASPermission} permission for the account SAS - * @param expiryTime - * The {@code OffsetDateTime} expiry time for the account SAS - * - * @return - * A string that represents the SAS token + * @param accountSASService The {@code AccountSASService} services for the account SAS + * @param accountSASResourceType An optional {@code AccountSASResourceType} resources for the account SAS + * @param accountSASPermission The {@code AccountSASPermission} permission for the account SAS + * @param expiryTime The {@code OffsetDateTime} expiry time for the account SAS + * @return A string that represents the SAS token */ public String generateAccountSAS(AccountSASService accountSASService, AccountSASResourceType accountSASResourceType, - AccountSASPermission accountSASPermission, OffsetDateTime expiryTime) { + AccountSASPermission accountSASPermission, OffsetDateTime expiryTime) { return this.storageAsyncClient.generateAccountSAS(accountSASService, accountSASResourceType, accountSASPermission, expiryTime); } /** * Generates an account SAS token with the specified parameters * - * @param accountSASService - * The {@code AccountSASService} services for the account SAS - * @param accountSASResourceType - * An optional {@code AccountSASResourceType} resources for the account SAS - * @param accountSASPermission - * The {@code AccountSASPermission} permission for the account SAS - * @param expiryTime - * The {@code OffsetDateTime} expiry time for the account SAS - * @param startTime - * The {@code OffsetDateTime} start time for the account SAS - * @param version - * The {@code String} version for the account SAS - * @param ipRange - * An optional {@code IPRange} ip address range for the SAS - * @param sasProtocol - * An optional {@code SASProtocol} protocol for the SAS - * - * @return - * A string that represents the SAS token + * @param accountSASService The {@code AccountSASService} services for the account SAS + * @param accountSASResourceType An optional {@code AccountSASResourceType} resources for the account SAS + * @param accountSASPermission The {@code AccountSASPermission} permission for the account SAS + * @param expiryTime The {@code OffsetDateTime} expiry time for the account SAS + * @param startTime The {@code OffsetDateTime} start time for the account SAS + * @param version The {@code String} version for the account SAS + * @param ipRange An optional {@code IPRange} ip address range for the SAS + * @param sasProtocol An optional {@code SASProtocol} protocol for the SAS + * @return A string that represents the SAS token */ public String generateAccountSAS(AccountSASService accountSASService, AccountSASResourceType accountSASResourceType, - AccountSASPermission accountSASPermission, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, IPRange ipRange, - SASProtocol sasProtocol) { + AccountSASPermission accountSASPermission, OffsetDateTime expiryTime, OffsetDateTime startTime, String version, IPRange ipRange, + SASProtocol sasProtocol) { return this.storageAsyncClient.generateAccountSAS(accountSASService, accountSASResourceType, accountSASPermission, expiryTime, startTime, version, ipRange, sasProtocol); } } diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageRawClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageRawClient.java deleted file mode 100644 index cebfdc451ae67..0000000000000 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageRawClient.java +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.storage.blob; - -import com.azure.core.http.HttpPipeline; -import com.azure.storage.blob.implementation.AzureBlobStorageImpl; -import com.azure.storage.blob.models.ListContainersOptions; -import com.azure.storage.blob.models.ServicesGetAccountInfoResponse; -import com.azure.storage.blob.models.ServicesGetPropertiesResponse; -import com.azure.storage.blob.models.ServicesGetStatisticsResponse; -import com.azure.storage.blob.models.ServicesGetUserDelegationKeyResponse; -import com.azure.storage.blob.models.ServicesListContainersSegmentResponse; -import com.azure.storage.blob.models.ServicesSetPropertiesResponse; -import com.azure.storage.blob.models.StorageServiceProperties; -import com.azure.storage.common.credentials.SASTokenCredential; -import reactor.core.publisher.Mono; - -import java.time.Duration; -import java.time.OffsetDateTime; - -/** - * Represents a URL to a storage service. This class does not hold any state about a particular storage account but is - * instead a convenient way of sending off appropriate requests to the resource on the service. - * It may also be used to construct URLs to blobs and containers. - * Please see here for more - * information on containers. - */ -final class StorageRawClient { - - StorageAsyncRawClient storageAsyncRawClient; - - /** - * Creates a {@code ServiceURL} object pointing to the account specified by the URL and using the provided pipeline - * to make HTTP requests. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_url "Sample code for ServiceURL constructor")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - StorageRawClient(AzureBlobStorageImpl azureBlobStorage) { - this.storageAsyncRawClient = new StorageAsyncRawClient(azureBlobStorage); - } - - /** - * Returns a Mono segment of containers starting from the specified Marker. - * Use an empty marker to start enumeration from the beginning. Container names are returned in lexicographic order. - * After getting a segment, process it, and then call ListContainers again (passing the the previously-returned - * Marker) to get the next segment. For more information, see - * the Azure Docs. - * - * @param marker - * Identifies the portion of the list to be returned with the next list operation. - * This value is returned in the response of a previous list operation as the - * ListContainersSegmentResponse.body().nextMarker(). Set to null to list the first segment. - * @param options - * A {@link ListContainersOptions} which specifies what data should be returned by the service. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_list "Sample code for ServiceURL.listContainersSegment")] \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_list_helper "Helper code for ServiceURL.listContainersSegment")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ServicesListContainersSegmentResponse listContainersSegment(String marker, - ListContainersOptions options) { - return this.listContainersSegment(marker, options, null); - } - - /** - * Returns a Mono segment of containers starting from the specified Marker. - * Use an empty marker to start enumeration from the beginning. Container names are returned in lexicographic order. - * After getting a segment, process it, and then call ListContainers again (passing the the previously-returned - * Marker) to get the next segment. For more information, see - * the Azure Docs. - * - * @param marker - * Identifies the portion of the list to be returned with the next list operation. - * This value is returned in the response of a previous list operation as the - * ListContainersSegmentResponse.body().nextMarker(). Set to null to list the first segment. - * @param options - * A {@link ListContainersOptions} which specifies what data should be returned by the service. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_list "Sample code for ServiceURL.listContainersSegment")] \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_list_helper "Helper code for ServiceURL.listContainersSegment")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ServicesListContainersSegmentResponse listContainersSegment(String marker, - ListContainersOptions options, Duration timeout) { - Mono response = storageAsyncRawClient.listContainersSegment(marker, options); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Gets the properties of a storage account’s Blob service. For more information, see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_getsetprops "Sample code for ServiceURL.getProperties")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ServicesGetPropertiesResponse getProperties() { - return this.getProperties(null); - } - - /** - * Gets the properties of a storage account’s Blob service. For more information, see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_getsetprops "Sample code for ServiceURL.getProperties")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ServicesGetPropertiesResponse getProperties(Duration timeout) { - Mono response = storageAsyncRawClient.getProperties(); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Sets properties for a storage account's Blob service endpoint. For more information, see the - * Azure Docs. - * Note that setting the default service version has no effect when using this client because this client explicitly - * sets the version header on each request, overriding the default. - * - * @param properties - * Configures the service. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_getsetprops "Sample code for ServiceURL.setProperties")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ServicesSetPropertiesResponse setProperties(StorageServiceProperties properties) { - return this.setProperties(properties, null); - } - - /** - * Sets properties for a storage account's Blob service endpoint. For more information, see the - * Azure Docs. - * Note that setting the default service version has no effect when using this client because this client explicitly - * sets the version header on each request, overriding the default. - * - * @param properties - * Configures the service. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_getsetprops "Sample code for ServiceURL.setProperties")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ServicesSetPropertiesResponse setProperties(StorageServiceProperties properties, Duration timeout) { - Mono response = storageAsyncRawClient.setProperties(properties); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Gets a user delegation key for use with this account's blob storage. - * Note: This method call is only valid when using {@link SASTokenCredential} in this object's {@link HttpPipeline}. - * - * @param start - * Start time for the key's validity. Null indicates immediate start. - * @param expiry - * Expiration of the key's validity. - * - * @return Emits the successful response. - */ - public ServicesGetUserDelegationKeyResponse getUserDelegationKey(OffsetDateTime start, OffsetDateTime expiry) { - return this.getUserDelegationKey(start, expiry, null); - } - - /** - * Gets a user delegation key for use with this account's blob storage. - * Note: This method call is only valid when using {@link SASTokenCredential} in this object's {@link HttpPipeline}. - * - * @param start - * Start time for the key's validity. Null indicates immediate start. - * @param expiry - * Expiration of the key's validity. - * - * @return Emits the successful response. - */ - public ServicesGetUserDelegationKeyResponse getUserDelegationKey(OffsetDateTime start, OffsetDateTime expiry, - Duration timeout) { - Mono response = storageAsyncRawClient.getUserDelegationKey(start, expiry); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Retrieves statistics related to replication for the Blob service. It is only available on the secondary - * location endpoint when read-access geo-redundant replication is enabled for the storage account. For more - * information, see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_stats "Sample code for ServiceURL.getStats")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ServicesGetStatisticsResponse getStatistics() { - return this.getStatistics(null); - } - - /** - * Retrieves statistics related to replication for the Blob service. It is only available on the secondary - * location endpoint when read-access geo-redundant replication is enabled for the storage account. For more - * information, see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_stats "Sample code for ServiceURL.getStats")] \n - * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ServicesGetStatisticsResponse getStatistics(Duration timeout) { - Mono response = storageAsyncRawClient.getStatistics(); - return Utility.blockWithOptionalTimeout(response, timeout); - } - - /** - * Returns the sku name and account kind for the account. For more information, please see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=account_info "Sample code for ServiceURL.getAccountInfo")] \n - * For more samples, please see the [Samples file] (https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ServicesGetAccountInfoResponse getAccountInfo() { - return this.getAccountInfo(null); - } - - /** - * Returns the sku name and account kind for the account. For more information, please see the - * Azure Docs. - * - * @return Emits the successful response. - * - * @apiNote ## Sample Code \n - * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=account_info "Sample code for ServiceURL.getAccountInfo")] \n - * For more samples, please see the [Samples file] (https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) - */ - public ServicesGetAccountInfoResponse getAccountInfo(Duration timeout) { - Mono response = storageAsyncRawClient.getAccountInfo(); - return Utility.blockWithOptionalTimeout(response, timeout); - } -} diff --git a/storage/client/blob/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java b/storage/client/blob/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java index 4dce1c831ce21..cff7bc91f7765 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java +++ b/storage/client/blob/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java @@ -43,6 +43,7 @@ public final class SASTokenCredential { /** * Creates a SAS token credential from the passed SAS token. + * * @param sasToken SAS token used to authenticate requests with the service. */ public SASTokenCredential(String sasToken) { @@ -58,6 +59,7 @@ public String sasToken() { /** * Creates a SAS token credential from the passed URL query string + * * @param query URL query used to build the SAS token * @return a SAS token credential if the query param contains all the necessary pieces */ diff --git a/storage/client/blob/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java b/storage/client/blob/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java index 743eae8f262e4..e8b54914cb762 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java +++ b/storage/client/blob/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java @@ -18,6 +18,7 @@ public final class SharedKeyCredentialPolicy implements HttpPipelinePolicy { /** * Creates a SharedKey pipeline policy that adds the SharedKey into the request's authorization header. + * * @param credential the SharedKey credential used to create the policy. */ public SharedKeyCredentialPolicy(SharedKeyCredential credential) { @@ -25,9 +26,7 @@ public SharedKeyCredentialPolicy(SharedKeyCredential credential) { } /** - * Gets the shared key credential linked to the policy. - * @return - * The {@link SharedKeyCredential} linked to the policy. + * @return the {@link SharedKeyCredential} linked to the policy. */ public SharedKeyCredential sharedKeyCredential() { return this.credential; diff --git a/storage/client/blob/src/test/java/com/azure/storage/blob/Sample.java b/storage/client/blob/src/test/java/com/azure/storage/blob/Sample.java index 1ac12cbe978da..f6d19d6b84167 100644 --- a/storage/client/blob/src/test/java/com/azure/storage/blob/Sample.java +++ b/storage/client/blob/src/test/java/com/azure/storage/blob/Sample.java @@ -8,6 +8,8 @@ import com.azure.storage.blob.models.BlobItem; import com.azure.storage.blob.models.ContainerItem; import com.azure.storage.common.credentials.SharedKeyCredential; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -16,7 +18,6 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.UUID; @@ -116,8 +117,7 @@ public void asyncSample() throws IOException { for (int i = 0; i < 5; i++) { BlockBlobAsyncClient blobClient = finalContainerClient.getBlockBlobAsyncClient("testblob-" + i); byte[] message = ("test data" + i).getBytes(StandardCharsets.UTF_8); - Flux testdata = Flux.just(ByteBuffer.wrap(message)); - + Flux testdata = Flux.just(ByteBufAllocator.DEFAULT.buffer(message.length).writeBytes(message)); finished = finished.and(blobClient.upload(testdata, message.length) .then(Mono.defer(() -> { From b00cdc6af6df7c8fba03725bec110ecbbdc3f6f9 Mon Sep 17 00:00:00 2001 From: Alan Zimmer <48699787+alzimmermsft@users.noreply.github.com> Date: Fri, 19 Jul 2019 10:51:25 -0700 Subject: [PATCH 3/8] Add deleteContainer to StorageClient and getBlobClient with Snapshot to ContainerClient (#4376) * Removed raw clients * Added deleteContainer to StorageClient * Added getAppendBlob with snapshot to ContainerClient --- .../com/azure/storage/blob/BlobAsyncClient.java | 12 ++++-------- .../azure/storage/blob/ContainerAsyncClient.java | 6 ++---- .../com/azure/storage/blob/ContainerClient.java | 16 ++++++++++++++++ .../azure/storage/blob/StorageAsyncClient.java | 11 +++++++++++ .../com/azure/storage/blob/StorageClient.java | 11 +++++++++++ 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java index 2601107aaa0b6..c8ada7d8722fb 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java @@ -194,8 +194,7 @@ public Mono> startCopyFromURL(URL sourceURL) { * @param destAccessConditions {@link BlobAccessConditions} against the destination. * @return A reactive response containing the copy ID for the long running operation. */ - public Mono> startCopyFromURL(URL sourceURL, Metadata metadata, - ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions) { + public Mono> startCopyFromURL(URL sourceURL, Metadata metadata, ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions) { metadata = metadata == null ? new Metadata() : metadata; sourceModifiedAccessConditions = sourceModifiedAccessConditions == null ? new ModifiedAccessConditions() : sourceModifiedAccessConditions; @@ -262,8 +261,7 @@ public Mono> copyFromURL(URL copySource) { * @param destAccessConditions {@link BlobAccessConditions} against the destination. * @return A reactive response containing the copy ID for the long running operation. */ - public Mono> copyFromURL(URL copySource, Metadata metadata, - ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions) { + public Mono> copyFromURL(URL copySource, Metadata metadata, ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions) { metadata = metadata == null ? new Metadata() : metadata; sourceModifiedAccessConditions = sourceModifiedAccessConditions == null ? new ModifiedAccessConditions() : sourceModifiedAccessConditions; @@ -302,8 +300,7 @@ public Mono>> download() { * @param options {@link ReliableDownloadOptions} * @return A reactive response containing the blob data. */ - public Mono>> download(BlobRange range, BlobAccessConditions accessConditions, - boolean rangeGetContentMD5, ReliableDownloadOptions options) { + public Mono>> download(BlobRange range, BlobAccessConditions accessConditions, boolean rangeGetContentMD5, ReliableDownloadOptions options) { return this.download(range, accessConditions, rangeGetContentMD5) .map(response -> new SimpleResponse<>( response.rawResponse(), @@ -457,8 +454,7 @@ public Mono delete() { * @param accessConditions {@link BlobAccessConditions} * @return A reactive response signalling completion. */ - public Mono delete(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, - BlobAccessConditions accessConditions) { + public Mono delete(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, BlobAccessConditions accessConditions) { accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; return postProcessResponse(this.azureBlobStorage.blobs().deleteWithRestResponseAsync( diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java index 6d9e64f16a924..936bab6932528 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java @@ -355,8 +355,7 @@ public Mono setMetadata(Metadata metadata) { * @throws UnsupportedOperationException If {@link ContainerAccessConditions#modifiedAccessConditions()} has * anything set other than {@link ModifiedAccessConditions#ifModifiedSince()}. */ - public Mono setMetadata(Metadata metadata, - ContainerAccessConditions accessConditions) { + public Mono setMetadata(Metadata metadata, ContainerAccessConditions accessConditions) { metadata = metadata == null ? new Metadata() : metadata; accessConditions = accessConditions == null ? new ContainerAccessConditions() : accessConditions; if (!validateNoEtag(accessConditions.modifiedAccessConditions()) @@ -434,8 +433,7 @@ public Mono setAccessPolicy(PublicAccessType accessType, * @throws UnsupportedOperationException If {@link ContainerAccessConditions#modifiedAccessConditions()} has either * {@link ModifiedAccessConditions#ifMatch()} or {@link ModifiedAccessConditions#ifNoneMatch()} set. */ - public Mono setAccessPolicy(PublicAccessType accessType, - List identifiers, ContainerAccessConditions accessConditions) { + public Mono setAccessPolicy(PublicAccessType accessType, List identifiers, ContainerAccessConditions accessConditions) { accessConditions = accessConditions == null ? new ContainerAccessConditions() : accessConditions; if (!validateNoEtag(accessConditions.modifiedAccessConditions())) { diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClient.java index de5d4f1431f39..12d5844a696f4 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClient.java @@ -127,6 +127,22 @@ 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. + * + * @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 diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncClient.java index b93ee7bd579e7..9e4d0fb2140f5 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncClient.java @@ -106,6 +106,17 @@ public Mono> createContainer(String containerName .map(response -> new SimpleResponse<>(response, containerAsyncClient)); } + /** + * Deletes the specified container in the storage account. If the container doesn't exist the operation fails. For + * more information see the Azure Docs. + * + * @param containerName Name of the container to delete + * @return A response containing status code and HTTP headers + */ + public Mono deleteContainer(String containerName) { + return getContainerAsyncClient(containerName).delete(); + } + /** * Gets the URL of the storage account represented by this client. * diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClient.java index 1511726d653bb..5749b1b3fe7d7 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClient.java @@ -88,6 +88,17 @@ public Response createContainer(String containerName, Metadata return new SimpleResponse<>(client.create(metadata, accessType, null), client); } + /** + * Deletes the specified container in the storage account. If the container doesn't exist the operation fails. For + * more information see the Azure Docs. + * + * @param containerName Name of the container to delete + * @return A response containing status code and HTTP headers + */ + public VoidResponse deleteContainer(String containerName) { + return storageAsyncClient.deleteContainer(containerName).block(); + } + /** * Gets the URL of the storage account represented by this client. * From 78ea66bd8222df9d1ae6af68acfcf206286b7c16 Mon Sep 17 00:00:00 2001 From: Sima Zhu <48036328+sima-zhu@users.noreply.github.com> Date: Mon, 22 Jul 2019 09:23:56 -0700 Subject: [PATCH 4/8] Storage queue linting, builder refactor, tests (#4383) * Initial check in for storage queue --- .../resources/spotbugs/spotbugs-exclude.xml | 1 + eng/jacoco-test-coverage/pom.xml | 7 +- eng/spotbugs-aggregate-report/pom.xml | 7 +- pom.client.xml | 8 +- storage/client/queue/README.md | 135 ++-- storage/client/queue/pom.xml | 78 ++ .../credentials/SharedKeyCredential.java | 39 +- .../common/policy/RequestRetryOptions.java | 6 +- .../common/policy/RequestRetryPolicy.java | 4 + .../azure/storage/queue/QueueAsyncClient.java | 474 +++++++++++- .../queue/QueueAsyncClientBuilder.java | 5 - .../com/azure/storage/queue/QueueClient.java | 389 ++++++++++ .../storage/queue/QueueClientBuilder.java | 344 +++++++++ .../storage/queue/QueueConfiguration.java | 12 + .../queue/QueueServiceAsyncClient.java | 301 ++++++++ .../storage/queue/QueueServiceClient.java | 234 ++++++ .../queue/QueueServiceClientBuilder.java | 301 ++++++++ .../java/com/azure/storage/queue/README.md | 377 ++++++++++ .../AzureQueueStorageBuilder.java | 4 +- .../queue/implementation/MessageIdsImpl.java | 21 +- .../queue/implementation/MessagesImpl.java | 41 +- .../queue/implementation/QueuesImpl.java | 64 +- .../queue/implementation/ServicesImpl.java | 3 +- ...dMessageItem.java => DequeuedMessage.java} | 31 +- .../queue/models/MessagesDequeueResponse.java | 6 +- .../queue/models/MessagesPeekResponse.java | 6 +- ...kedMessageItem.java => PeekedMessage.java} | 23 +- .../storage/queue/models/QueueProperties.java | 38 + .../queue/models/QueuesSegmentOptions.java | 89 +++ .../storage/queue/models/UpdatedMessage.java | 39 + .../com/azure/storage/queue/package-info.java | 7 + .../com/azure/storage/queue/AsyncSamples.java | 42 ++ .../azure/storage/queue/MessageSamples.java | 73 ++ .../storage/queue/QueueExceptionSamples.java | 69 ++ .../storage/queue/QueueServiceSamples.java | 31 + .../com/azure/storage/queue/SampleHelper.java | 13 + .../javadoc/QueueJavaDocCodeSamples.java | 668 +++++++++++++++++ .../QueueServiceJavaDocCodeSamples.java | 369 ++++++++++ .../storage/queue/QueueAsyncClientTests.java | 695 ++++++++++++++++++ .../azure/storage/queue/QueueClientTests.java | 654 ++++++++++++++++ .../storage/queue/QueueClientTestsBase.java | 148 ++++ .../queue/QueueServiceAsyncClientTests.java | 250 +++++++ .../queue/QueueServiceClientTests.java | 257 +++++++ .../queue/QueueServiceClientTestsBase.java | 67 ++ .../com/azure/storage/queue/TestHelpers.java | 161 ++++ .../session-records/clearMessages.json | 161 ++++ .../clearMessagesQueueDoesNotExist.json | 42 ++ .../session-records/createQueue.json | 90 +++ .../createQueueTwiceDifferentMetadata.json | 90 +++ .../createQueueTwiceSameMetadata.json | 125 ++++ .../createQueueWithMetadata.json | 91 +++ .../createTwiceDifferentMetadata.json | 71 ++ .../createTwiceSameMetadata.json | 68 ++ .../session-records/createWithMetadata.json | 72 ++ .../session-records/createWithSASToken.json | 23 + .../session-records/createWithSharedKey.json | 23 + .../session-records/deleteExisting.json | 94 +++ .../session-records/deleteExistingQueue.json | 75 ++ .../session-records/deleteMessage.json | 124 ++++ .../deleteMessageInvalidMessageId.json | 109 +++ .../deleteMessageInvalidPopReceipt.json | 109 +++ .../deleteMessageQueueDoesNotExist.json | 42 ++ .../session-records/deleteMetadata.json | 106 +++ .../session-records/deleteNonExistent.json | 42 ++ .../deleteNonExistentQueue.json | 42 ++ .../session-records/dequeueMessage.json | 90 +++ .../dequeueMultipleMessages.json | 109 +++ .../dequeueQueueDoesNotExist.json | 42 ++ .../dequeueTooManyMessages.json | 71 ++ .../session-records/enqueueEmptyMessage.json | 90 +++ .../session-records/enqueueMessage.json | 90 +++ .../enqueueQueueDoesNotExist.json | 43 ++ .../enqueueShortTimeToLiveMessage.json | 90 +++ .../session-records/getAccessPolicy.json | 71 ++ .../getAccessPolicyQueueDoesNotExist.json | 42 ++ .../session-records/getProperties.json | 72 ++ .../getPropertiesQueueDoesNotExist.json | 42 ++ .../getQueueDoesNotCreateAQueue.json | 43 ++ .../resources/session-records/listQueues.json | 186 +++++ .../listQueuesIncludeMetadata.json | 186 +++++ .../session-records/listQueuesWithPrefix.json | 186 +++++ .../session-records/peekMessage.json | 90 +++ .../session-records/peekMultipleMessages.json | 109 +++ .../peekQueueDoesNotExist.json | 42 ++ .../session-records/peekTooManyMessages.json | 71 ++ .../session-records/setAccessPolicy.json | 88 +++ .../setAccessPolicyQueueDoesNotExist.json | 43 ++ .../setInvalidAccessPolicy.json | 72 ++ .../session-records/setInvalidMetadata.json | 71 ++ .../session-records/setMetadata.json | 88 +++ .../setMetadataQueueDoesNotExist.json | 42 ++ .../session-records/setProperties.json | 114 +++ .../setTooManyAccessPolicies.json | 72 ++ .../session-records/updateMessage.json | 128 ++++ .../updateMessageInvalidMessageId.json | 110 +++ .../updateMessageInvalidPopReceipt.json | 110 +++ .../updateMessageQueueDoesNotExist.json | 43 ++ 97 files changed, 10746 insertions(+), 190 deletions(-) create mode 100644 storage/client/queue/pom.xml delete mode 100644 storage/client/queue/src/main/java/com/azure/storage/queue/QueueAsyncClientBuilder.java create mode 100644 storage/client/queue/src/main/java/com/azure/storage/queue/QueueClient.java create mode 100644 storage/client/queue/src/main/java/com/azure/storage/queue/QueueClientBuilder.java create mode 100644 storage/client/queue/src/main/java/com/azure/storage/queue/QueueConfiguration.java create mode 100644 storage/client/queue/src/main/java/com/azure/storage/queue/QueueServiceAsyncClient.java create mode 100644 storage/client/queue/src/main/java/com/azure/storage/queue/QueueServiceClient.java create mode 100644 storage/client/queue/src/main/java/com/azure/storage/queue/QueueServiceClientBuilder.java create mode 100644 storage/client/queue/src/main/java/com/azure/storage/queue/README.md rename storage/client/queue/src/main/java/com/azure/storage/queue/models/{DequeuedMessageItem.java => DequeuedMessage.java} (85%) rename storage/client/queue/src/main/java/com/azure/storage/queue/models/{PeekedMessageItem.java => PeekedMessage.java} (85%) create mode 100644 storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueProperties.java create mode 100644 storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesSegmentOptions.java create mode 100644 storage/client/queue/src/main/java/com/azure/storage/queue/models/UpdatedMessage.java create mode 100644 storage/client/queue/src/main/java/com/azure/storage/queue/package-info.java create mode 100644 storage/client/queue/src/samples/java/com/azure/storage/queue/AsyncSamples.java create mode 100644 storage/client/queue/src/samples/java/com/azure/storage/queue/MessageSamples.java create mode 100644 storage/client/queue/src/samples/java/com/azure/storage/queue/QueueExceptionSamples.java create mode 100644 storage/client/queue/src/samples/java/com/azure/storage/queue/QueueServiceSamples.java create mode 100644 storage/client/queue/src/samples/java/com/azure/storage/queue/SampleHelper.java create mode 100644 storage/client/queue/src/samples/java/com/azure/storage/queue/javadoc/QueueJavaDocCodeSamples.java create mode 100644 storage/client/queue/src/samples/java/com/azure/storage/queue/javadoc/QueueServiceJavaDocCodeSamples.java create mode 100644 storage/client/queue/src/test/java/com/azure/storage/queue/QueueAsyncClientTests.java create mode 100644 storage/client/queue/src/test/java/com/azure/storage/queue/QueueClientTests.java create mode 100644 storage/client/queue/src/test/java/com/azure/storage/queue/QueueClientTestsBase.java create mode 100644 storage/client/queue/src/test/java/com/azure/storage/queue/QueueServiceAsyncClientTests.java create mode 100644 storage/client/queue/src/test/java/com/azure/storage/queue/QueueServiceClientTests.java create mode 100644 storage/client/queue/src/test/java/com/azure/storage/queue/QueueServiceClientTestsBase.java create mode 100644 storage/client/queue/src/test/java/com/azure/storage/queue/TestHelpers.java create mode 100644 storage/client/queue/src/test/resources/session-records/clearMessages.json create mode 100644 storage/client/queue/src/test/resources/session-records/clearMessagesQueueDoesNotExist.json create mode 100644 storage/client/queue/src/test/resources/session-records/createQueue.json create mode 100644 storage/client/queue/src/test/resources/session-records/createQueueTwiceDifferentMetadata.json create mode 100644 storage/client/queue/src/test/resources/session-records/createQueueTwiceSameMetadata.json create mode 100644 storage/client/queue/src/test/resources/session-records/createQueueWithMetadata.json create mode 100644 storage/client/queue/src/test/resources/session-records/createTwiceDifferentMetadata.json create mode 100644 storage/client/queue/src/test/resources/session-records/createTwiceSameMetadata.json create mode 100644 storage/client/queue/src/test/resources/session-records/createWithMetadata.json create mode 100644 storage/client/queue/src/test/resources/session-records/createWithSASToken.json create mode 100644 storage/client/queue/src/test/resources/session-records/createWithSharedKey.json create mode 100644 storage/client/queue/src/test/resources/session-records/deleteExisting.json create mode 100644 storage/client/queue/src/test/resources/session-records/deleteExistingQueue.json create mode 100644 storage/client/queue/src/test/resources/session-records/deleteMessage.json create mode 100644 storage/client/queue/src/test/resources/session-records/deleteMessageInvalidMessageId.json create mode 100644 storage/client/queue/src/test/resources/session-records/deleteMessageInvalidPopReceipt.json create mode 100644 storage/client/queue/src/test/resources/session-records/deleteMessageQueueDoesNotExist.json create mode 100644 storage/client/queue/src/test/resources/session-records/deleteMetadata.json create mode 100644 storage/client/queue/src/test/resources/session-records/deleteNonExistent.json create mode 100644 storage/client/queue/src/test/resources/session-records/deleteNonExistentQueue.json create mode 100644 storage/client/queue/src/test/resources/session-records/dequeueMessage.json create mode 100644 storage/client/queue/src/test/resources/session-records/dequeueMultipleMessages.json create mode 100644 storage/client/queue/src/test/resources/session-records/dequeueQueueDoesNotExist.json create mode 100644 storage/client/queue/src/test/resources/session-records/dequeueTooManyMessages.json create mode 100644 storage/client/queue/src/test/resources/session-records/enqueueEmptyMessage.json create mode 100644 storage/client/queue/src/test/resources/session-records/enqueueMessage.json create mode 100644 storage/client/queue/src/test/resources/session-records/enqueueQueueDoesNotExist.json create mode 100644 storage/client/queue/src/test/resources/session-records/enqueueShortTimeToLiveMessage.json create mode 100644 storage/client/queue/src/test/resources/session-records/getAccessPolicy.json create mode 100644 storage/client/queue/src/test/resources/session-records/getAccessPolicyQueueDoesNotExist.json create mode 100644 storage/client/queue/src/test/resources/session-records/getProperties.json create mode 100644 storage/client/queue/src/test/resources/session-records/getPropertiesQueueDoesNotExist.json create mode 100644 storage/client/queue/src/test/resources/session-records/getQueueDoesNotCreateAQueue.json create mode 100644 storage/client/queue/src/test/resources/session-records/listQueues.json create mode 100644 storage/client/queue/src/test/resources/session-records/listQueuesIncludeMetadata.json create mode 100644 storage/client/queue/src/test/resources/session-records/listQueuesWithPrefix.json create mode 100644 storage/client/queue/src/test/resources/session-records/peekMessage.json create mode 100644 storage/client/queue/src/test/resources/session-records/peekMultipleMessages.json create mode 100644 storage/client/queue/src/test/resources/session-records/peekQueueDoesNotExist.json create mode 100644 storage/client/queue/src/test/resources/session-records/peekTooManyMessages.json create mode 100644 storage/client/queue/src/test/resources/session-records/setAccessPolicy.json create mode 100644 storage/client/queue/src/test/resources/session-records/setAccessPolicyQueueDoesNotExist.json create mode 100644 storage/client/queue/src/test/resources/session-records/setInvalidAccessPolicy.json create mode 100644 storage/client/queue/src/test/resources/session-records/setInvalidMetadata.json create mode 100644 storage/client/queue/src/test/resources/session-records/setMetadata.json create mode 100644 storage/client/queue/src/test/resources/session-records/setMetadataQueueDoesNotExist.json create mode 100644 storage/client/queue/src/test/resources/session-records/setProperties.json create mode 100644 storage/client/queue/src/test/resources/session-records/setTooManyAccessPolicies.json create mode 100644 storage/client/queue/src/test/resources/session-records/updateMessage.json create mode 100644 storage/client/queue/src/test/resources/session-records/updateMessageInvalidMessageId.json create mode 100644 storage/client/queue/src/test/resources/session-records/updateMessageInvalidPopReceipt.json create mode 100644 storage/client/queue/src/test/resources/session-records/updateMessageQueueDoesNotExist.json 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 f7e3bcb5eb317..5f55e13d99146 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 @@ -439,6 +439,7 @@ + diff --git a/eng/jacoco-test-coverage/pom.xml b/eng/jacoco-test-coverage/pom.xml index ea21a08695cb7..cee087f22d298 100644 --- a/eng/jacoco-test-coverage/pom.xml +++ b/eng/jacoco-test-coverage/pom.xml @@ -32,6 +32,7 @@ 4.0.0-preview.1 5.0.0-preview.2 12.0.0-preview.1 + 12.0.0-preview.1 @@ -93,7 +94,11 @@ - + + com.azure + azure-storage-queue + ${azure-storage-queue.version} + diff --git a/eng/spotbugs-aggregate-report/pom.xml b/eng/spotbugs-aggregate-report/pom.xml index a8f5addab7e12..f390bb0c7db4c 100644 --- a/eng/spotbugs-aggregate-report/pom.xml +++ b/eng/spotbugs-aggregate-report/pom.xml @@ -30,6 +30,7 @@ 4.0.0-preview.1 5.0.0-preview.2 12.0.0-preview.1 + 12.0.0-preview.1 @@ -182,7 +183,11 @@ - + + com.azure + azure-storage-queue + ${azure-storage-queue.version} + diff --git a/pom.client.xml b/pom.client.xml index d4ed7878ba447..e833ab1290e4e 100644 --- a/pom.client.xml +++ b/pom.client.xml @@ -393,6 +393,10 @@ Azure Storage - Blobs com.azure.storage.blob* + + Azure Storage - Queues + com.azure.storage.queue* + https://docs.oracle.com/javase/8/docs/api/ @@ -546,7 +550,8 @@ -snippetpath ${project.basedir}/sdk/eventhubs/azure-eventhubs/src/samples/java -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}/storage/client/queue/src/samples/java @@ -748,5 +753,6 @@ ./sdk/identity/azure-identity ./storage/client/blob + ./storage/client/queue diff --git a/storage/client/queue/README.md b/storage/client/queue/README.md index 7b4dbbf1afadd..436f7e6f2094a 100644 --- a/storage/client/queue/README.md +++ b/storage/client/queue/README.md @@ -26,9 +26,7 @@ A single queue message can be up to 64 KB in size, and a queue can contain milli To create a Storage Account you can use the Azure Portal or [Azure CLI][azure_cli]. ```Powershell -az group create \ - --name storage-resource-group \ - --location westus +az group create --name storage-resource-group --location westus ``` ### Authenticate the client @@ -52,7 +50,6 @@ az storage queue generate-sas ```Powershell CONNECTION_STRING= -#usage example az storage queue generate-sas --name javasdksas --expiry 2019-06-05 @@ -112,10 +109,10 @@ The queue service do operations on the queues in the storage account and manage ### Queue Service Client The client performs the interactions with the Queue service, create or delete a queue, getting and setting Queue properties, list queues in account, and get queue statistics. An asynchronous, `QueueServiceAsyncClient`, and synchronous, `QueueClient`, client exists in the SDK allowing for selection of a client based on an application's use case. -Once you have the value of the SASToken you can create the queue service client with `${accountName}`, `${sasToken}`. +Once you have the value of the SASToken you can create the queue service client with `${accountName}`, `${SASToken}`. ```Java -String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) -QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); +String queueServiceURL = String.format("https://%s.queue.core.windows.net", accountName) +QueueServiceClient queueServiceClient = new QueueServiceClientBuilder().endpoint(queueURL).credential(SASToken).build(); QueueClient newQueueServiceClient = queueServiceClient.createQueue("myqueue"); ``` @@ -123,8 +120,9 @@ QueueClient newQueueServiceClient = queueServiceClient.createQueue("myqueue"); or ```Java -String queueServiceAsyncURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) -QueueServiceAsyncClient queueServiceAsyncClient = QueueServiceAsyncClient.builder().endpoint(queueServiceAsyncURL).build(); +String queueServiceAsyncURL = String.format("https://%s.queue.core.windows.net/", accountName) +QueueServiceAsyncClient queueServiceAsyncClient = new QueueServiceClientBuilder().endpoint(queueServiceAsyncURL) + credential(SASToken).build(); queueServiceAsyncClient.createQueue("newAsyncQueue").subscribe( result -> { // do something when new queue created @@ -142,10 +140,10 @@ Azure Queue storage is a service for storing large numbers of messages that can A single queue message can be up to 64 KB in size, and a queue can contain millions of messages, up to the total capacity limit of a storage account. ### QueueClient -Once you have the value of the SASToken you can create the queue service client with `${accountName}`, `${queueName}`, `${sasToken}`. +Once you have the value of the SASToken you can create the queue service client with `${accountName}`, `${queueName}`, `${SASToken}`. ```Java -String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); -QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); +String queueURL = String.format("https://%s.queue.core.windows.net/%s", accountName, queueName); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).credential(SASToken).build(); // metadata is map of key-value pair, timeout is client side timeout QueueClient newQueueClient = queueClient.create(metadata, timeout); ``` @@ -170,6 +168,7 @@ queueAsyncClient.create(metadata, timeout).subscribe( ## Examples The following sections provide several code snippets covering some of the most common Configuration Service tasks, including: +- [Build a client](#build-a-client) - [Create a Queue](#Create-a-queue) - [Delete a queue](#Delete-a-queue) - [List the queues in account](#List-queues-in-account) @@ -183,32 +182,54 @@ The following sections provide several code snippets covering some of the most c - [Delete message from a queue](#Delete-message-from-a-queue) - [Get a Queue properties](#Get-a-queue-properties) - [Set/Update a Queue metadata](#Set-a-queue-metadata) + +### Build a client +We have two ways of building QueueService or Queue Client. Here will take queueServiceClient as an example. Same things apply to queueClient. + +First, build client from full URL/endpoint (e.g. with queueName, with SASToken and etc.) + +```Java +String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken); +QueueServiceClient queueServiceClient = new QueueServiceClientBuilder().endpoint(queueServiceURL).buildClient(); +``` + +Or + +We can build the queueServiceClient from the builder using `${SASToken}` as credential. + +```Java +String queueServiceURL = String.format("https://%s.queue.core.windows.net", accountName); +QueueServiceClient queueServiceClient = new QueueServiceClientBuilder().endpoint(queueServiceURL).credential(SASToken).buildClient(); +``` + ### Create a queue -Create a queue in the Storage Account. Throws StorageErrorException If the queue fails to be created. +Create a queue in the Storage Account using `${SASToken}` as credential. +Throws StorageErrorException If the queue fails to be created. ```Java -String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) -QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); +String queueServiceURL = String.format("https://%s.queue.core.windows.net", accountName); +QueueServiceClient queueServiceClient = new QueueServiceClientBuilder().endpoint(queueServiceURL).credential(SASToken).buildClient(); QueueClient newQueueServiceClient = queueServiceClient.createQueue("myqueue"); ``` ### Delete a queue -Delete a queue in the Storage Account. Throws StorageErrorException If the queue fails to be deleted. +Delete a queue in the Storage Account using `${SASToken}` as credential. +Throws StorageErrorException If the queue fails to be deleted. ```Java -String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) -QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); +String queueServiceURL = String.format("https://%s.queue.core.windows.net", accountName); +QueueServiceClient queueServiceClient = new QueueServiceClientBuilder().endpoint(queueServiceURL).credential(SASToken).buildClient(); QueueClient newQueueServiceClient = queueServiceClient.deleteQueue("myqueue"); ``` ### List queues in account -List all the queues in account. +List all the queues in account using `${SASToken}` as credential. ```Java -String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) -QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); +String queueServiceURL = String.format("https://%s.queue.core.windows.net", accountName); +QueueServiceClient queueServiceClient = new QueueServiceClientBuilder().endpoint(queueServiceURL).credential(SASToken).buildClient(); // @param marker: Starting point to list the queues // @param options: Filter for queue selection queueServiceClient.listQueuesSegment(marker, options).forEach{ @@ -219,9 +240,11 @@ queueServiceClient.listQueuesSegment(marker, options).forEach{ ### Get properties in queue account Get queue properties in account, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules. + +Use `${SASToken}` as credential. ```Java -String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) -QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); +String queueServiceURL = String.format("https://%s.queue.core.windows.net", accountName); +QueueServiceClient queueServiceClient = new QueueServiceClientBuilder().endpoint(queueServiceURL).credential(SASToken).buildClient(); Response properties = queueServiceClient.getProperties(); ``` @@ -229,9 +252,11 @@ Response properties = queueServiceClient.getProperties ### Set properties in queue account Set queue properties in account, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules. + +Use `${SASToken}` as credential. ```Java -String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) -QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); +String queueServiceURL = String.format("https://%s.queue.core.windows.net", accountName); +QueueServiceClient queueServiceClient = new QueueServiceClientBuilder().endpoint(queueServiceURL).credential(SASToken).buildClient(); StorageServiceProperties properties = new StorageServiceProperties() { // logging: some logging; @@ -244,30 +269,34 @@ queueServiceClient.setProperties(properties); ``` ### Get queue service statistics -he `Get Queue Service Stats` operation retrieves statistics related to replication for the Queue service. +The `Get Queue Service Stats` operation retrieves statistics related to replication for the Queue service. + +Use `${SASToken}` as credential. It is only available on the secondary location endpoint when read-access geo-redundant replication is enabled for the storage account. ```Java -String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) -QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); +String queueServiceURL = String.format("https://%s.queue.core.windows.net", accountName); +QueueServiceClient queueServiceClient = new QueueServiceClientBuilder().endpoint(queueServiceURL).credential(SASToken).buildClient(); Response queueStats = queueServiceClient.getStatistics(); ``` ### Enqueue message into a queue The operation adds a new message to the back of the message queue. A visibility timeout can also be specified to make the message invisible until the visibility timeout expires. + +Use `${SASToken}` as credential. A message must be in a format that can be included in an XML request with UTF-8 encoding. The encoded message can be up to 64 KB in size for versions 2011-08-18 and newer, or 8 KB in size for previous versions. ```Java -String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); -QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); +String queueSURL = String.format("https://%s.queue.core.windows.net", accountName); +QueueClient queueClient = new QueueClientBuilder().endpoint(queueURL).credential(SASToken).queueName("myqueue").buildClient(); queueClient.enqueueMessage("myMessage"); ``` ### Update messaged from a queue -The operation updates a message in the message queue. +The operation updates a message in the message queue. Use `${SASToken}` as credential. ```Java -String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); -QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); +String queueSURL = String.format("https://%s.queue.core.windows.net", accountName); +QueueClient queueClient = new QueueClientBuilder().endpoint(queueURL).credential(SASToken).queueName("myqueue").buildClient(); // @param messageId Id of the message // @param popReceipt Unique identifier that must match the message for it to be updated // @param visibilityTimeout How long the message will be invisible in the queue in seconds @@ -275,48 +304,52 @@ queueClient.updateMessage(messageId, "new message", popReceipt, visibilityTimeou ``` ### Peek messages from a queue -The operation retrieves one or more messages from the front of the queue. +The operation retrieves one or more messages from the front of the queue. Use `${SASToken}` as credential. ```Java -String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); -QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); +String queueSURL = String.format("https://%s.queue.core.windows.net", accountName); +QueueClient queueClient = new QueueClientBuilder().endpoint(queueURL).credential(SASToken).queueName("myqueue").buildClient(); queueClient.peekMessages().forEach(message-> {print message.messageText();}); ``` ### Dequeue messages from a queue -The operation retrieves one or more messages from the front of the queue. +The operation retrieves one or more messages from the front of the queue. Use `${SASToken}` as credential. ```Java -String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); -QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); +String queueSURL = String.format("https://%s.queue.core.windows.net", accountName); +QueueClient queueClient = new QueueClientBuilder().endpoint(queueURL).credential(SASToken).queueName("myqueue").buildClient(); queueClient.dequeueMessage("myMessage").forEach(message-> {print message.messageText();}); ``` ### Delete message from a queue -The operation retrieves one or more messages from the front of the queue. +The operation retrieves one or more messages from the front of the queue. Use `${SASToken}` as credential. ```Java -String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); -QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); +String queueSURL = String.format("https://%s.queue.core.windows.net", accountName); +QueueClient queueClient = new QueueClientBuilder().endpoint(queueURL).credential(SASToken).queueName("myqueue").buildClient(); queueClient.deleteMessage(messageId, popReceipt); ``` ### Get a queue properties The operation retrieves user-defined metadata and queue properties on the specified queue. Metadata is associated with the queue as name-values pairs. + +Use `${SASToken}` as credential. ```Java -String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); -QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); +String queueSURL = String.format("https://%s.queue.core.windows.net", accountName); +QueueClient queueClient = new QueueClientBuilder().endpoint(queueURL).credential(SASToken).queueName("myqueue").buildClient(); Response properties = queueClient.getProperties(); ``` ### Set a queue metadata The operation sets user-defined metadata on the specified queue. Metadata is associated with the queue as name-value pairs. + +Use `${SASToken}` as credential. ```Java -String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); -QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); +String queueSURL = String.format("https://%s.queue.core.windows.net", accountName); +QueueClient queueClient = new QueueClientBuilder().endpoint(queueURL).credential(SASToken).queueName("myqueue").buildClient(); Map metadata = new HashMap<>() {{ put("key1", "val1"); @@ -335,10 +368,11 @@ When you interact with queue using this Java client library, errors returned by ## Next steps ### More Samples -- QueueServiceSample -- MessageSample -- QueueExceptionSample -- AsyncSample +Get started with our [Queue samples][samples]: +- [QueueServiceSample](src/samples/java/blob/QueueServiceSample.java): Create, list and delete queues +- [MessageSample](src/samples/java/blob/MessageSample.java): Enqueue, peek dequeue, update, clear and delete messages. Get properties of the queue. +- [QueueExceptionSample](src/samples/java/blob/QueueExceptionSample.java): Handle the exceptions from storage queue service side. +- [AsyncSample](src/samples/java/blob/AsyncSample.java): Create queue and enqueue message using async queue client call. [Quickstart: Create a Java Spring app with App Configuration](https://docs.microsoft.com/en-us/azure/azure-app-configuration/quickstart-java-spring-app) @@ -375,3 +409,4 @@ If you would like to become an active contributor to this project please follow [azure_cli]: https://docs.microsoft.com/cli/azure [sas_token]: https://docs.microsoft.com/en-us/azure/storage/common/storage-dotnet-shared-access-signature-part-1 [storage_rest]: https://docs.microsoft.com/en-us/rest/api/storageservices/queue-service-error-codes +[samples]: samples/ diff --git a/storage/client/queue/pom.xml b/storage/client/queue/pom.xml new file mode 100644 index 0000000000000..c018da31ab260 --- /dev/null +++ b/storage/client/queue/pom.xml @@ -0,0 +1,78 @@ + + + + com.azure + azure-client-sdk-parent + 1.1.0 + ../../../pom.client.xml + + + 4.0.0 + + com.azure + azure-storage-queue + 12.0.0-preview.1 + + azure-storage-queue + https://github.com/Azure/azure-sdk-for-java + + + + azure-java-build-docs + ${site.url}/site/${project.artifactId} + + + + + scm:git:https://github.com/Azure/azure-sdk-for-java + scm:git:git@github.com:Azure/azure-sdk-for-java.git + HEAD + + + + + com.azure + azure-core + 1.0.0-preview.2 + + + org.slf4j + slf4j-api + + + + com.azure + azure-core-test + 1.0.0-preview.2 + test + + + com.azure + azure-identity + 1.0.0-preview.1 + test + + + junit + junit + test + + + org.slf4j + slf4j-simple + test + + + io.projectreactor + reactor-test + test + + + com.microsoft.azure + adal4j + test + + + diff --git a/storage/client/queue/src/main/java/com/azure/storage/common/credentials/SharedKeyCredential.java b/storage/client/queue/src/main/java/com/azure/storage/common/credentials/SharedKeyCredential.java index 19b2b4c307221..db8045e723a1a 100644 --- a/storage/client/queue/src/main/java/com/azure/storage/common/credentials/SharedKeyCredential.java +++ b/storage/client/queue/src/main/java/com/azure/storage/common/credentials/SharedKeyCredential.java @@ -4,6 +4,7 @@ package com.azure.storage.common.credentials; import com.azure.core.implementation.util.ImplUtils; +import com.azure.core.util.logging.ClientLogger; import io.netty.handler.codec.http.QueryStringDecoder; import javax.crypto.Mac; @@ -26,11 +27,12 @@ * SharedKey credential policy that is put into a header to authorize requests. */ public final class SharedKeyCredential { + private static final ClientLogger LOGGER = new ClientLogger(SharedKeyCredential.class); private static final String AUTHORIZATION_HEADER_FORMAT = "SharedKey %s:%s"; // Pieces of the connection string that are needed. - private static final String ACCOUNT_NAME = "AccountName".toLowerCase(); - private static final String ACCOUNT_KEY = "AccountKey".toLowerCase(); + private static final String ACCOUNT_NAME = "accountname"; + private static final String ACCOUNT_KEY = "accountkey"; private final String accountName; private final byte[] accountKey; @@ -59,7 +61,7 @@ public static SharedKeyCredential fromConnectionString(String connectionString) HashMap connectionStringPieces = new HashMap<>(); for (String connectionStringPiece : connectionString.split(";")) { String[] kvp = connectionStringPiece.split("=", 2); - connectionStringPieces.put(kvp[0].toLowerCase(), kvp[1]); + connectionStringPieces.put(kvp[0].toLowerCase(Locale.ROOT), kvp[1]); } String accountName = connectionStringPieces.get(ACCOUNT_NAME); @@ -98,9 +100,11 @@ public String generateAuthorizationHeader(URL requestURL, String httpMethod, Map * * @param stringToSign The UTF-8-encoded string to sign. * @return A {@code String} that contains the HMAC-SHA256-encoded signature. - * @throws InvalidKeyException If the accountKey is not a valid Base64-encoded string. + * @throws RuntimeException for one of the following cases: + * - If the HMAC-SHA256 signature for {@code sharedKeyCredentials} fails to generate. + * - If the an invalid key has been given to the client. */ - public String computeHmac256(final String stringToSign) throws InvalidKeyException { + public String computeHmac256(final String stringToSign) { try { /* We must get a new instance of the Mac calculator for each signature calculated because the instances are @@ -111,8 +115,12 @@ public String computeHmac256(final String stringToSign) throws InvalidKeyExcepti hmacSha256.init(new SecretKeySpec(this.accountKey, "HmacSHA256")); byte[] utf8Bytes = stringToSign.getBytes(StandardCharsets.UTF_8); return Base64.getEncoder().encodeToString(hmacSha256.doFinal(utf8Bytes)); - } catch (final NoSuchAlgorithmException e) { - throw new Error(e); + } catch (final NoSuchAlgorithmException e) { + LOGGER.asError().log(e.getMessage()); + throw new RuntimeException(e); + } catch (InvalidKeyException e) { + LOGGER.asError().log("Please double check the account key. Error details: " + e.getMessage()); + throw new RuntimeException("Please double check the account key. Error details: " + e.getMessage()); } } @@ -121,20 +129,20 @@ private String buildStringToSign(URL requestURL, String httpMethod, MapSample Code

* *

For more samples, please see the samples file

+ * @throws IllegalArgumentException If one of the following case exists: + *
    + *
  • There is only one null value for retryDelay and maxRetryDelay.
  • + *
  • Unrecognized retry policy type.
  • + *
*/ public RequestRetryOptions(RetryPolicyType retryPolicyType, Integer maxTries, Integer tryTimeout, Long retryDelayInMs, Long maxRetryDelayInMs, String secondaryHost) { @@ -105,7 +110,6 @@ public RequestRetryOptions(RetryPolicyType retryPolicyType, Integer maxTries, In } this.maxRetryDelayInMs = TimeUnit.SECONDS.toMillis(120); } - this.secondaryHost = secondaryHost; } diff --git a/storage/client/queue/src/main/java/com/azure/storage/common/policy/RequestRetryPolicy.java b/storage/client/queue/src/main/java/com/azure/storage/common/policy/RequestRetryPolicy.java index b862b76928af0..1b4bf56936bf5 100644 --- a/storage/client/queue/src/main/java/com/azure/storage/common/policy/RequestRetryPolicy.java +++ b/storage/client/queue/src/main/java/com/azure/storage/common/policy/RequestRetryPolicy.java @@ -30,6 +30,10 @@ public final class RequestRetryPolicy implements HttpPipelinePolicy { private final RequestRetryOptions requestRetryOptions; + /** + * Create a policy of retrying a given HTTP request. + * @param requestRetryOptions Options for configuring the RequestRetryPolicy. + */ public RequestRetryPolicy(RequestRetryOptions requestRetryOptions) { this.requestRetryOptions = requestRetryOptions; } diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/QueueAsyncClient.java b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueAsyncClient.java index eab2a19707d5c..2d3bd7636aeaf 100644 --- a/storage/client/queue/src/main/java/com/azure/storage/queue/QueueAsyncClient.java +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueAsyncClient.java @@ -1,29 +1,473 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. package com.azure.storage.queue; -import com.azure.core.ServiceClient; import com.azure.core.http.HttpPipeline; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.http.rest.VoidResponse; +import com.azure.core.util.Context; +import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.common.credentials.SASTokenCredential; +import com.azure.storage.common.credentials.SharedKeyCredential; import com.azure.storage.queue.implementation.AzureQueueStorageBuilder; import com.azure.storage.queue.implementation.AzureQueueStorageImpl; - +import com.azure.storage.queue.models.DequeuedMessage; +import com.azure.storage.queue.models.EnqueuedMessage; +import com.azure.storage.queue.models.MessageIdUpdateHeaders; +import com.azure.storage.queue.models.MessageIdsUpdateResponse; +import com.azure.storage.queue.models.PeekedMessage; +import com.azure.storage.queue.models.QueueGetPropertiesHeaders; +import com.azure.storage.queue.models.QueueMessage; +import com.azure.storage.queue.models.QueueProperties; +import com.azure.storage.queue.models.QueuesGetPropertiesResponse; +import com.azure.storage.queue.models.SignedIdentifier; +import com.azure.storage.queue.models.StorageErrorException; +import com.azure.storage.queue.models.UpdatedMessage; +import java.net.MalformedURLException; import java.net.URL; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +/** + * This class provides a client that contains all the operations for interacting with a queue in Azure Storage Queue. + * Operations allowed by the client are creating and deleting the queue, retrieving and updating metadata and access + * policies of the queue, and enqueuing, dequeuing, peeking, updating, and deleting messages. + * + *

Instantiating an Asynchronous Queue Client

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.instantiation} + * + *

View {@link QueueClientBuilder this} for additional ways to construct the client.

+ * + * @see QueueClientBuilder + * @see QueueClient + * @see SharedKeyCredential + * @see SASTokenCredential + */ +public final class QueueAsyncClient { + private static final ClientLogger LOGGER = new ClientLogger(QueueAsyncClient.class); + private final AzureQueueStorageImpl client; + private final String queueName; + + /** + * Creates a QueueAsyncClient that sends requests to the storage queue service at {@code AzureQueueStorageImpl#url() endpoint}. + * Each service call goes through the {@link HttpPipeline pipeline} in the {@code AzureQueueStorageImpl client}. + * + * @param client Client that interacts with the service interfaces + * @param queueName Name of the queue + */ + QueueAsyncClient(AzureQueueStorageImpl client, String queueName) { + this.queueName = queueName; + + this.client = new AzureQueueStorageBuilder().pipeline(client.httpPipeline()) + .url(client.url()) + .version(client.version()) + .build(); + } + + /** + * Creates a QueueAsyncClient that sends requests to the storage queue service at {@code endpoint}. + * Each service call goes through the {@code httpPipeline}. + * + * @param endpoint URL for the Storage Queue service + * @param httpPipeline HttpPipeline that the HTTP requests and response flow through + * @param queueName Name of the queue + */ + QueueAsyncClient(URL endpoint, HttpPipeline httpPipeline, String queueName) { + this.queueName = queueName; + + this.client = new AzureQueueStorageBuilder().pipeline(httpPipeline) + .url(endpoint.toString()) + .build(); + } + + /** + * @return the URL of the storage queue + * @throws RuntimeException If the queue is using a malformed URL. + */ + public URL getQueueUrl() { + try { + return new URL(client.url()); + } catch (MalformedURLException ex) { + LOGGER.asError().log("Queue URL is malformed"); + throw new RuntimeException("Queue URL is malformed"); + } + } + + /** + * Creates a new queue. + * + *

Code Samples

+ * + *

Create a queue

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.create} + * + * @return A response that only contains headers and response status code + * @throws StorageErrorException If a queue with the same name already exists in the queue service. + */ + public Mono create() { + return create(null); + } + + /** + * Creates a new queue. + * + *

Code Samples

+ * + *

Create a queue with metadata "queue:metadataMap"

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.create#map} + * + * @param metadata Metadata to associate with the queue + * @return A response that only contains headers and response status code + * @throws StorageErrorException If a queue with the same name and different metadata already exists in the queue service. + */ + public Mono create(Map metadata) { + return client.queues().createWithRestResponseAsync(queueName, null, metadata, null, Context.NONE) + .map(VoidResponse::new); + } + + /** + * Permanently deletes the queue. + * + *

Code Samples

+ * + *

Delete a queue

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.delete} + * + * @return A response that only contains headers and response status code + * @throws StorageErrorException If the queue doesn't exist + */ + public Mono delete() { + return client.queues().deleteWithRestResponseAsync(queueName, Context.NONE) + .map(VoidResponse::new); + } + + /** + * Retrieves metadata and approximate message count of the queue. + * + *

Code Samples

+ * + *

Get the properties of the queue

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.getProperties} + * + * @return A response containing a {@link QueueProperties} value which contains the metadata and approximate + * messages count of the queue. + * @throws StorageErrorException If the queue doesn't exist + */ + public Mono> getProperties() { + return client.queues().getPropertiesWithRestResponseAsync(queueName, Context.NONE) + .map(this::getQueuePropertiesResponse); + } + + /** + * Sets the metadata of the queue. + * + * Passing in a {@code null} value for metadata will clear the metadata associated with the queue. + * + *

Code Samples

+ * + *

Set the queue's metadata to "queue:metadataMap"

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.setMetadata#map} + * + *

Clear the queue's metadata

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.clearMetadata#map} + * + * @param metadata Metadata to set on the queue + * @return A response that only contains headers and response status code + * @throws StorageErrorException If the queue doesn't exist + */ + public Mono setMetadata(Map metadata) { + return client.queues().setMetadataWithRestResponseAsync(queueName, null, metadata, null, Context.NONE) + .map(VoidResponse::new); + } + + /** + * Retrieves stored access policies specified on the queue. + * + *

Code Samples

+ * + *

List the stored access policies

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.getAccessPolicy} + * + * @return The stored access policies specified on the queue. + * @throws StorageErrorException If the queue doesn't exist + */ + public Flux getAccessPolicy() { + return client.queues().getAccessPolicyWithRestResponseAsync(queueName, Context.NONE) + .flatMapMany(response -> Flux.fromIterable(response.value())); + } + + /** + * Sets stored access policies on the queue. + * + *

Code Samples

+ * + *

Set a read only stored access policy

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.setAccessPolicy} + * + * @param permissions Access policies to set on the queue + * @return A response that only contains headers and response status code + * @throws StorageErrorException If the queue doesn't exist, a stored access policy doesn't have all fields filled out, + * or the queue will have more than five policies. + */ + public Mono setAccessPolicy(List permissions) { + return client.queues().setAccessPolicyWithRestResponseAsync(queueName, permissions, null, null, Context.NONE) + .map(VoidResponse::new); + } + + /** + * Deletes all messages in the queue. + * + *

Code Samples

+ * + *

Clear the messages

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.clearMessages} + * + * @return A response that only contains headers and response status code + * @throws StorageErrorException If the queue doesn't exist + */ + public Mono clearMessages() { + return client.messages().clearWithRestResponseAsync(queueName, Context.NONE) + .map(VoidResponse::new); + } + + /** + * Enqueues a message that has a time-to-live of 7 days and is instantly visible. + * + *

Code Samples

+ * + *

Enqueue a message of "Hello, Azure"

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.enqueueMessage#string} + * + * @param messageText Message text + * @return A {@link EnqueuedMessage} value that contains the {@link EnqueuedMessage#messageId() messageId} and + * {@link EnqueuedMessage#popReceipt() popReceipt} that are used to interact with the message and other metadata + * about the enqueued message. + * @throws StorageErrorException If the queue doesn't exist + */ + public Mono> enqueueMessage(String messageText) { + return enqueueMessage(messageText, Duration.ofSeconds(0), Duration.ofDays(7)); + } + + /** + * Enqueues a message with a given time-to-live and a timeout period where the message is invisible in the queue. + * + *

Code Samples

+ * + *

Add a message of "Hello, Azure" that has a timeout of 5 seconds

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.enqueueMessage#string-duration-duration} + * + *

Add a message of "Goodbye, Azure" that has a time to live of 5 seconds

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.enqueueMessageLiveTime#string-duration-duration} + * + * @param messageText Message text + * @param visibilityTimeout Optional. The timeout period for how long the message is invisible in the queue in seconds. + * If unset the value will default to 0 and the message will be instantly visible. The timeout must be between 0 + * seconds and 7 days. + * @param timeToLive Optional. How long the message will stay alive in the queue in seconds. If unset the value will + * default to 7 days, if -1 is passed the message will not expire. The time to live must be -1 or any positive number. + * @return A {@link EnqueuedMessage} value that contains the {@link EnqueuedMessage#messageId() messageId} and + * {@link EnqueuedMessage#popReceipt() popReceipt} that are used to interact with the message and other metadata + * about the enqueued message. + * @throws StorageErrorException If the queue doesn't exist or the {@code visibilityTimeout} or {@code timeToLive} + * are outside of the allowed limits. + */ + public Mono> enqueueMessage(String messageText, Duration visibilityTimeout, Duration timeToLive) { + Integer visibilityTimeoutInSeconds = (visibilityTimeout == null) ? null : (int) visibilityTimeout.getSeconds(); + Integer timeToLiveInSeconds = (timeToLive == null) ? null : (int) timeToLive.getSeconds(); + QueueMessage message = new QueueMessage().messageText(messageText); + + return client.messages().enqueueWithRestResponseAsync(queueName, message, visibilityTimeoutInSeconds, timeToLiveInSeconds, null, null, Context.NONE) + .map(response -> new SimpleResponse<>(response, response.value().get(0))); + } + + /** + * Retrieves the first message in the queue and hides it from other operations for 30 seconds. + * + *

Code Samples

+ * + *

Dequeue a message

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.dequeueMessages} + * + * @return The first {@link DequeuedMessage} in the queue, it contains + * {@link DequeuedMessage#messageId() messageId} and {@link DequeuedMessage#popReceipt() popReceipt} used to interact + * with the message, additionally it contains other metadata about the message. + * @throws StorageErrorException If the queue doesn't exist + */ + public Flux dequeueMessages() { + return dequeueMessages(1, Duration.ofSeconds(30)); + } + + /** + * Retrieves up to the maximum number of messages from the queue and hides them from other operations for 30 seconds. + * + *

Code Samples

+ * + *

Dequeue up to 5 messages

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.dequeueMessages#integer} + * + * @param maxMessages Optional. Maximum number of messages to get, if there are less messages exist in the queue than requested + * all the messages will be returned. If left empty only 1 message will be retrieved, the allowed range is 1 to 32 + * messages. + * @return Up to {@code maxMessages} {@link DequeuedMessage DequeuedMessages} from the queue. Each DequeuedMessage contains + * {@link DequeuedMessage#messageId() messageId} and {@link DequeuedMessage#popReceipt() popReceipt} used to interact + * with the message and other metadata about the message. + * @throws StorageErrorException If the queue doesn't exist or {@code maxMessages} is outside of the allowed bounds + */ + public Flux dequeueMessages(Integer maxMessages) { + return dequeueMessages(maxMessages, Duration.ofSeconds(30)); + } -public class QueueAsyncClient extends ServiceClient { - private final String endpoint; - private final AzureQueueStorageImpl generateClient; - private final String apiVersion; + /** + * Retrieves up to the maximum number of messages from the queue and hides them from other operations for the + * timeout period. + * + *

Code Samples

+ * + *

Dequeue up to 5 messages and give them a 60 second timeout period

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.dequeueMessages#integer-duration} + * + * @param maxMessages Optional. Maximum number of messages to get, if there are less messages exist in the queue than requested + * all the messages will be returned. If left empty only 1 message will be retrieved, the allowed range is 1 to 32 + * messages. + * @param visibilityTimeout Optional. The timeout period for how long the message is invisible in the queue in seconds. + * If left empty the dequeued messages will be invisible for 30 seconds. The timeout must be between 1 second and 7 days. + * @return Up to {@code maxMessages} {@link DequeuedMessage DequeuedMessages} from the queue. Each DeqeuedMessage contains + * {@link DequeuedMessage#messageId() messageId} and {@link DequeuedMessage#popReceipt() popReceipt} used to interact + * with the message and other metadata about the message. + * @throws StorageErrorException If the queue doesn't exist or {@code maxMessages} or {@code visibilityTimeout} is + * outside of the allowed bounds + */ + public Flux dequeueMessages(Integer maxMessages, Duration visibilityTimeout) { + Integer visibilityTimeoutInSeconds = (visibilityTimeout == null) ? null : (int) visibilityTimeout.getSeconds(); + return client.messages().dequeueWithRestResponseAsync(queueName, maxMessages, visibilityTimeoutInSeconds, null, null, Context.NONE) + .flatMapMany(response -> Flux.fromIterable(response.value())); + } - private QueueAsyncClient(URL endpoint, HttpPipeline httpPipeline) { - super(httpPipeline); - this.endpoint = endpoint.toString(); - this.generateClient = new AzureQueueStorageBuilder().pipeline(httpPipeline).url(this.endpoint).build(); - this.apiVersion = this.generateClient.version(); + /** + * Peeks the first message in the queue. + * + * Peeked messages don't contain the necessary information needed to interact with the message nor will it hide + * messages from other operations on the queue. + * + *

Code Samples

+ * + *

Peek the first message

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.peekMessages} + * + * @return A {@link PeekedMessage} that contains metadata about the message. + */ + public Flux peekMessages() { + return peekMessages(null); + } + + /** + * Peek messages from the front of the queue up to the maximum number of messages. + * + * Peeked messages don't contain the necessary information needed to interact with the message nor will it hide + * messages from other operations on the queue. + * + *

Code Samples

+ * + *

Peek up to the first five messages

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.peekMessages#integer} + * + * @param maxMessages Optional. Maximum number of messages to peek, if there are less messages exist in the queue than requested + * all the messages will be peeked. If left empty only 1 message will be peeked, the allowed range is 1 to 32 + * messages. + * @return Up to {@code maxMessages} {@link PeekedMessage PeekedMessages} from the queue. Each PeekedMessage contains + * metadata about the message. + * @throws StorageErrorException If the queue doesn't exist or {@code maxMessages} is outside of the allowed bounds + */ + public Flux peekMessages(Integer maxMessages) { + return client.messages().peekWithRestResponseAsync(queueName, maxMessages, null, null, Context.NONE) + .flatMapMany(response -> Flux.fromIterable(response.value())); } /** - * Creates a appendBlobClientBuilder that can configure options for the SecretAsyncClient before creating an instance of it. - * @return A new appendBlobClientBuilder to create a SecretAsyncClient from. + * Updates the specific message in the queue with a new message and resets the visibility timeout. + * + *

Code Samples

+ * + *

Dequeue the first message and update it to "Hello again, Azure" and hide it for 5 seconds

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.updateMessage} + * + * @param messageText Updated value for the message + * @param messageId Id of the message to update + * @param popReceipt Unique identifier that must match for the message to be updated + * @param visibilityTimeout The timeout period for how long the message is invisible in the queue in seconds. The + * timeout period must be between 1 second and 7 days. + * @return A {@link UpdatedMessage} that contains the new {@link UpdatedMessage#popReceipt() popReceipt} to interact + * with the message, additionally contains the updated metadata about the message. + * @throws StorageErrorException If the queue or messageId don't exist, the popReceipt doesn't match on the message, + * or the {@code visibilityTimeout} is outside the allowed bounds + */ + public Mono> updateMessage(String messageText, String messageId, String popReceipt, Duration visibilityTimeout) { + QueueMessage message = new QueueMessage().messageText(messageText); + return client.messageIds().updateWithRestResponseAsync(queueName, messageId, message, popReceipt, (int) visibilityTimeout.getSeconds(), Context.NONE) + .map(this::getUpdatedMessageResponse); + } + + /** + * Deletes the specified message in the queue + * + *

Code Samples

+ * + *

Delete the first message

+ * + * {@codesnippet com.azure.storage.queue.queueAsyncClient.deleteMessage} + * + * @param messageId Id of the message to deleted + * @param popReceipt Unique identifier that must match for the message to be deleted + * @return A response that only contains headers and response status code + * @throws StorageErrorException If the queue or messageId don't exist or the popReceipt doesn't match on the message + */ + public Mono deleteMessage(String messageId, String popReceipt) { + return client.messageIds().deleteWithRestResponseAsync(queueName, messageId, popReceipt, Context.NONE) + .map(VoidResponse::new); + } + + /* + * Maps the HTTP headers returned from the service to the expected response type + * @param response Service response + * @return Mapped response + */ + private Response getQueuePropertiesResponse(QueuesGetPropertiesResponse response) { + QueueGetPropertiesHeaders propertiesHeaders = response.deserializedHeaders(); + QueueProperties properties = new QueueProperties(propertiesHeaders.metadata(), propertiesHeaders.approximateMessagesCount()); + return new SimpleResponse<>(response, properties); + } + + /* + * Maps the HTTP headers returned from the service to the expected response type + * @param response Service response + * @return Mapped response */ - public static QueueAsyncClientBuilder builder() { - return new QueueAsyncClientBuilder(); + private Response getUpdatedMessageResponse(MessageIdsUpdateResponse response) { + MessageIdUpdateHeaders headers = response.deserializedHeaders(); + UpdatedMessage updatedMessage = new UpdatedMessage(headers.popReceipt(), headers.timeNextVisible()); + return new SimpleResponse<>(response, updatedMessage); } } diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/QueueAsyncClientBuilder.java b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueAsyncClientBuilder.java deleted file mode 100644 index b76c9c63e8700..0000000000000 --- a/storage/client/queue/src/main/java/com/azure/storage/queue/QueueAsyncClientBuilder.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.azure.storage.queue; - -public class QueueAsyncClientBuilder { - -} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/QueueClient.java b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueClient.java new file mode 100644 index 0000000000000..763c58560871e --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueClient.java @@ -0,0 +1,389 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.common.credentials.SASTokenCredential; +import com.azure.storage.common.credentials.SharedKeyCredential; +import com.azure.storage.queue.models.DequeuedMessage; +import com.azure.storage.queue.models.EnqueuedMessage; +import com.azure.storage.queue.models.PeekedMessage; +import com.azure.storage.queue.models.QueueProperties; +import com.azure.storage.queue.models.SignedIdentifier; +import com.azure.storage.queue.models.StorageErrorException; +import com.azure.storage.queue.models.UpdatedMessage; +import java.net.URL; +import java.time.Duration; +import java.util.List; +import java.util.Map; + +/** + * This class provides a client that contains all the operations for interacting with a queue in Azure Storage Queue. + * Operations allowed by the client are creating and deleting the queue, retrieving and updating metadata and access + * policies of the queue, and enqueuing, dequeuing, peeking, updating, and deleting messages. + * + *

Instantiating an Synchronous Queue Client

+ * + * {@codesnippet com.azure.storage.queue.queueClient.instantiation} + * + *

View {@link QueueClientBuilder this} for additional ways to construct the client.

+ * + * @see QueueClientBuilder + * @see QueueAsyncClient + * @see SharedKeyCredential + * @see SASTokenCredential + */ +public final class QueueClient { + private final QueueAsyncClient client; + + /** + * Creates a QueueClient that wraps a QueueAsyncClient and blocks requests. + * + * @param client QueueAsyncClient that is used to send requests + */ + QueueClient(QueueAsyncClient client) { + this.client = client; + } + + /** + * @return the URL of the storage queue. + * @throws RuntimeException If the queue is using a malformed URL. + */ + public URL getQueueUrl() { + return client.getQueueUrl(); + } + + /** + * Creates a new queue. + * + *

Code Samples

+ * + *

Create a queue

+ * + *{@codesnippet com.azure.storage.queue.queueClient.create} + * + * @return A response that only contains headers and response status code + * @throws StorageErrorException If a queue with the same name already exists in the queue service. + */ + public VoidResponse create() { + return create(null); + } + + /** + * Creates a new queue. + * + *

Code Samples

+ * + *

Create a queue with metadata "queue:metadataMap"

+ * + * {@codesnippet com.azure.storage.queue.queueClient.create#map} + * + * @param metadata Metadata to associate with the queue + * @return A response that only contains headers and response status code + * @throws StorageErrorException If a queue with the same name and different metadata already exists in the queue service. + */ + public VoidResponse create(Map metadata) { + return client.create(metadata).block(); + } + + /** + * Permanently deletes the queue. + * + *

Code Samples

+ * + *

Delete a queue

+ * + * {@codesnippet com.azure.storage.queue.queueClient.delete} + * + * @return A response that only contains headers and response status code + * @throws StorageErrorException If the queue doesn't exist + */ + public VoidResponse delete() { + return client.delete().block(); + } + + /** + * Retrieves metadata and approximate message count of the queue. + * + *

Code Samples

+ * + *

Get the properties of the queue

+ * + * {@codesnippet com.azure.storage.queue.queueClient.getProperties} + * + * @return A response containing a {@link QueueProperties} value which contains the metadata and approximate + * messages count of the queue. + * @throws StorageErrorException If the queue doesn't exist + */ + public Response getProperties() { + return client.getProperties().block(); + } + + /** + * Sets the metadata of the queue. + * + * Passing in a {@code null} value for metadata will clear the metadata associated with the queue. + * + *

Code Samples

+ * + *

Set the queue's metadata to "queue:metadataMap"

+ * + * {@codesnippet com.azure.storage.queue.queueClient.setMetadata#map} + * + *

Clear the queue's metadata

+ * + * {@codesnippet com.azure.storage.queue.queueClient.clearMetadata#map} + * + * @param metadata Metadata to set on the queue + * @return A response that only contains headers and response status code + * @throws StorageErrorException If the queue doesn't exist + */ + public VoidResponse setMetadata(Map metadata) { + return client.setMetadata(metadata).block(); + } + + /** + * Retrieves stored access policies specified on the queue. + * + *

Code Samples

+ * + *

List the stored access policies

+ * + * {@codesnippet com.azure.storage.queue.queueClient.getAccessPolicy} + * + * @return The stored access policies specified on the queue. + * @throws StorageErrorException If the queue doesn't exist + */ + public Iterable getAccessPolicy() { + return client.getAccessPolicy().toIterable(); + } + + /** + * Sets stored access policies on the queue. + * + *

Code Samples

+ * + *

Set a read only stored access policy

+ * + * {@codesnippet com.azure.storage.queue.queueClient.setAccessPolicy} + * + * @param permissions Access policies to set on the queue + * @return A response that only contains headers and response status code + * @throws StorageErrorException If the queue doesn't exist, a stored access policy doesn't have all fields filled out, + * or the queue will have more than five policies. + */ + public VoidResponse setAccessPolicy(List permissions) { + return client.setAccessPolicy(permissions).block(); + } + + /** + * Deletes all messages in the queue. + * + *

Code Samples

+ * + *

Clear the messages

+ * + * {@codesnippet com.azure.storage.queue.queueClient.clearMessages} + * + * @return A response that only contains headers and response status code + * @throws StorageErrorException If the queue doesn't exist + */ + public VoidResponse clearMessages() { + return client.clearMessages().block(); + } + + /** + * Enqueues a message that has a time-to-live of 7 days and is instantly visible. + * + *

Code Samples

+ * + *

Enqueue a message of "Hello, Azure"

+ * + * {@codesnippet com.azure.storage.queue.queueClient.enqueueMessage#string} + * + * @param messageText Message text + * @return A {@link EnqueuedMessage} value that contains the {@link EnqueuedMessage#messageId() messageId} and + * {@link EnqueuedMessage#popReceipt() popReceipt} that are used to interact with the message and other metadata + * about the enqueued message. + * @throws StorageErrorException If the queue doesn't exist + */ + public Response enqueueMessage(String messageText) { + return enqueueMessage(messageText, Duration.ofSeconds(0), Duration.ofDays(7)); + } + + /** + * Enqueues a message with a given time-to-live and a timeout period where the message is invisible in the queue. + * + *

Code Samples

+ * + *

Add a message of "Hello, Azure" that has a timeout of 5 seconds

+ * + * {@codesnippet com.azure.storage.queue.queueClient.enqueueMessage#string-duration-duration} + * + *

Add a message of "Goodbye, Azure" that has a time to live of 5 seconds

+ * + * {@codesnippet com.azure.storage.queue.queueClient.enqueueMessageLiveTime#string-duration-duration} + * + * @param messageText Message text + * @param visibilityTimeout Optional. The timeout period for how long the message is invisible in the queue in seconds. + * If unset the value will default to 0 and the message will be instantly visible. The timeout must be between 0 + * seconds and 7 days. + * @param timeToLive Optional. How long the message will stay alive in the queue in seconds. If unset the value will + * default to 7 days, if -1 is passed the message will not expire. The time to live must be -1 or any positive number. + * @return A {@link EnqueuedMessage} value that contains the {@link EnqueuedMessage#messageId() messageId} and + * {@link EnqueuedMessage#popReceipt() popReceipt} that are used to interact with the message and other metadata + * about the enqueued message. + * @throws StorageErrorException If the queue doesn't exist or the {@code visibilityTimeout} or {@code timeToLive} + * are outside of the allowed limits. + */ + public Response enqueueMessage(String messageText, Duration visibilityTimeout, Duration timeToLive) { + return client.enqueueMessage(messageText, visibilityTimeout, timeToLive).block(); + } + + /** + * Retrieves the first message in the queue and hides it from other operations for 30 seconds. + * + *

Code Samples

+ * + *

Dequeue a message

+ * + * {@codesnippet com.azure.storage.queue.queueClient.dequeueMessages} + * + * @return The first {@link DequeuedMessage} in the queue, it contains + * {@link DequeuedMessage#messageId() messageId} and {@link DequeuedMessage#popReceipt() popReceipt} used to interact + * with the message, additionally it contains other metadata about the message. + * @throws StorageErrorException If the queue doesn't exist + */ + public Iterable dequeueMessages() { + return dequeueMessages(1, Duration.ofSeconds(30)); + } + + /** + * Retrieves up to the maximum number of messages from the queue and hides them from other operations for 30 seconds. + * + *

Code Samples

+ * + *

Dequeue up to 5 messages

+ * + * {@codesnippet com.azure.storage.queue.queueClient.dequeueMessages#integer} + * + * @param maxMessages Optional. Maximum number of messages to get, if there are less messages exist in the queue than requested + * all the messages will be returned. If left empty only 1 message will be retrieved, the allowed range is 1 to 32 + * messages. + * @return Up to {@code maxMessages} {@link DequeuedMessage DequeuedMessages} from the queue. Each DequeuedMessage contains + * {@link DequeuedMessage#messageId() messageId} and {@link DequeuedMessage#popReceipt() popReceipt} used to interact + * with the message and other metadata about the message. + * @throws StorageErrorException If the queue doesn't exist or {@code maxMessages} is outside of the allowed bounds + */ + public Iterable dequeueMessages(Integer maxMessages) { + return dequeueMessages(maxMessages, Duration.ofSeconds(30)); + } + + /** + * Retrieves up to the maximum number of messages from the queue and hides them from other operations for the + * timeout period. + * + *

Code Samples

+ * + *

Dequeue up to 5 messages and give them a 60 second timeout period

+ * + * {@codesnippet com.azure.storage.queue.queueClient.dequeueMessages#integer-duration} + * + * @param maxMessages Optional. Maximum number of messages to get, if there are less messages exist in the queue than requested + * all the messages will be returned. If left empty only 1 message will be retrieved, the allowed range is 1 to 32 + * messages. + * @param visibilityTimeout Optional. The timeout period for how long the message is invisible in the queue in seconds. + * If left empty the dequeued messages will be invisible for 30 seconds. The timeout must be between 1 second and 7 days. + * @return Up to {@code maxMessages} {@link DequeuedMessage DequeuedMessages} from the queue. Each DeqeuedMessage contains + * {@link DequeuedMessage#messageId() messageId} and {@link DequeuedMessage#popReceipt() popReceipt} used to interact + * with the message and other metadata about the message. + * @throws StorageErrorException If the queue doesn't exist or {@code maxMessages} or {@code visibilityTimeout} is + * outside of the allowed bounds + */ + public Iterable dequeueMessages(Integer maxMessages, Duration visibilityTimeout) { + return client.dequeueMessages(maxMessages, visibilityTimeout).toIterable(); + } + + /** + * Peeks the first message in the queue. + * + * Peeked messages don't contain the necessary information needed to interact with the message nor will it hide + * messages from other operations on the queue. + * + *

Code Samples

+ * + *

Peek the first message

+ * + * {@codesnippet com.azure.storage.queue.queueClient.peekMessages} + * + * @return A {@link PeekedMessage} that contains metadata about the message. + */ + public Iterable peekMessages() { + return peekMessages(null); + } + + /** + * Peek messages from the front of the queue up to the maximum number of messages. + * + * Peeked messages don't contain the necessary information needed to interact with the message nor will it hide + * messages from other operations on the queue. + * + *

Code Samples

+ * + *

Peek up to the first five messages

+ * + * {@codesnippet com.azure.storage.queue.queueClient.peekMessages#integer} + * + * @param maxMessages Optional. Maximum number of messages to peek, if there are less messages exist in the queue than requested + * all the messages will be peeked. If left empty only 1 message will be peeked, the allowed range is 1 to 32 + * messages. + * @return Up to {@code maxMessages} {@link PeekedMessage PeekedMessages} from the queue. Each PeekedMessage contains + * metadata about the message. + * @throws StorageErrorException If the queue doesn't exist or {@code maxMessages} is outside of the allowed bounds + */ + public Iterable peekMessages(Integer maxMessages) { + return client.peekMessages(maxMessages).toIterable(); + } + + /** + * Updates the specific message in the queue with a new message and resets the visibility timeout. + * + *

Code Samples

+ * + *

Dequeue the first message and update it to "Hello again, Azure" and hide it for 5 seconds

+ * + * {@codesnippet com.azure.storage.queue.queueClient.updateMessage} + * + * @param messageText Updated value for the message + * @param messageId Id of the message to update + * @param popReceipt Unique identifier that must match for the message to be updated + * @param visibilityTimeout The timeout period for how long the message is invisible in the queue in seconds. The + * timeout period must be between 1 second and 7 days. + * @return A {@link UpdatedMessage} that contains the new {@link UpdatedMessage#popReceipt() popReceipt} to interact + * with the message, additionally contains the updated metadata about the message. + * @throws StorageErrorException If the queue or messageId don't exist, the popReceipt doesn't match on the message, + * or the {@code visibilityTimeout} is outside the allowed bounds + */ + public Response updateMessage(String messageText, String messageId, String popReceipt, Duration visibilityTimeout) { + return client.updateMessage(messageText, messageId, popReceipt, visibilityTimeout).block(); + } + + /** + * Deletes the specified message in the queue + * + *

Code Samples

+ * + *

Delete the first message

+ * + * {@codesnippet com.azure.storage.queue.queueClient.deleteMessage} + * + * @param messageId Id of the message to deleted + * @param popReceipt Unique identifier that must match for the message to be deleted + * @return A response that only contains headers and response status code + * @throws StorageErrorException If the queue or messageId don't exist or the popReceipt doesn't match on the message + */ + public VoidResponse deleteMessage(String messageId, String popReceipt) { + return client.deleteMessage(messageId, popReceipt).block(); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/QueueClientBuilder.java b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueClientBuilder.java new file mode 100644 index 0000000000000..d272cfc1bbf89 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueClientBuilder.java @@ -0,0 +1,344 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue; + +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.policy.AddDatePolicy; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLoggingPolicy; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.RequestIdPolicy; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.implementation.http.policy.spi.HttpPolicyProviders; +import com.azure.core.implementation.util.ImplUtils; +import com.azure.core.util.configuration.Configuration; +import com.azure.core.util.configuration.ConfigurationManager; +import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.common.credentials.SASTokenCredential; +import com.azure.storage.common.credentials.SharedKeyCredential; +import com.azure.storage.common.policy.SASTokenCredentialPolicy; +import com.azure.storage.common.policy.SharedKeyCredentialPolicy; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Objects; + +/** + * This class provides a fluent builder API to help aid the configuration and instantiation of the {@link QueueClient QueueClients} + * and {@link QueueAsyncClient QueueAsyncClients}, calling {@link QueueClientBuilder#buildClient() buildClient} constructs an + * instance of QueueClient and calling {@link QueueClientBuilder#buildAsyncClient() buildAsyncClient} constructs an instance of + * QueueAsyncClient. + * + *

The client needs the endpoint of the Azure Storage Queue service, name of the queue, and authorization credentials. + * {@link QueueClientBuilder#endpoint(String) endpoint} gives the builder the endpoint and may give the builder the + * {@link QueueClientBuilder#queueName(String) queueName} and a {@link SASTokenCredential} that authorizes the client.

+ * + *

Instantiating a synchronous Queue Client with SAS token

+ * {@codesnippet com.azure.storage.queue.queueClient.instantiation.sastoken} + * + *

Instantiating an Asynchronous Queue Client with SAS token

+ * {@codesnippet com.azure.storage.queue.queueAsyncClient.instantiation.sastoken} + * + *

If the {@code endpoint} doesn't contain the queue name or {@code SASTokenCredential} they may be set using + * {@link QueueClientBuilder#queueName(String) queueName} and {@link QueueClientBuilder#credential(SASTokenCredential) credential}.

+ * + *

Instantiating a synchronous Queue Client with credential

+ * {@codesnippet com.azure.storage.queue.queueClient.instantiation.credential} + * + *

Instantiating an Asynchronous Queue Client with credential

+ * {@codesnippet com.azure.storage.queue.queueAsyncClient.instantiation.credential} + * + *

Another way to authenticate the client is using a {@link SharedKeyCredential}. To create a SharedKeyCredential + * a connection string from the Storage Queue service must be used. Set the SharedKeyCredential with + * {@link QueueClientBuilder#connectionString(String) connectionString}. If the builder has both a SASTokenCredential and + * SharedKeyCredential the SharedKeyCredential will be preferred when authorizing requests sent to the service.

+ * + *

Instantiating a synchronous Queue Client with connection string.

+ * {@codesnippet com.azure.storage.queue.queueClient.instantiation.connectionstring} + * + *

Instantiating an Asynchronous Queue Client with connection string.

+ * {@codesnippet com.azure.storage.queue.queueAsyncClient.instantiation.connectionstring} + * + * @see QueueClient + * @see QueueAsyncClient + * @see SASTokenCredential + * @see SharedKeyCredential + */ +public final class QueueClientBuilder { + private static final ClientLogger LOGGER = new ClientLogger(QueueClientBuilder.class); + private static final String ACCOUNT_NAME = "accountname"; + private final List policies; + + private URL endpoint; + private String queueName; + private SASTokenCredential sasTokenCredential; + private SharedKeyCredential sharedKeyCredential; + private HttpClient httpClient; + private HttpPipeline pipeline; + private HttpLogDetailLevel logLevel; + private RetryPolicy retryPolicy; + private Configuration configuration; + + /** + * Creates a builder instance that is able to configure and construct {@link QueueClient QueueClients} + * and {@link QueueAsyncClient QueueAsyncClients}. + */ + public QueueClientBuilder() { + retryPolicy = new RetryPolicy(); + logLevel = HttpLogDetailLevel.NONE; + policies = new ArrayList<>(); + + configuration = ConfigurationManager.getConfiguration(); + } + + /** + * Creates a {@link QueueClient} based on options set in the builder. Every time {@code buildClient()} is + * called a new instance of {@link QueueClient} is created. + * + *

+ * If {@link QueueClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline}, + * {@link QueueClientBuilder#endpoint(String) endpoint}, and + * {@link QueueClientBuilder#queueName(String) queueName} are used to create the {@link QueueAsyncClient client}. + * All other builder settings are ignored. + *

+ * + * @return A QueueClient with the options set from the builder. + * @throws NullPointerException If {@code endpoint} or {@code queueName} have not been set. + * @throws IllegalStateException If neither a {@link SharedKeyCredential} or {@link SASTokenCredential} has been set. + */ + public QueueClient buildClient() { + return new QueueClient(buildAsyncClient()); + } + + /** + * Creates a {@link QueueAsyncClient} based on options set in the builder. Every time {@code buildAsyncClient()} is + * called a new instance of {@link QueueAsyncClient} is created. + * + *

+ * If {@link QueueClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline}, + * {@link QueueClientBuilder#endpoint(String) endpoint}, and + * {@link QueueClientBuilder#queueName(String) queueName} are used to create the {@link QueueAsyncClient client}. + * All other builder settings are ignored. + *

+ * + * @return A QueueAsyncClient with the options set from the builder. + * @throws NullPointerException If {@code endpoint} or {@code queueName} have not been set. + * @throws IllegalArgumentException If neither a {@link SharedKeyCredential} or {@link SASTokenCredential} has been set. + */ + public QueueAsyncClient buildAsyncClient() { + Objects.requireNonNull(endpoint); + Objects.requireNonNull(queueName); + + if (sasTokenCredential == null && sharedKeyCredential == null) { + LOGGER.asError().log("Credentials are required for authorization"); + throw new IllegalArgumentException("Credentials are required for authorization"); + } + + if (pipeline != null) { + return new QueueAsyncClient(endpoint, pipeline, queueName); + } + // Closest to API goes first, closest to wire goes last. + final List policies = new ArrayList<>(); + + policies.add(new UserAgentPolicy(QueueConfiguration.NAME, QueueConfiguration.VERSION, configuration)); + policies.add(new RequestIdPolicy()); + policies.add(new AddDatePolicy()); + + if (sharedKeyCredential != null) { + policies.add(new SharedKeyCredentialPolicy(sharedKeyCredential)); + } else { + policies.add(new SASTokenCredentialPolicy(sasTokenCredential)); + } + + HttpPolicyProviders.addBeforeRetryPolicies(policies); + + policies.add(retryPolicy); + + policies.addAll(this.policies); + HttpPolicyProviders.addAfterRetryPolicies(policies); + policies.add(new HttpLoggingPolicy(logLevel)); + + HttpPipeline pipeline = HttpPipeline.builder() + .policies(policies.toArray(new HttpPipelinePolicy[0])) + .httpClient(httpClient) + .build(); + + return new QueueAsyncClient(endpoint, pipeline, queueName); + } + + /** + * Sets the endpoint for the Azure Storage Queue instance that the client will interact with. + * + *

The first path segment, if the endpoint contains path segments, will be assumed to be the name of the queue + * that the client will interact with.

+ * + *

Query parameters of the endpoint will be parsed using {@link SASTokenCredential#fromQuery(String) fromQuery} in an + * attempt to generate a {@link SASTokenCredential} to authenticate requests sent to the service.

+ * + * @param endpoint The URL of the Azure Storage Queue instance to send service requests to and receive responses from. + * @return the updated QueueClientBuilder object + * @throws IllegalArgumentException If {@code endpoint} isn't a proper URL + */ + public QueueClientBuilder endpoint(String endpoint) { + Objects.requireNonNull(endpoint); + try { + URL fullURL = new URL(endpoint); + this.endpoint = new URL(fullURL.getProtocol() + "://" + fullURL.getHost()); + + // Attempt to get the queue name from the URL passed + String[] pathSegments = fullURL.getPath().split("/", 2); + if (pathSegments.length == 2 && !ImplUtils.isNullOrEmpty(pathSegments[1])) { + this.queueName = pathSegments[1]; + } + + // Attempt to get the SAS token from the URL passed + SASTokenCredential credential = SASTokenCredential.fromQuery(fullURL.getQuery()); + if (credential != null) { + this.sasTokenCredential = credential; + } + } catch (MalformedURLException ex) { + LOGGER.asError().log("The Azure Storage Queue endpoint url is malformed. Endpoint: " + endpoint); + throw new IllegalArgumentException("The Azure Storage Queue endpoint url is malformed. Endpoint: " + endpoint); + } + + return this; + } + + /** + * Sets the name of the queue that the client will interact with. + * + * @param queueName Name of the queue + * @return the updated QueueClientBuilder object + * @throws NullPointerException If {@code queueName} is {@code null}. + */ + public QueueClientBuilder queueName(String queueName) { + this.queueName = Objects.requireNonNull(queueName); + return this; + } + + /** + * Sets the {@link SASTokenCredential} used to authenticate requests sent to the Queue. + * + * @param credential SAS token credential generated from the Storage account that authorizes requests + * @return the updated QueueClientBuilder object + * @throws NullPointerException If {@code credential} is {@code null}. + */ + public QueueClientBuilder credential(SASTokenCredential credential) { + this.sasTokenCredential = Objects.requireNonNull(credential); + return this; + } + + /** + * Sets the {@link SharedKeyCredential} used to authenticate requests sent to the Queue. + * + * @param credential Shared key credential can retrieve from the Storage account that authorizes requests + * @return the updated QueueServiceClientBuilder object + * @throws NullPointerException If {@code credential} is {@code null}. + */ + public QueueClientBuilder credential(SharedKeyCredential credential) { + this.sharedKeyCredential = Objects.requireNonNull(credential); + return this; + } + + /** + * Creates a {@link SharedKeyCredential} from the {@code connectionString} used to authenticate requests sent to the + * Queue service. + * + * @param connectionString Connection string from the Access Keys section in the Storage account + * @return the updated QueueClientBuilder object + * @throws NullPointerException If {@code connectionString} is {@code null}. + */ + public QueueClientBuilder connectionString(String connectionString) { + Objects.requireNonNull(connectionString); + this.sharedKeyCredential = SharedKeyCredential.fromConnectionString(connectionString); + getEndPointFromConnectionString(connectionString); + return this; + } + + private void getEndPointFromConnectionString(String connectionString) { + HashMap connectionStringPieces = new HashMap<>(); + for (String connectionStringPiece : connectionString.split(";")) { + String[] kvp = connectionStringPiece.split("=", 2); + connectionStringPieces.put(kvp[0].toLowerCase(Locale.ROOT), kvp[1]); + } + String accountName = connectionStringPieces.get(ACCOUNT_NAME); + try { + this.endpoint = new URL(String.format("https://%s.queue.core.windows.net", accountName)); + } catch (MalformedURLException e) { + LOGGER.asError().log("There is no valid account for the connection string. " + + "Connection String: %s", connectionString); + throw new IllegalArgumentException(String.format("There is no valid account for the connection string. " + + "Connection String: %s", connectionString)); + } + } + /** + * Sets the HTTP client to use for sending and receiving requests to and from the service. + * + * @param httpClient The HTTP client to use for requests. + * @return The updated QueueClientBuilder object. + * @throws NullPointerException If {@code httpClient} is {@code null}. + */ + public QueueClientBuilder httpClient(HttpClient httpClient) { + this.httpClient = Objects.requireNonNull(httpClient); + return this; + } + + /** + * Adds a policy to the set of existing policies that are executed after the {@link RetryPolicy}. + * + * @param pipelinePolicy The retry policy for service requests. + * @return The updated QueueClientBuilder object. + * @throws NullPointerException If {@code pipelinePolicy} is {@code null}. + */ + public QueueClientBuilder addPolicy(HttpPipelinePolicy pipelinePolicy) { + Objects.requireNonNull(pipelinePolicy); + this.policies.add(pipelinePolicy); + return this; + } + + /** + * Sets the logging level for HTTP requests and responses. + * + * @param logLevel The amount of logging output when sending and receiving HTTP requests/responses. + * @return The updated QueueClientBuilder object. + */ + public QueueClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { + this.logLevel = logLevel; + return this; + } + + /** + * Sets the HTTP pipeline to use for the service client. + * + * If {@code pipeline} is set, all other settings are ignored, aside from {@link QueueClientBuilder#endpoint(String) endpoint} + * and {@link QueueClientBuilder#queueName(String) queueName} when building clients. + * + * @param pipeline The HTTP pipeline to use for sending service requests and receiving responses. + * @return The updated QueueClientBuilder object. + * @throws NullPointerException If {@code pipeline} is {@code null}. + */ + public QueueClientBuilder pipeline(HttpPipeline pipeline) { + Objects.requireNonNull(pipeline); + this.pipeline = pipeline; + return this; + } + + /** + * Sets the configuration store that is used during construction of the service client. + * + * The default configuration store is a clone of the {@link ConfigurationManager#getConfiguration() global + * configuration store}, use {@link Configuration#NONE} to bypass using configuration settings during construction. + * + * @param configuration The configuration store used to + * @return The updated QueueClientBuilder object. + */ + public QueueClientBuilder configuration(Configuration configuration) { + this.configuration = configuration; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/QueueConfiguration.java b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueConfiguration.java new file mode 100644 index 0000000000000..7a794525484f7 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueConfiguration.java @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue; + +/* + * Gets the SDK information for this library component. + */ +class QueueConfiguration { + //TODO: Eventually remove these hardcoded strings with https://github.com/Azure/azure-sdk-for-java/issues/3141 + static final String NAME = "azure-storage-queue"; + static final String VERSION = "12.0.0-preview.1"; +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/QueueServiceAsyncClient.java b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueServiceAsyncClient.java new file mode 100644 index 0000000000000..e093f1d34b171 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueServiceAsyncClient.java @@ -0,0 +1,301 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue; + +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.http.rest.VoidResponse; +import com.azure.core.util.Context; +import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.common.credentials.SASTokenCredential; +import com.azure.storage.common.credentials.SharedKeyCredential; +import com.azure.storage.queue.implementation.AzureQueueStorageBuilder; +import com.azure.storage.queue.implementation.AzureQueueStorageImpl; +import com.azure.storage.queue.models.CorsRule; +import com.azure.storage.queue.models.ListQueuesIncludeType; +import com.azure.storage.queue.models.ListQueuesSegmentResponse; +import com.azure.storage.queue.models.QueueItem; +import com.azure.storage.queue.models.QueuesSegmentOptions; +import com.azure.storage.queue.models.ServicesListQueuesSegmentResponse; +import com.azure.storage.queue.models.StorageErrorException; +import com.azure.storage.queue.models.StorageServiceProperties; +import com.azure.storage.queue.models.StorageServiceStats; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +/** + * This class provides a client that contains all the operations for interacting with a queue account in Azure Storage. + * Operations allowed by the client are creating, listing, and deleting queues, retrieving and updating properties of the account, + * and retrieving statistics of the account. + * + *

Instantiating an Asynchronous Queue Service Client

+ * + * {@codesnippet com.azure.storage.queue.queueServiceAsyncClient.instantiation} + * + *

View {@link QueueServiceClientBuilder this} for additional ways to construct the client.

+ * + * @see QueueServiceClientBuilder + * @see QueueServiceClient + * @see SharedKeyCredential + * @see SASTokenCredential + */ +public final class QueueServiceAsyncClient { + private static final ClientLogger LOGGER = new ClientLogger(QueueServiceAsyncClient.class); + private final AzureQueueStorageImpl client; + + /** + * Creates a QueueServiceAsyncClient that sends requests to the storage account at {@code endpoint}. + * Each service call goes through the {@code httpPipeline}. + * + * @param endpoint URL for the Storage Queue service + * @param httpPipeline HttpPipeline that the HTTP requests and response flow through + */ + QueueServiceAsyncClient(URL endpoint, HttpPipeline httpPipeline) { + this.client = new AzureQueueStorageBuilder().pipeline(httpPipeline) + .url(endpoint.toString()) + .build(); + } + + /** + * @return the URL of the storage queue + * @throws RuntimeException If the queue service is using a malformed URL. + */ + public URL getQueueServiceUrl() { + try { + return new URL(client.url()); + } catch (MalformedURLException ex) { + LOGGER.asError().log("Queue Service URL is malformed"); + throw new RuntimeException("Storage account URL is malformed"); + } + } + + /** + * Constructs a QueueAsyncClient that interacts with the specified queue. + * + * This will not create the queue in the storage account if it doesn't exist. + * + * @param queueName Name of the queue + * @return QueueAsyncClient that interacts with the specified queue + */ + public QueueAsyncClient getQueueAsyncClient(String queueName) { + return new QueueAsyncClient(client, queueName); + } + + /** + * Creates a queue in the storage account with the specified name and returns a QueueAsyncClient to interact + * with it. + * + *

Code Samples

+ * + *

Create the queue "test"

+ * + * {@codesnippet com.azure.storage.queue.queueServiceAsyncClient.createQueue#string} + * + * @param queueName Name of the queue + * @return A response containing the QueueAsyncClient and the status of creating the queue + * @throws StorageErrorException If a queue with the same name and different metadata already exists + */ + public Mono> createQueue(String queueName) { + return createQueue(queueName, null); + } + + /** + * Creates a queue in the storage account with the specified name and metadata and returns a QueueAsyncClient to + * interact with it. + * + *

Code Samples

+ * + *

Create the queue "test" with metadata "queue:metadata"

+ * + * {@codesnippet com.azure.storage.queue.queueServiceAsyncClient.createQueue#string-map} + * + * @param queueName Name of the queue + * @param metadata Metadata to associate with the queue + * @return A response containing the QueueAsyncClient and the status of creating the queue + * @throws StorageErrorException If a queue with the same name and different metadata already exists + */ + public Mono> createQueue(String queueName, Map metadata) { + QueueAsyncClient queueAsyncClient = new QueueAsyncClient(client, queueName); + + return queueAsyncClient.create(metadata) + .map(response -> new SimpleResponse<>(response, queueAsyncClient)); + } + + /** + * Deletes a queue in the storage account + * + *

Code Samples

+ * + *

Delete the queue "test"

+ * + * {@codesnippet com.azure.storage.queue.queueServiceAsyncClient.deleteQueue#string} + * + * @param queueName Name of the queue + * @return A response that only contains headers and response status code + * @throws StorageErrorException If the queue doesn't exist + */ + public Mono deleteQueue(String queueName) { + return new QueueAsyncClient(client, queueName).delete(); + } + + /** + * Lists all queues in the storage account without their metadata. + * + *

Code Samples

+ * + *

List all queues in the account

+ * + * {@codesnippet com.azure.storage.queue.queueServiceAsyncClient.listQueues} + * + * @return {@link QueueItem Queues} in the storage account + */ + public Flux listQueues() { + return listQueues(null, null); + } + + /** + * Lists the queues in the storage account that pass the filter. + * + * Pass true to {@link QueuesSegmentOptions#includeMetadata(boolean) includeMetadata} to have metadata returned for + * the queues. + * + *

Code Samples

+ * + *

List all queues that begin with "azure"

+ * + * {@codesnippet com.azure.storage.queue.queueServiceClient.listQueues#queueSergmentOptions} + * + * @param options Options for listing queues + * @return {@link QueueItem Queues} in the storage account that satisfy the filter requirements + */ + public Flux listQueues(QueuesSegmentOptions options) { + return listQueues(null, options); + } + + /** + * Lists the queues in the storage account that pass the filter starting at the specified marker. + * + * Pass true to {@link QueuesSegmentOptions#includeMetadata(boolean) includeMetadata} to have metadata returned for + * the queues. + * + * @param marker Starting point to list the queues + * @param options Options for listing queues + * @return {@link QueueItem Queues} in the storage account that satisfy the filter requirements + */ + Flux listQueues(String marker, QueuesSegmentOptions options) { + String prefix = null; + Integer maxResults = null; + final List include = new ArrayList<>(); + + if (options != null) { + prefix = options.prefix(); + maxResults = options.maxResults(); + if (options.includeMetadata()) { + include.add(ListQueuesIncludeType.fromString(ListQueuesIncludeType.METADATA.toString())); + } + } + + Mono result = client.services() + .listQueuesSegmentWithRestResponseAsync(prefix, marker, maxResults, include, null, null, Context.NONE); + + return result.flatMapMany(response -> extractAndFetchQueues(response, include, Context.NONE)); + } + + /* + * Helper function used to auto-enumerate through paged responses + */ + private Flux listQueues(ServicesListQueuesSegmentResponse response, List include, Context context) { + ListQueuesSegmentResponse value = response.value(); + Mono result = client.services() + .listQueuesSegmentWithRestResponseAsync(value.prefix(), value.marker(), value.maxResults(), include, null, null, context); + + return result.flatMapMany(r -> extractAndFetchQueues(r, include, context)); + } + + /* + * Helper function used to auto-enumerate though paged responses + */ + private Flux extractAndFetchQueues(ServicesListQueuesSegmentResponse response, List include, Context context) { + String nextPageLink = response.value().nextMarker(); + if (nextPageLink == null) { + return Flux.fromIterable(response.value().queueItems()); + } + + return Flux.fromIterable(response.value().queueItems()).concatWith(listQueues(response, include, context)); + } + + /** + * Retrieves the properties of the storage account's Queue service. The properties range from storage analytics and + * metric to CORS (Cross-Origin Resource Sharing). + * + *

Code Samples

+ * + *

Retrieve Queue service properties

+ * + * {@codesnippet com.azure.storage.queue.queueServiceAsyncClient.getProperties} + * + * @return Storage account Queue service properties + */ + public Mono> getProperties() { + return client.services().getPropertiesWithRestResponseAsync(Context.NONE) + .map(response -> new SimpleResponse<>(response, response.value())); + } + + /** + * Sets the properties for the storage account's Queue service. The properties range from storage analytics and + * metric to CORS (Cross-Origin Resource Sharing). + * + * To maintain the CORS in the Queue service pass a {@code null} value for {@link StorageServiceProperties#cors() CORS}. + * To disable all CORS in the Queue service pass an empty list for {@link StorageServiceProperties#cors() CORS}. + * + *

Code Sample

+ * + *

Clear CORS in the Queue service

+ * + * {@codesnippet com.azure.storage.queue.queueServiceAsyncClient.setProperties#storageServiceProperties} + * + *

Enable Minute and Hour Metrics

+ * + * {@codesnippet com.azure.storage.queue.queueServiceAsyncClient.setPropertiesEnableMetrics#storageServiceProperties} + * + * @param properties Storage account Queue service properties + * @return A response that only contains headers and response status code + * @throws StorageErrorException When one of the following is true + *
    + *
  • A CORS rule is missing one of its fields
  • + *
  • More than five CORS rules will exist for the Queue service
  • + *
  • Size of all CORS rules exceeds 2KB
  • + *
  • + * Length of {@link CorsRule#allowedHeaders() allowed headers}, {@link CorsRule#exposedHeaders() exposed headers}, + * or {@link CorsRule#allowedOrigins() allowed origins} exceeds 256 characters. + *
  • + *
  • {@link CorsRule#allowedMethods() Allowed methods} isn't DELETE, GET, HEAD, MERGE, POST, OPTIONS, or PUT
  • + *
+ */ + public Mono setProperties(StorageServiceProperties properties) { + return client.services().setPropertiesWithRestResponseAsync(properties, Context.NONE) + .map(VoidResponse::new); + } + + /** + * Retrieves the geo replication information about the Queue service. + * + *

Code Samples

+ * + *

Retrieve the geo replication information

+ * + * {@codesnippet com.azure.storage.queue.queueServiceAsyncClient.getStatistics} + * + * @return The geo replication information about the Queue service + */ + public Mono> getStatistics() { + return client.services().getStatisticsWithRestResponseAsync(Context.NONE) + .map(response -> new SimpleResponse<>(response, response.value())); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/QueueServiceClient.java b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueServiceClient.java new file mode 100644 index 0000000000000..a002e5b12f872 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueServiceClient.java @@ -0,0 +1,234 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.common.credentials.SASTokenCredential; +import com.azure.storage.common.credentials.SharedKeyCredential; +import com.azure.storage.queue.models.CorsRule; +import com.azure.storage.queue.models.QueueItem; +import com.azure.storage.queue.models.QueuesSegmentOptions; +import com.azure.storage.queue.models.StorageErrorException; +import com.azure.storage.queue.models.StorageServiceProperties; +import com.azure.storage.queue.models.StorageServiceStats; +import java.net.URL; +import java.util.Map; + +/** + * This class provides a client that contains all the operations for interacting with a queue account in Azure Storage. + * Operations allowed by the client are creating, listing, and deleting queues, retrieving and updating properties of the account, + * and retrieving statistics of the account. + * + *

Instantiating an Synchronous Queue Service Client

+ * + * {@codesnippet com.azure.storage.queue.queueServiceClient.instantiation} + * + *

View {@link QueueServiceClientBuilder this} for additional ways to construct the client.

+ * + * @see QueueServiceClientBuilder + * @see QueueServiceAsyncClient + * @see SharedKeyCredential + * @see SASTokenCredential + */ +public final class QueueServiceClient { + private final QueueServiceAsyncClient client; + + /** + * Creates a QueueServiceClient that wraps a QueueServiceAsyncClient and blocks requests. + * + * @param client QueueServiceAsyncClient that is used to send requests + */ + QueueServiceClient(QueueServiceAsyncClient client) { + this.client = client; + } + + /** + * @return the URL of the storage queue + */ + public URL getQueueServiceUrl() { + return client.getQueueServiceUrl(); + } + + /** + * Constructs a QueueClient that interacts with the specified queue. + * + * This will not create the queue in the storage account if it doesn't exist. + * + * @param queueName Name of the queue + * @return QueueClient that interacts with the specified queue + */ + public QueueClient getQueueClient(String queueName) { + return new QueueClient(client.getQueueAsyncClient(queueName)); + } + + /** + * Creates a queue in the storage account with the specified name and returns a QueueClient to interact with it. + * + *

Code Samples

+ * + *

Create the queue "test"

+ * + * {@codesnippet com.azure.storage.queue.queueServiceClient.createQueue#string} + * + * @param queueName Name of the queue + * @return A response containing the QueueClient and the status of creating the queue + * @throws StorageErrorException If a queue with the same name and different metadata already exists + */ + public Response createQueue(String queueName) { + return createQueue(queueName, null); + } + + /** + * Creates a queue in the storage account with the specified name and metadata and returns a QueueClient to + * interact with it. + * + *

Code Samples

+ * + *

Create the queue "test" with metadata "queue:metadata"

+ * + * {@codesnippet com.azure.storage.queue.queueServiceClient.createQueue#string-map} + * + * @param queueName Name of the queue + * @param metadata Metadata to associate with the queue + * @return A response containing the QueueClient and the status of creating the queue + * @throws StorageErrorException If a queue with the same name and different metadata already exists + */ + public Response createQueue(String queueName, Map metadata) { + Response response = client.createQueue(queueName, metadata).block(); + + return new SimpleResponse<>(response, new QueueClient(response.value())); + } + + /** + * Deletes a queue in the storage account + * + *

Code Samples

+ * + *

Delete the queue "test"

+ * + * {@codesnippet com.azure.storage.queue.queueServiceClient.deleteQueue#string} + * + * @param queueName Name of the queue + * @return A response containing the status of deleting the queue + * @throws StorageErrorException If the queue doesn't exist + */ + public VoidResponse deleteQueue(String queueName) { + return client.deleteQueue(queueName).block(); + } + + /** + * Lists all queues in the storage account without their metadata. + * + *

Code Samples

+ * + *

List all queues in the account

+ * + * {@codesnippet com.azure.storage.queue.queueServiceClient.listQueues} + * + * @return {@link QueueItem Queues} in the storage account + */ + public Iterable listQueues() { + return listQueues(null, null); + } + + /** + * Lists the queues in the storage account that pass the filter. + * + * Pass true to {@link QueuesSegmentOptions#includeMetadata(boolean) includeMetadata} to have metadata returned for + * the queues. + * + *

Code Samples

+ * + *

List all queues that begin with "azure"

+ * + * {@codesnippet com.azure.storage.queue.queueServiceClient.listQueues#queueSergmentOptions} + * + * @param options Options for listing queues + * @return {@link QueueItem Queues} in the storage account that satisfy the filter requirements + */ + public Iterable listQueues(QueuesSegmentOptions options) { + return listQueues(null, options); + } + + /** + * Lists the queues in the storage account that pass the filter starting at the specified marker. + * + * Pass true to {@link QueuesSegmentOptions#includeMetadata(boolean) includeMetadata} to have metadata returned for + * the queues. + * + * @param marker Starting point to list the queues + * @param options Options for listing queues + * @return {@link QueueItem Queues} in the storage account that satisfy the filter requirements + */ + Iterable listQueues(String marker, QueuesSegmentOptions options) { + return client.listQueues(marker, options).toIterable(); + } + + /** + * Retrieves the properties of the storage account's Queue service. The properties range from storage analytics and + * metric to CORS (Cross-Origin Resource Sharing). + * + *

Code Samples

+ * + *

Retrieve Queue service properties

+ * + * {@codesnippet com.azure.storage.queue.queueServiceClient.getProperties} + * + * @return Storage account Queue service properties + */ + public Response getProperties() { + return client.getProperties().block(); + } + + /** + * Sets the properties for the storage account's Queue service. The properties range from storage analytics and + * metric to CORS (Cross-Origin Resource Sharing). + * + * To maintain the CORS in the Queue service pass a {@code null} value for {@link StorageServiceProperties#cors() CORS}. + * To disable all CORS in the Queue service pass an empty list for {@link StorageServiceProperties#cors() CORS}. + * + *

Code Sample

+ * + *

Clear CORS in the Queue service

+ * + * {@codesnippet com.azure.storage.queue.queueServiceClient.setProperties#storageServiceProperties} + * + *

Enable Minute and Hour Metrics

+ * + * {@codesnippet com.azure.storage.queue.queueServiceClient.setPropertiesEnableMetrics#storageServiceProperties} + * + * @param properties Storage account Queue service properties + * @return A response that only contains headers and response status code + * @throws StorageErrorException When one of the following is true + *
    + *
  • A CORS rule is missing one of its fields
  • + *
  • More than five CORS rules will exist for the Queue service
  • + *
  • Size of all CORS rules exceeds 2KB
  • + *
  • + * Length of {@link CorsRule#allowedHeaders() allowed headers}, {@link CorsRule#exposedHeaders() exposed headers}, + * or {@link CorsRule#allowedOrigins() allowed origins} exceeds 256 characters. + *
  • + *
  • {@link CorsRule#allowedMethods() Allowed methods} isn't DELETE, GET, HEAD, MERGE, POST, OPTIONS, or PUT
  • + *
+ */ + public VoidResponse setProperties(StorageServiceProperties properties) { + return client.setProperties(properties).block(); + } + + /** + * Retrieves the geo replication information about the Queue service. + * + *

Code Samples

+ * + *

Retrieve the geo replication information

+ * + * {@codesnippet com.azure.storage.queue.queueServiceClient.getStatistics} + * + * @return The geo replication information about the Queue service + */ + public Response getStatistics() { + return client.getStatistics().block(); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/QueueServiceClientBuilder.java b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueServiceClientBuilder.java new file mode 100644 index 0000000000000..63b191256f5dd --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueServiceClientBuilder.java @@ -0,0 +1,301 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue; + +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.policy.AddDatePolicy; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLoggingPolicy; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.RequestIdPolicy; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.implementation.http.policy.spi.HttpPolicyProviders; +import com.azure.core.util.configuration.Configuration; +import com.azure.core.util.configuration.ConfigurationManager; +import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.common.credentials.SASTokenCredential; +import com.azure.storage.common.credentials.SharedKeyCredential; +import com.azure.storage.common.policy.SASTokenCredentialPolicy; +import com.azure.storage.common.policy.SharedKeyCredentialPolicy; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * This class provides a fluent builder API to help aid the configuration and instantiation of the {@link QueueServiceClient queueServiceClients} + * and {@link QueueServiceAsyncClient queueServiceAsyncClients}, calling {@link QueueServiceClientBuilder#buildClient() buildClient} + * constructs an instance of QueueServiceClient and calling {@link QueueServiceClientBuilder#buildAsyncClient() buildAsyncClient} + * constructs an instance of QueueServiceAsyncClient. + * + *

The client needs the endpoint of the Azure Storage Queue service, name of the share, and authorization credential. + * {@link QueueServiceClientBuilder#endpoint(String) endpoint} gives the builder the endpoint and may give the builder the + * A {@link SASTokenCredential} that authorizes the client.

+ * + *

Instantiating a synchronous Queue Service Client with SAS token

+ * {@codesnippet com.azure.storage.queue.queueServiceClient.instantiation.sastoken} + * + *

Instantiating an Asynchronous Queue Service Client with SAS token

+ * {@codesnippet com.azure.storage.queue.queueServiceAsyncClient.instantiation.sastoken} + * + *

If the {@code endpoint} doesn't contain {@code SASTokenCredential} they may be set using + * {@link QueueClientBuilder#credential(SASTokenCredential) credential}.

+ * + *

Instantiating a synchronous Queue Service Client with SAS token

+ * {@codesnippet com.azure.storage.queue.queueServiceAsyncClient.instantiation.credential} + * + *

Instantiating an Asynchronous Queue Service Client with SAS token

+ * {@codesnippet com.azure.storage.queue.queueServiceAsyncClient.instantiation.credential} + * + *

If the {@code endpoint} doesn't contain the query parameters to construct a {@code SASTokenCredential} they may + * be set using {@link QueueServiceClientBuilder#credential(SASTokenCredential) credential}.

+ * + *

Another way to authenticate the client is using a {@link SharedKeyCredential}. To create a SharedKeyCredential + * a connection string from the Storage Queue service must be used. Set the SharedKeyCredential with + * {@link QueueServiceClientBuilder#connectionString(String) connectionString}. If the builder has both a SASTokenCredential and + * SharedKeyCredential the SharedKeyCredential will be preferred when authorizing requests sent to the service.

+ * + *

Instantiating a synchronous Queue Service Client with connection string.

+ * {@codesnippet com.azure.storage.queue.queueServiceClient.instantiation.connectionstring} + * + *

Instantiating an Asynchronous Queue Service Client with connection string.

+ * {@codesnippet com.azure.storage.queue.queueServiceAsyncClient.instantiation.connectionstring} + * + * @see QueueServiceClient + * @see QueueServiceAsyncClient + * @see SASTokenCredential + * @see SharedKeyCredential + */ +public final class QueueServiceClientBuilder { + private static final ClientLogger LOGGER = new ClientLogger(QueueServiceClientBuilder.class); + private final List policies; + + private URL endpoint; + private SASTokenCredential sasTokenCredential; + private SharedKeyCredential sharedKeyCredential; + private HttpClient httpClient; + private HttpPipeline pipeline; + private HttpLogDetailLevel logLevel; + private RetryPolicy retryPolicy; + private Configuration configuration; + + /** + * Creates a builder instance that is able to configure and construct {@link QueueServiceClient QueueServiceClients} + * and {@link QueueServiceAsyncClient QueueServiceAsyncClients}. + */ + public QueueServiceClientBuilder() { + retryPolicy = new RetryPolicy(); + logLevel = HttpLogDetailLevel.NONE; + policies = new ArrayList<>(); + configuration = ConfigurationManager.getConfiguration(); + } + + /** + * Creates a {@link QueueServiceAsyncClient} based on options set in the builder. Every time {@code buildAsyncClient()} is + * called a new instance of {@link QueueServiceAsyncClient} is created. + * + *

+ * If {@link QueueServiceClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline} and + * {@link QueueServiceClientBuilder#endpoint(String) endpoint} are used to create the + * {@link QueueServiceAsyncClient client}. All other builder settings are ignored. + *

+ * + * @return A QueueServiceAsyncClient with the options set from the builder. + * @throws NullPointerException If {@code endpoint} or {@code queueName} have not been set. + * @throws IllegalArgumentException If neither a {@link SharedKeyCredential} or {@link SASTokenCredential} has been set. + */ + public QueueServiceAsyncClient buildAsyncClient() { + Objects.requireNonNull(endpoint); + + if (sasTokenCredential == null && sharedKeyCredential == null) { + LOGGER.asError().log("Credentials are required for authorization"); + throw new IllegalArgumentException("Credentials are required for authorization"); + } + + if (pipeline != null) { + return new QueueServiceAsyncClient(endpoint, pipeline); + } + // Closest to API goes first, closest to wire goes last. + final List policies = new ArrayList<>(); + + policies.add(new UserAgentPolicy(QueueConfiguration.NAME, QueueConfiguration.VERSION, configuration)); + policies.add(new RequestIdPolicy()); + policies.add(new AddDatePolicy()); + + if (sharedKeyCredential != null) { + policies.add(new SharedKeyCredentialPolicy(sharedKeyCredential)); + } else { + policies.add(new SASTokenCredentialPolicy(sasTokenCredential)); + } + + HttpPolicyProviders.addBeforeRetryPolicies(policies); + + policies.add(retryPolicy); + + policies.addAll(this.policies); + HttpPolicyProviders.addAfterRetryPolicies(policies); + policies.add(new HttpLoggingPolicy(logLevel)); + + HttpPipeline pipeline = HttpPipeline.builder() + .policies(policies.toArray(new HttpPipelinePolicy[0])) + .httpClient(httpClient) + .build(); + + return new QueueServiceAsyncClient(endpoint, pipeline); + } + + /** + * Creates a {@link QueueServiceClient} based on options set in the builder. Every time {@code buildClient()} is + * called a new instance of {@link QueueServiceClient} is created. + * + *

+ * If {@link QueueServiceClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline} and + * {@link QueueServiceClientBuilder#endpoint(String) endpoint} are used to create the + * {@link QueueServiceClient client}. All other builder settings are ignored. + *

+ * + * @return A QueueServiceClient with the options set from the builder. + * @throws NullPointerException If {@code endpoint} or {@code queueName} have not been set. + * @throws IllegalStateException If neither a {@link SharedKeyCredential} or {@link SASTokenCredential} has been set. + */ + public QueueServiceClient buildClient() { + return new QueueServiceClient(buildAsyncClient()); + } + + + /** + * Sets the endpoint for the Azure Storage Queue instance that the client will interact with. + * + *

Query parameters of the endpoint will be parsed using {@link SASTokenCredential#fromQuery(String) fromQuery} in an + * attempt to generate a {@link SASTokenCredential} to authenticate requests sent to the service.

+ * + * @param endpoint The URL of the Azure Storage Queue instance to send service requests to and receive responses from. + * @return the updated QueueServiceClientBuilder object + * @throws IllegalArgumentException If {@code endpoint} isn't a proper URL + */ + public QueueServiceClientBuilder endpoint(String endpoint) { + Objects.requireNonNull(endpoint); + try { + URL fullURL = new URL(endpoint); + this.endpoint = new URL(fullURL.getProtocol() + "://" + fullURL.getHost()); + + // Attempt to get the SAS token from the URL passed + SASTokenCredential credential = SASTokenCredential.fromQuery(fullURL.getQuery()); + if (credential != null) { + this.sasTokenCredential = credential; + } + } catch (MalformedURLException ex) { + LOGGER.asError().log("The Azure Storage Queue endpoint url is malformed."); + throw new IllegalArgumentException("The Azure Storage Queue endpoint url is malformed."); + } + + return this; + } + + /** + * Sets the {@link SASTokenCredential} used to authenticate requests sent to the Queue service. + * + * @param credential SAS token credential generated from the Storage account that authorizes requests + * @return the updated QueueServiceClientBuilder object + * @throws NullPointerException If {@code credential} is {@code null}. + */ + public QueueServiceClientBuilder credential(SASTokenCredential credential) { + this.sasTokenCredential = Objects.requireNonNull(credential); + return this; + } + + /** + * Sets the {@link SharedKeyCredential} used to authenticate requests sent to the Queue service. + * + * @param credential Shared key credential can retrieve from the Storage account that authorizes requests + * @return the updated QueueServiceClientBuilder object + * @throws NullPointerException If {@code credential} is {@code null}. + */ + public QueueServiceClientBuilder credential(SharedKeyCredential credential) { + this.sharedKeyCredential = Objects.requireNonNull(credential); + return this; + } + + + /** + * Creates a {@link SharedKeyCredential} from the {@code connectionString} used to authenticate requests sent to the + * Queue service. + * + * @param connectionString Connection string from the Access Keys section in the Storage account + * @return the updated QueueServiceClientBuilder object + * @throws NullPointerException If {@code connectionString} is {@code null}. + */ + public QueueServiceClientBuilder connectionString(String connectionString) { + Objects.requireNonNull(connectionString); + this.sharedKeyCredential = SharedKeyCredential.fromConnectionString(connectionString); + return this; + } + + /** + * Sets the HTTP client to use for sending and receiving requests to and from the service. + * + * @param httpClient The HTTP client to use for requests. + * @return The updated QueueServiceClientBuilder object. + * @throws NullPointerException If {@code httpClient} is {@code null}. + */ + public QueueServiceClientBuilder httpClient(HttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Adds a policy to the set of existing policies that are executed after the {@link RetryPolicy}. + * + * @param pipelinePolicy The retry policy for service requests. + * @return The updated QueueServiceClientBuilder object. + * @throws NullPointerException If {@code pipelinePolicy} is {@code null}. + */ + public QueueServiceClientBuilder addPolicy(HttpPipelinePolicy pipelinePolicy) { + this.policies.add(pipelinePolicy); + return this; + } + + /** + * Sets the logging level for HTTP requests and responses. + * + * @param logLevel The amount of logging output when sending and receiving HTTP requests/responses. + * @return The updated QueueServiceClientBuilder object. + */ + public QueueServiceClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { + this.logLevel = logLevel; + return this; + } + + /** + * Sets the HTTP pipeline to use for the service client. + * + * If {@code pipeline} is set, all other settings are ignored, aside from {@link QueueServiceClientBuilder#endpoint(String) endpoint} + * when building clients. + * + * @param pipeline The HTTP pipeline to use for sending service requests and receiving responses. + * @return The updated QueueServiceClientBuilder object. + * @throws NullPointerException If {@code pipeline} is {@code null}. + */ + public QueueServiceClientBuilder pipeline(HttpPipeline pipeline) { + Objects.requireNonNull(pipeline); + this.pipeline = pipeline; + return this; + } + + /** + * Sets the configuration store that is used during construction of the service client. + * + * The default configuration store is a clone of the {@link ConfigurationManager#getConfiguration() global + * configuration store}, use {@link Configuration#NONE} to bypass using configuration settings during construction. + * + * @param configuration The configuration store used to + * @return The updated QueueServiceClientBuilder object. + */ + public QueueServiceClientBuilder configuration(Configuration configuration) { + this.configuration = configuration; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/README.md b/storage/client/queue/src/main/java/com/azure/storage/queue/README.md new file mode 100644 index 0000000000000..86ffe940daf0c --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/README.md @@ -0,0 +1,377 @@ +# Azure Storage Queue client library for Java +Azure Queue storage is a service for storing large numbers of messages that can be accessed from anywhere in the world via authenticated calls using HTTP or HTTPS. +A single queue message can be up to 64 KB in size, and a queue can contain millions of messages, up to the total capacity limit of a storage account. + +[Source code][source_code] | [Package (Maven)][package] | [API reference documentation][api_documentation] | [Product documentation][storage_docs] + +## Getting started + +### Prerequisites + +- [Java Development Kit (JDK)][jdk] with version 8 or above +- [Azure Subscription][azure_subscription] +- [Create Strorage Account][storage_account] + +### Adding the package to your product + +```xml + + com.azure + azure-storage + 12.0.0 + +``` + +### Create a Storage Account +To create a Storage Account you can use the Azure Portal or [Azure CLI][azure_cli]. + +```Powershell +az group create \ + --name storage-resource-group \ + --location westus +``` + +### Authenticate the client + +In order to interact with the Storage service (Blob, Queue, Message, MessageId, File) you'll need to create an instance of the Service Client class. +To make this possible you'll need the Account SAS (shared access signature) string of Storage account. Learn more at [SAS Token][sas_token] + +#### Get Credentials + +- **SAS Token** + +a. Use the [Azure CLI][azure_cli] snippet below to get the SAS token from the Storage account. + +```Powershell +az storage queue generate-sas + --name {queue name} + --expiry {date/time to expire SAS token} + --permission {permission to grant} + --connection-string {connection string of the storage account} +``` + +```Powershell +CONNECTION_STRING= + +az storage queue generate-sas + --name javasdksas + --expiry 2019-06-05 + --permission rpau + --connection-string $CONNECTION_STRING +``` +b. Alternatively, get the Account SAS Token from the Azure Portal. +``` +Go to your storage account -> Shared access signature -> Click on Generate SAS and connection string (after setup) +``` + +- **Shared Key Credential** + +a. Use account name and account key. Account name is your storage account name. +``` +// Here is where we get the key +Go to your storage account -> Access keys -> Key 1/ Key 2 -> Key +``` +b. Use the connection string +``` +// Here is where we get the key +Go to your storage account -> Access Keys -> Keys 1/ Key 2 -> Connection string +``` +## Key concepts +### URL format +Queues are addressable using the following URL format: +https://.queue.core.windows.net/ +The following URL addresses a queue in the diagram: +https://myaccount.queue.core.windows.net/images-to-download + +#### Resource URI Syntax +For the storage account, the base URI for queue operations includes the name of the account only: +```$xslt +https://myaccount.queue.core.windows.net +``` +For a queue, the base URI includes the name of the account and the name of the queue: +```$xslt +https://myaccount.queue.core.windows.net/myqueue +``` + +### Handling Exceptions + +```java +TODO +``` + +### Queue Names +Every queue within an account must have a unique name. The queue name must be a valid DNS name, and cannot be changed once created. Queue names must confirm to the following rules: +1. A queue name must start with a letter or number, and can only contain letters, numbers, and the dash (-) character. +1. The first and last letters in the queue name must be alphanumeric. The dash (-) character cannot be the first or last character. Consecutive dash characters are not permitted in the queue name. +1. All letters in a queue name must be lowercase. +1. A queue name must be from 3 through 63 characters long. + +### Queue Services +The queue service do operations on the queues in the storage account and manage the queue properties. + +### Queue Service Client + +The client performs the interactions with the Queue service, create or delete a queue, getting and setting Queue properties, list queues in account, and get queue statistics. An asynchronous, `QueueServiceAsyncClient`, and synchronous, `QueueClient`, client exists in the SDK allowing for selection of a client based on an application's use case. +Once you have the value of the SASToken you can create the queue service client with `${accountName}`, `${sasToken}`. +```Java +String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) +QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); + +QueueClient newQueueServiceClient = queueServiceClient.createQueue("myqueue"); +``` + +or + +```Java +String queueServiceAsyncURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) +QueueServiceAsyncClient queueServiceAsyncClient = QueueServiceAsyncClient.builder().endpoint(queueServiceAsyncURL).build(); +queueServiceAsyncClient.createQueue("newAsyncQueue").subscribe( + result -> { + // do something when new queue created + }, + error -> { + // do something if something wrong happened + }, + () -> { + // completed, do something + }); +``` + +### Queue +Azure Queue storage is a service for storing large numbers of messages that can be accessed from anywhere in the world via authenticated calls using HTTP or HTTPS. +A single queue message can be up to 64 KB in size, and a queue can contain millions of messages, up to the total capacity limit of a storage account. + +### QueueClient +Once you have the value of the SASToken you can create the queue service client with `${accountName}`, `${queueName}`, `${sasToken}`. +```Java +String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); +// metadata is map of key-value pair, timeout is client side timeout +QueueClient newQueueClient = queueClient.create(metadata, timeout); +``` + +or + +```Java +String queueAsyncURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueAsyncName, sasToken) +QueueAsyncClient queueAsyncClient = QueueAsyncClient.builder().endpoint(queueAsyncURL).build(); +queueAsyncClient.create(metadata, timeout).subscribe( + result -> { + // do something when new queue created + }, + error -> { + // do something if something wrong happened + }, + () -> { + // completed, do something + }); +``` + +## Examples + +The following sections provide several code snippets covering some of the most common Configuration Service tasks, including: +- [Create a Queue](#Create-a-queue) +- [Delete a queue](#Delete-a-queue) +- [List the queues in account](#List-queues-in-account) +- [Get propertiesin Queue account](#Get-properties-in-queue-account) +- [Set propertiesin Queue account](#Set-properties-in-queue-account) +- [Get statistcs of queue](#Get-queue-service-statistics) +- [Enqueue message into a queue](#Enqueue-message-into-a-queue) +- [Update message into a queue](#Update-message-into-a-queue) +- [Peek messages into a queue](#Peek-messages-into-a-queue) +- [Dequeue messages from a queue](#Dequeue-messages-from-a-queue) +- [Delete message from a queue](#Delete-message-from-a-queue) +- [Get a Queue properties](#Get-a-queue-properties) +- [Set/Update a Queue metadata](#Set-a-queue-metadata) +### Create a queue + +Create a queue in the Storage Account. Throws StorageErrorException If the queue fails to be created. + +```Java +String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) +QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); + +QueueClient newQueueServiceClient = queueServiceClient.createQueue("myqueue"); +``` +### Delete a queue + +Delete a queue in the Storage Account. Throws StorageErrorException If the queue fails to be deleted. +```Java +String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) +QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); + +QueueClient newQueueServiceClient = queueServiceClient.deleteQueue("myqueue"); +``` + +### List queues in account + +List all the queues in account. +```Java +String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) +QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); +// @param marker: Starting point to list the queues +// @param options: Filter for queue selection +queueServiceClient.listQueuesSegment(marker, options).forEach{ + queueItem -> {//do something} +}; +``` + +### Get properties in queue account + +Get queue properties in account, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules. +```Java +String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) +QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); + +Response properties = queueServiceClient.getProperties(); +``` + +### Set properties in queue account + +Set queue properties in account, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules. +```Java +String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) +QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); + +StorageServiceProperties properties = new StorageServiceProperties() { + // logging: some logging; + // HourMetrics: some metrics + // MinuteMetrics: some metrics + // Cors: some cors +} + +queueServiceClient.setProperties(properties); +``` + +### Get queue service statistics +he `Get Queue Service Stats` operation retrieves statistics related to replication for the Queue service. +It is only available on the secondary location endpoint when read-access geo-redundant replication is enabled for the storage account. +```Java +String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) +QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); + +Response queueStats = queueServiceClient.getStatistics(); +``` + +### Enqueue message into a queue +The operation adds a new message to the back of the message queue. A visibility timeout can also be specified to make the message invisible until the visibility timeout expires. +A message must be in a format that can be included in an XML request with UTF-8 encoding. The encoded message can be up to 64 KB in size for versions 2011-08-18 and newer, or 8 KB in size for previous versions. +```Java +String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); + +queueClient.enqueueMessage("myMessage"); +``` + +### Update messaged from a queue +The operation updates a message in the message queue. +```Java +String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); +// @param messageId Id of the message +// @param popReceipt Unique identifier that must match the message for it to be updated +// @param visibilityTimeout How long the message will be invisible in the queue in seconds +queueClient.updateMessage(messageId, "new message", popReceipt, visibilityTimeout); +``` + +### Peek messages from a queue +The operation retrieves one or more messages from the front of the queue. +```Java +String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); + +queueClient.peekMessages().forEach(message-> {print message.messageText();}); +``` + + +### Dequeue messages from a queue +The operation retrieves one or more messages from the front of the queue. +```Java +String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); + +queueClient.dequeueMessage("myMessage").forEach(message-> {print message.messageText();}); +``` + + +### Delete message from a queue +The operation retrieves one or more messages from the front of the queue. +```Java +String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); + +queueClient.deleteMessage(messageId, popReceipt); +``` + +### Get a queue properties +The operation retrieves user-defined metadata and queue properties on the specified queue. Metadata is associated with the queue as name-values pairs. +```Java +String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); + +Response properties = queueClient.getProperties(); +``` + +### Set a queue metadata +The operation sets user-defined metadata on the specified queue. Metadata is associated with the queue as name-value pairs. +```Java +String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); + +Map metadata = new HashMap<>() {{ + put("key1", "val1"); + put("key2", "val2"); +}}; +queueClient.setMetadata(metadata); +``` + + +## Troubleshooting + +## General + +When you interact with queue using this Java client library, errors returned by the service correspond to the same HTTP status codes returned for [REST API][storage_rest] requests. For example, if you try to retrieve a queue that doesn't exist in your Storage Account, a `404` error is returned, indicating `Not Found`. + +## Next steps + +### More Samples +- QueueServiceSample +- MessageSample +- QueueExceptionSample +- AsyncSample + +[Quickstart: Create a Java Spring app with App Configuration](https://docs.microsoft.com/en-us/azure/azure-app-configuration/quickstart-java-spring-app) + +## Contributing +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +If you would like to become an active contributor to this project please follow the instructions provided in [Microsoft Azure Projects Contribution Guidelines](http://azure.github.io/guidelines.html). + +1. Fork it +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create new Pull Request + + +[source_code]: to-be-continue +[package]: to-be-continue +[api_documentation]: https://docs.microsoft.com/en-us/rest/api/storageservices/queue-service-rest-api +[storage_docs]: https://docs.microsoft.com/en-us/azure/storage/queues/storage-queues-introduction +[jdk]: https://docs.microsoft.com/en-us/java/azure/java-supported-jdk-runtime?view=azure-java-stable +[maven]: https://maven.apache.org/ +[azure_subscription]: https://azure.microsoft.com/en-us/free/ +[storage_account]: https://docs.microsoft.com/en-us/azure/storage/common/storage-quickstart-create-account?tabs=azure-portal +[azure_cli]: https://docs.microsoft.com/cli/azure +[sas_token]: https://docs.microsoft.com/en-us/azure/storage/common/storage-dotnet-shared-access-signature-part-1 +[storage_rest]: https://docs.microsoft.com/en-us/rest/api/storageservices/queue-service-error-codes diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/AzureQueueStorageBuilder.java b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/AzureQueueStorageBuilder.java index 4f678dfe10832..f3582e10e1a44 100644 --- a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/AzureQueueStorageBuilder.java +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/AzureQueueStorageBuilder.java @@ -75,9 +75,7 @@ public AzureQueueStorageImpl build() { if (this.url != null) { client.url(this.url); } - if (this.version != null) { - client.version(this.version); - } + client.version(this.version); return client; } } diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/MessageIdsImpl.java b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/MessageIdsImpl.java index 8a705fe7e4af7..f5e6c952f5de1 100644 --- a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/MessageIdsImpl.java +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/MessageIdsImpl.java @@ -10,6 +10,7 @@ import com.azure.core.annotations.HeaderParam; import com.azure.core.annotations.Host; import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.PathParam; import com.azure.core.annotations.PUT; import com.azure.core.annotations.QueryParam; import com.azure.core.annotations.Service; @@ -57,12 +58,12 @@ private interface MessageIdsService { @PUT("{queueName}/messages/{messageid}") @ExpectedResponses({204}) @UnexpectedResponseExceptionType(StorageErrorException.class) - Mono update(@HostParam("url") String url, @BodyParam("application/xml; charset=utf-8") QueueMessage queueMessage, @QueryParam("popreceipt") String popReceipt, @QueryParam("visibilitytimeout") int visibilitytimeout, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); + Mono update(@HostParam("url") String url, @PathParam("queueName") String queueName, @PathParam("messageid") String messageId, @BodyParam("application/xml; charset=utf-8") QueueMessage queueMessage, @QueryParam("popreceipt") String popReceipt, @QueryParam("visibilitytimeout") int visibilitytimeout, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); @DELETE("{queueName}/messages/{messageid}") @ExpectedResponses({204}) @UnexpectedResponseExceptionType(StorageErrorException.class) - Mono delete(@HostParam("url") String url, @QueryParam("popreceipt") String popReceipt, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); + Mono delete(@HostParam("url") String url, @PathParam("queueName") String queueName, @PathParam("messageid") String messageId, @QueryParam("popreceipt") String popReceipt, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); } /** @@ -75,10 +76,10 @@ private interface MessageIdsService { * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono updateWithRestResponseAsync(QueueMessage queueMessage, String popReceipt, int visibilitytimeout, Context context) { + public Mono updateWithRestResponseAsync(String queueName, String messageId, QueueMessage queueMessage, String popReceipt, int visibilitytimeout, Context context) { final Integer timeout = null; final String requestId = null; - return service.update(this.client.url(), queueMessage, popReceipt, visibilitytimeout, timeout, this.client.version(), requestId, context); + return service.update(this.client.url(), queueName, messageId, queueMessage, popReceipt, visibilitytimeout, timeout, this.client.version(), requestId, context); } /** @@ -93,8 +94,8 @@ public Mono updateWithRestResponseAsync(QueueMessage q * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono updateWithRestResponseAsync(QueueMessage queueMessage, String popReceipt, int visibilitytimeout, Integer timeout, String requestId, Context context) { - return service.update(this.client.url(), queueMessage, popReceipt, visibilitytimeout, timeout, this.client.version(), requestId, context); + public Mono updateWithRestResponseAsync(String queueName, String messageId, QueueMessage queueMessage, String popReceipt, int visibilitytimeout, Integer timeout, String requestId, Context context) { + return service.update(this.client.url(), queueName, messageId, queueMessage, popReceipt, visibilitytimeout, timeout, this.client.version(), requestId, context); } /** @@ -105,10 +106,10 @@ public Mono updateWithRestResponseAsync(QueueMessage q * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono deleteWithRestResponseAsync(String popReceipt, Context context) { + public Mono deleteWithRestResponseAsync(String queueName, String messageId, String popReceipt, Context context) { final Integer timeout = null; final String requestId = null; - return service.delete(this.client.url(), popReceipt, timeout, this.client.version(), requestId, context); + return service.delete(this.client.url(), queueName, messageId, popReceipt, timeout, this.client.version(), requestId, context); } /** @@ -121,7 +122,7 @@ public Mono deleteWithRestResponseAsync(String popRece * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono deleteWithRestResponseAsync(String popReceipt, Integer timeout, String requestId, Context context) { - return service.delete(this.client.url(), popReceipt, timeout, this.client.version(), requestId, context); + public Mono deleteWithRestResponseAsync(String queueName, String messageId, String popReceipt, Integer timeout, String requestId, Context context) { + return service.delete(this.client.url(), queueName, messageId, popReceipt, timeout, this.client.version(), requestId, context); } } diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/MessagesImpl.java b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/MessagesImpl.java index ee59aae16b63f..84f680cad1dba 100644 --- a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/MessagesImpl.java +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/MessagesImpl.java @@ -11,6 +11,7 @@ import com.azure.core.annotations.HeaderParam; import com.azure.core.annotations.Host; import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.PathParam; import com.azure.core.annotations.POST; import com.azure.core.annotations.QueryParam; import com.azure.core.annotations.Service; @@ -60,22 +61,22 @@ private interface MessagesService { @GET("{queueName}/messages") @ExpectedResponses({200}) @UnexpectedResponseExceptionType(StorageErrorException.class) - Mono dequeue(@HostParam("url") String url, @QueryParam("numofmessages") Integer numberOfMessages, @QueryParam("visibilitytimeout") Integer visibilitytimeout, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); + Mono dequeue(@HostParam("url") String url, @PathParam("queueName") String queueName, @QueryParam("numofmessages") Integer numberOfMessages, @QueryParam("visibilitytimeout") Integer visibilitytimeout, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); @DELETE("{queueName}/messages") @ExpectedResponses({204}) @UnexpectedResponseExceptionType(StorageErrorException.class) - Mono clear(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); + Mono clear(@HostParam("url") String url, @PathParam("queueName") String queueName, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); @POST("{queueName}/messages") @ExpectedResponses({201}) @UnexpectedResponseExceptionType(StorageErrorException.class) - Mono enqueue(@HostParam("url") String url, @BodyParam("application/xml; charset=utf-8") QueueMessage queueMessage, @QueryParam("visibilitytimeout") Integer visibilitytimeout, @QueryParam("messagettl") Integer messageTimeToLive, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); + Mono enqueue(@HostParam("url") String url, @PathParam("queueName") String queueName, @BodyParam("application/xml; charset=utf-8") QueueMessage queueMessage, @QueryParam("visibilitytimeout") Integer visibilitytimeout, @QueryParam("messagettl") Integer messageTimeToLive, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); @GET("{queueName}/messages") @ExpectedResponses({200}) @UnexpectedResponseExceptionType(StorageErrorException.class) - Mono peek(@HostParam("url") String url, @QueryParam("numofmessages") Integer numberOfMessages, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("peekonly") String peekonly, Context context); + Mono peek(@HostParam("url") String url, @PathParam("queueName") String queueName, @QueryParam("numofmessages") Integer numberOfMessages, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("peekonly") String peekonly, Context context); } /** @@ -85,12 +86,12 @@ private interface MessagesService { * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono dequeueWithRestResponseAsync(Context context) { + public Mono dequeueWithRestResponseAsync(String queueName, Context context) { final Integer numberOfMessages = null; final Integer visibilitytimeout = null; final Integer timeout = null; final String requestId = null; - return service.dequeue(this.client.url(), numberOfMessages, visibilitytimeout, timeout, this.client.version(), requestId, context); + return service.dequeue(this.client.url(), queueName, numberOfMessages, visibilitytimeout, timeout, this.client.version(), requestId, context); } /** @@ -104,8 +105,8 @@ public Mono dequeueWithRestResponseAsync(Context contex * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono dequeueWithRestResponseAsync(Integer numberOfMessages, Integer visibilitytimeout, Integer timeout, String requestId, Context context) { - return service.dequeue(this.client.url(), numberOfMessages, visibilitytimeout, timeout, this.client.version(), requestId, context); + public Mono dequeueWithRestResponseAsync(String queueName, Integer numberOfMessages, Integer visibilitytimeout, Integer timeout, String requestId, Context context) { + return service.dequeue(this.client.url(), queueName, numberOfMessages, visibilitytimeout, timeout, this.client.version(), requestId, context); } /** @@ -115,10 +116,10 @@ public Mono dequeueWithRestResponseAsync(Integer number * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono clearWithRestResponseAsync(Context context) { + public Mono clearWithRestResponseAsync(String queueName, Context context) { final Integer timeout = null; final String requestId = null; - return service.clear(this.client.url(), timeout, this.client.version(), requestId, context); + return service.clear(this.client.url(), queueName, timeout, this.client.version(), requestId, context); } /** @@ -130,8 +131,8 @@ public Mono clearWithRestResponseAsync(Context context) { * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono clearWithRestResponseAsync(Integer timeout, String requestId, Context context) { - return service.clear(this.client.url(), timeout, this.client.version(), requestId, context); + public Mono clearWithRestResponseAsync(String queueName, Integer timeout, String requestId, Context context) { + return service.clear(this.client.url(), queueName, timeout, this.client.version(), requestId, context); } /** @@ -142,12 +143,12 @@ public Mono clearWithRestResponseAsync(Integer timeout, S * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono enqueueWithRestResponseAsync(QueueMessage queueMessage, Context context) { + public Mono enqueueWithRestResponseAsync(String queueName, QueueMessage queueMessage, Context context) { final Integer visibilitytimeout = null; final Integer messageTimeToLive = null; final Integer timeout = null; final String requestId = null; - return service.enqueue(this.client.url(), queueMessage, visibilitytimeout, messageTimeToLive, timeout, this.client.version(), requestId, context); + return service.enqueue(this.client.url(), queueName, queueMessage, visibilitytimeout, messageTimeToLive, timeout, this.client.version(), requestId, context); } /** @@ -162,8 +163,8 @@ public Mono enqueueWithRestResponseAsync(QueueMessage q * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono enqueueWithRestResponseAsync(QueueMessage queueMessage, Integer visibilitytimeout, Integer messageTimeToLive, Integer timeout, String requestId, Context context) { - return service.enqueue(this.client.url(), queueMessage, visibilitytimeout, messageTimeToLive, timeout, this.client.version(), requestId, context); + public Mono enqueueWithRestResponseAsync(String queueName, QueueMessage queueMessage, Integer visibilitytimeout, Integer messageTimeToLive, Integer timeout, String requestId, Context context) { + return service.enqueue(this.client.url(), queueName, queueMessage, visibilitytimeout, messageTimeToLive, timeout, this.client.version(), requestId, context); } /** @@ -173,12 +174,12 @@ public Mono enqueueWithRestResponseAsync(QueueMessage q * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono peekWithRestResponseAsync(Context context) { + public Mono peekWithRestResponseAsync(String queueName, Context context) { final Integer numberOfMessages = null; final Integer timeout = null; final String requestId = null; final String peekonly = "true"; - return service.peek(this.client.url(), numberOfMessages, timeout, this.client.version(), requestId, peekonly, context); + return service.peek(this.client.url(), queueName, numberOfMessages, timeout, this.client.version(), requestId, peekonly, context); } /** @@ -191,8 +192,8 @@ public Mono peekWithRestResponseAsync(Context context) { * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono peekWithRestResponseAsync(Integer numberOfMessages, Integer timeout, String requestId, Context context) { + public Mono peekWithRestResponseAsync(String queueName, Integer numberOfMessages, Integer timeout, String requestId, Context context) { final String peekonly = "true"; - return service.peek(this.client.url(), numberOfMessages, timeout, this.client.version(), requestId, peekonly, context); + return service.peek(this.client.url(), queueName, numberOfMessages, timeout, this.client.version(), requestId, peekonly, context); } } diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/QueuesImpl.java b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/QueuesImpl.java index 2eb2d4d1ec2e2..db933d31e4238 100644 --- a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/QueuesImpl.java +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/QueuesImpl.java @@ -11,6 +11,7 @@ import com.azure.core.annotations.HeaderParam; import com.azure.core.annotations.Host; import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.PathParam; import com.azure.core.annotations.PUT; import com.azure.core.annotations.QueryParam; import com.azure.core.annotations.Service; @@ -25,10 +26,9 @@ import com.azure.storage.queue.models.QueuesSetMetadataResponse; import com.azure.storage.queue.models.SignedIdentifier; import com.azure.storage.queue.models.StorageErrorException; -import reactor.core.publisher.Mono; - import java.util.List; import java.util.Map; +import reactor.core.publisher.Mono; /** * An instance of this class provides access to all the operations defined in @@ -65,32 +65,32 @@ private interface QueuesService { @PUT("{queueName}") @ExpectedResponses({201, 204}) @UnexpectedResponseExceptionType(StorageErrorException.class) - Mono create(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); + Mono create(@HostParam("url") String url, @PathParam("queueName") String queueName, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); @DELETE("{queueName}") @ExpectedResponses({204}) @UnexpectedResponseExceptionType(StorageErrorException.class) - Mono delete(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); + Mono delete(@HostParam("url") String url, @PathParam("queueName") String queueName, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); @GET("{queueName}") @ExpectedResponses({200}) @UnexpectedResponseExceptionType(StorageErrorException.class) - Mono getProperties(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, Context context); + Mono getProperties(@HostParam("url") String url, @PathParam("queueName") String queueName, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, Context context); @PUT("{queueName}") @ExpectedResponses({204}) @UnexpectedResponseExceptionType(StorageErrorException.class) - Mono setMetadata(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, Context context); + Mono setMetadata(@HostParam("url") String url, @PathParam("queueName") String queueName, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, Context context); @GET("{queueName}") @ExpectedResponses({200}) @UnexpectedResponseExceptionType(StorageErrorException.class) - Mono getAccessPolicy(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, Context context); + Mono getAccessPolicy(@HostParam("url") String url, @PathParam("queueName") String queueName, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, Context context); @PUT("{queueName}") @ExpectedResponses({204}) @UnexpectedResponseExceptionType(StorageErrorException.class) - Mono setAccessPolicy(@HostParam("url") String url, @BodyParam("application/xml; charset=utf-8") SignedIdentifiersWrapper queueAcl, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, Context context); + Mono setAccessPolicy(@HostParam("url") String url, @PathParam("queueName") String queueName, @BodyParam("application/xml; charset=utf-8") SignedIdentifiersWrapper queueAcl, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, Context context); } /** @@ -100,11 +100,11 @@ private interface QueuesService { * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono createWithRestResponseAsync(Context context) { + public Mono createWithRestResponseAsync(String queueName, Context context) { final Integer timeout = null; final Map metadata = null; final String requestId = null; - return service.create(this.client.url(), timeout, metadata, this.client.version(), requestId, context); + return service.create(this.client.url(), queueName, timeout, metadata, this.client.version(), requestId, context); } /** @@ -117,8 +117,8 @@ public Mono createWithRestResponseAsync(Context context) { * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono createWithRestResponseAsync(Integer timeout, Map metadata, String requestId, Context context) { - return service.create(this.client.url(), timeout, metadata, this.client.version(), requestId, context); + public Mono createWithRestResponseAsync(String queueName, Integer timeout, Map metadata, String requestId, Context context) { + return service.create(this.client.url(), queueName, timeout, metadata, this.client.version(), requestId, context); } /** @@ -128,10 +128,10 @@ public Mono createWithRestResponseAsync(Integer timeout, M * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono deleteWithRestResponseAsync(Context context) { + public Mono deleteWithRestResponseAsync(String queueName, Context context) { final Integer timeout = null; final String requestId = null; - return service.delete(this.client.url(), timeout, this.client.version(), requestId, context); + return service.delete(this.client.url(), queueName, timeout, this.client.version(), requestId, context); } /** @@ -143,8 +143,8 @@ public Mono deleteWithRestResponseAsync(Context context) { * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono deleteWithRestResponseAsync(Integer timeout, String requestId, Context context) { - return service.delete(this.client.url(), timeout, this.client.version(), requestId, context); + public Mono deleteWithRestResponseAsync(String queueName, Integer timeout, String requestId, Context context) { + return service.delete(this.client.url(), queueName, timeout, this.client.version(), requestId, context); } /** @@ -154,11 +154,11 @@ public Mono deleteWithRestResponseAsync(Integer timeout, S * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono getPropertiesWithRestResponseAsync(Context context) { + public Mono getPropertiesWithRestResponseAsync(String queueName, Context context) { final Integer timeout = null; final String requestId = null; final String comp = "metadata"; - return service.getProperties(this.client.url(), timeout, this.client.version(), requestId, comp, context); + return service.getProperties(this.client.url(), queueName, timeout, this.client.version(), requestId, comp, context); } /** @@ -170,9 +170,9 @@ public Mono getPropertiesWithRestResponseAsync(Cont * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono getPropertiesWithRestResponseAsync(Integer timeout, String requestId, Context context) { + public Mono getPropertiesWithRestResponseAsync(String queueName, Integer timeout, String requestId, Context context) { final String comp = "metadata"; - return service.getProperties(this.client.url(), timeout, this.client.version(), requestId, comp, context); + return service.getProperties(this.client.url(), queueName, timeout, this.client.version(), requestId, comp, context); } /** @@ -182,12 +182,12 @@ public Mono getPropertiesWithRestResponseAsync(Inte * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono setMetadataWithRestResponseAsync(Context context) { + public Mono setMetadataWithRestResponseAsync(String queueName, Context context) { final Integer timeout = null; final Map metadata = null; final String requestId = null; final String comp = "metadata"; - return service.setMetadata(this.client.url(), timeout, metadata, this.client.version(), requestId, comp, context); + return service.setMetadata(this.client.url(), queueName, timeout, metadata, this.client.version(), requestId, comp, context); } /** @@ -200,9 +200,9 @@ public Mono setMetadataWithRestResponseAsync(Context * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono setMetadataWithRestResponseAsync(Integer timeout, Map metadata, String requestId, Context context) { + public Mono setMetadataWithRestResponseAsync(String queueName, Integer timeout, Map metadata, String requestId, Context context) { final String comp = "metadata"; - return service.setMetadata(this.client.url(), timeout, metadata, this.client.version(), requestId, comp, context); + return service.setMetadata(this.client.url(), queueName, timeout, metadata, this.client.version(), requestId, comp, context); } /** @@ -212,11 +212,11 @@ public Mono setMetadataWithRestResponseAsync(Integer * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono getAccessPolicyWithRestResponseAsync(Context context) { + public Mono getAccessPolicyWithRestResponseAsync(String queueName, Context context) { final Integer timeout = null; final String requestId = null; final String comp = "acl"; - return service.getAccessPolicy(this.client.url(), timeout, this.client.version(), requestId, comp, context); + return service.getAccessPolicy(this.client.url(), queueName, timeout, this.client.version(), requestId, comp, context); } /** @@ -228,9 +228,9 @@ public Mono getAccessPolicyWithRestResponseAsync( * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono getAccessPolicyWithRestResponseAsync(Integer timeout, String requestId, Context context) { + public Mono getAccessPolicyWithRestResponseAsync(String queueName, Integer timeout, String requestId, Context context) { final String comp = "acl"; - return service.getAccessPolicy(this.client.url(), timeout, this.client.version(), requestId, comp, context); + return service.getAccessPolicy(this.client.url(), queueName, timeout, this.client.version(), requestId, comp, context); } /** @@ -240,12 +240,12 @@ public Mono getAccessPolicyWithRestResponseAsync( * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono setAccessPolicyWithRestResponseAsync(Context context) { + public Mono setAccessPolicyWithRestResponseAsync(String queueName, Context context) { final Integer timeout = null; final String requestId = null; final String comp = "acl"; SignedIdentifiersWrapper queueAclConverted = new SignedIdentifiersWrapper(null); - return service.setAccessPolicy(this.client.url(), queueAclConverted, timeout, this.client.version(), requestId, comp, context); + return service.setAccessPolicy(this.client.url(), queueName, queueAclConverted, timeout, this.client.version(), requestId, comp, context); } /** @@ -258,9 +258,9 @@ public Mono setAccessPolicyWithRestResponseAsync( * @throws IllegalArgumentException thrown if parameters fail the validation. * @return a Mono which performs the network request upon subscription. */ - public Mono setAccessPolicyWithRestResponseAsync(List queueAcl, Integer timeout, String requestId, Context context) { + public Mono setAccessPolicyWithRestResponseAsync(String queueName, List queueAcl, Integer timeout, String requestId, Context context) { final String comp = "acl"; SignedIdentifiersWrapper queueAclConverted = new SignedIdentifiersWrapper(queueAcl); - return service.setAccessPolicy(this.client.url(), queueAclConverted, timeout, this.client.version(), requestId, comp, context); + return service.setAccessPolicy(this.client.url(), queueName, queueAclConverted, timeout, this.client.version(), requestId, comp, context); } } diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/ServicesImpl.java b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/ServicesImpl.java index dc353d45f5243..1dc20d2b42fa8 100644 --- a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/ServicesImpl.java +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/ServicesImpl.java @@ -25,9 +25,8 @@ import com.azure.storage.queue.models.ServicesSetPropertiesResponse; import com.azure.storage.queue.models.StorageErrorException; import com.azure.storage.queue.models.StorageServiceProperties; -import reactor.core.publisher.Mono; - import java.util.List; +import reactor.core.publisher.Mono; /** * An instance of this class provides access to all the operations defined in diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/DequeuedMessageItem.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/DequeuedMessage.java similarity index 85% rename from storage/client/queue/src/main/java/com/azure/storage/queue/models/DequeuedMessageItem.java rename to storage/client/queue/src/main/java/com/azure/storage/queue/models/DequeuedMessage.java index 7febd2c02758d..65e6e941c717a 100644 --- a/storage/client/queue/src/main/java/com/azure/storage/queue/models/DequeuedMessageItem.java +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/DequeuedMessage.java @@ -1,6 +1,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -// Code generated by Microsoft (R) AutoRest Code Generator. package com.azure.storage.queue.models; @@ -14,7 +13,7 @@ * on a Queue. */ @JacksonXmlRootElement(localName = "QueueMessage") -public final class DequeuedMessageItem { +public final class DequeuedMessage { /* * The Id of the Message. */ @@ -71,9 +70,9 @@ public String messageId() { * Set the messageId property: The Id of the Message. * * @param messageId the messageId value to set. - * @return the DequeuedMessageItem object itself. + * @return the DequeuedMessage object itself. */ - public DequeuedMessageItem messageId(String messageId) { + public DequeuedMessage messageId(String messageId) { this.messageId = messageId; return this; } @@ -96,9 +95,9 @@ public OffsetDateTime insertionTime() { * the Queue. * * @param insertionTime the insertionTime value to set. - * @return the DequeuedMessageItem object itself. + * @return the DequeuedMessage object itself. */ - public DequeuedMessageItem insertionTime(OffsetDateTime insertionTime) { + public DequeuedMessage insertionTime(OffsetDateTime insertionTime) { if (insertionTime == null) { this.insertionTime = null; } else { @@ -125,9 +124,9 @@ public OffsetDateTime expirationTime() { * and be automatically deleted. * * @param expirationTime the expirationTime value to set. - * @return the DequeuedMessageItem object itself. + * @return the DequeuedMessage object itself. */ - public DequeuedMessageItem expirationTime(OffsetDateTime expirationTime) { + public DequeuedMessage expirationTime(OffsetDateTime expirationTime) { if (expirationTime == null) { this.expirationTime = null; } else { @@ -153,9 +152,9 @@ public String popReceipt() { * been dequeued by another client. * * @param popReceipt the popReceipt value to set. - * @return the DequeuedMessageItem object itself. + * @return the DequeuedMessage object itself. */ - public DequeuedMessageItem popReceipt(String popReceipt) { + public DequeuedMessage popReceipt(String popReceipt) { this.popReceipt = popReceipt; return this; } @@ -178,9 +177,9 @@ public OffsetDateTime timeNextVisible() { * become visible in the Queue. * * @param timeNextVisible the timeNextVisible value to set. - * @return the DequeuedMessageItem object itself. + * @return the DequeuedMessage object itself. */ - public DequeuedMessageItem timeNextVisible(OffsetDateTime timeNextVisible) { + public DequeuedMessage timeNextVisible(OffsetDateTime timeNextVisible) { if (timeNextVisible == null) { this.timeNextVisible = null; } else { @@ -204,9 +203,9 @@ public long dequeueCount() { * dequeued. * * @param dequeueCount the dequeueCount value to set. - * @return the DequeuedMessageItem object itself. + * @return the DequeuedMessage object itself. */ - public DequeuedMessageItem dequeueCount(long dequeueCount) { + public DequeuedMessage dequeueCount(long dequeueCount) { this.dequeueCount = dequeueCount; return this; } @@ -224,9 +223,9 @@ public String messageText() { * Set the messageText property: The content of the Message. * * @param messageText the messageText value to set. - * @return the DequeuedMessageItem object itself. + * @return the DequeuedMessage object itself. */ - public DequeuedMessageItem messageText(String messageText) { + public DequeuedMessage messageText(String messageText) { this.messageText = messageText; return this; } diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesDequeueResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesDequeueResponse.java index 4ab4b09a4a620..c08c7ccc025c7 100644 --- a/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesDequeueResponse.java +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesDequeueResponse.java @@ -12,7 +12,7 @@ /** * Contains all response data for the dequeue operation. */ -public final class MessagesDequeueResponse extends ResponseBase> { +public final class MessagesDequeueResponse extends ResponseBase> { /** * Creates an instance of MessagesDequeueResponse. * @@ -22,7 +22,7 @@ public final class MessagesDequeueResponse extends ResponseBase value, MessagesDequeueHeaders headers) { + public MessagesDequeueResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, List value, MessagesDequeueHeaders headers) { super(request, statusCode, rawHeaders, value, headers); } @@ -30,7 +30,7 @@ public MessagesDequeueResponse(HttpRequest request, int statusCode, HttpHeaders * @return the deserialized response body. */ @Override - public List value() { + public List value() { return super.value(); } } diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesPeekResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesPeekResponse.java index 8ca8ed06fd99c..27ac646138908 100644 --- a/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesPeekResponse.java +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesPeekResponse.java @@ -12,7 +12,7 @@ /** * Contains all response data for the peek operation. */ -public final class MessagesPeekResponse extends ResponseBase> { +public final class MessagesPeekResponse extends ResponseBase> { /** * Creates an instance of MessagesPeekResponse. * @@ -22,7 +22,7 @@ public final class MessagesPeekResponse extends ResponseBase value, MessagesPeekHeaders headers) { + public MessagesPeekResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, List value, MessagesPeekHeaders headers) { super(request, statusCode, rawHeaders, value, headers); } @@ -30,7 +30,7 @@ public MessagesPeekResponse(HttpRequest request, int statusCode, HttpHeaders raw * @return the deserialized response body. */ @Override - public List value() { + public List value() { return super.value(); } } diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/PeekedMessageItem.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/PeekedMessage.java similarity index 85% rename from storage/client/queue/src/main/java/com/azure/storage/queue/models/PeekedMessageItem.java rename to storage/client/queue/src/main/java/com/azure/storage/queue/models/PeekedMessage.java index d86bdab8c2305..edc9960d2d747 100644 --- a/storage/client/queue/src/main/java/com/azure/storage/queue/models/PeekedMessageItem.java +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/PeekedMessage.java @@ -1,6 +1,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -// Code generated by Microsoft (R) AutoRest Code Generator. package com.azure.storage.queue.models; @@ -14,7 +13,7 @@ * on a Queue. */ @JacksonXmlRootElement(localName = "QueueMessage") -public final class PeekedMessageItem { +public final class PeekedMessage { /* * The Id of the Message. */ @@ -58,9 +57,9 @@ public String messageId() { * Set the messageId property: The Id of the Message. * * @param messageId the messageId value to set. - * @return the PeekedMessageItem object itself. + * @return the PeekedMessage object itself. */ - public PeekedMessageItem messageId(String messageId) { + public PeekedMessage messageId(String messageId) { this.messageId = messageId; return this; } @@ -83,9 +82,9 @@ public OffsetDateTime insertionTime() { * the Queue. * * @param insertionTime the insertionTime value to set. - * @return the PeekedMessageItem object itself. + * @return the PeekedMessage object itself. */ - public PeekedMessageItem insertionTime(OffsetDateTime insertionTime) { + public PeekedMessage insertionTime(OffsetDateTime insertionTime) { if (insertionTime == null) { this.insertionTime = null; } else { @@ -112,9 +111,9 @@ public OffsetDateTime expirationTime() { * and be automatically deleted. * * @param expirationTime the expirationTime value to set. - * @return the PeekedMessageItem object itself. + * @return the PeekedMessage object itself. */ - public PeekedMessageItem expirationTime(OffsetDateTime expirationTime) { + public PeekedMessage expirationTime(OffsetDateTime expirationTime) { if (expirationTime == null) { this.expirationTime = null; } else { @@ -138,9 +137,9 @@ public long dequeueCount() { * dequeued. * * @param dequeueCount the dequeueCount value to set. - * @return the PeekedMessageItem object itself. + * @return the PeekedMessage object itself. */ - public PeekedMessageItem dequeueCount(long dequeueCount) { + public PeekedMessage dequeueCount(long dequeueCount) { this.dequeueCount = dequeueCount; return this; } @@ -158,9 +157,9 @@ public String messageText() { * Set the messageText property: The content of the Message. * * @param messageText the messageText value to set. - * @return the PeekedMessageItem object itself. + * @return the PeekedMessage object itself. */ - public PeekedMessageItem messageText(String messageText) { + public PeekedMessage messageText(String messageText) { this.messageText = messageText; return this; } diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueProperties.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueProperties.java new file mode 100644 index 0000000000000..bb343ea96bd24 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueProperties.java @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue.models; + +import java.util.Map; + +/** + * Model class containing properties of a specific queue in the storage Queue service. + */ +public final class QueueProperties { + private final Map metadata; + private final int approximateMessagesCount; + + /** + * Creates an instance that contains properties of a queue. + * + * @param metadata Metadata associated with the queue + * @param approximateMessagesCount Approximate number of messages contained in the queue + */ + public QueueProperties(Map metadata, int approximateMessagesCount) { + this.metadata = metadata; + this.approximateMessagesCount = approximateMessagesCount; + } + + /** + * @return the user-defined metadata associated with the queue + */ + public Map metadata() { + return this.metadata; + } + + /** + * @return the approximate number of messages contained in the queue at the time of properties retrieval + */ + public int approximateMessagesCount() { + return approximateMessagesCount; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesSegmentOptions.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesSegmentOptions.java new file mode 100644 index 0000000000000..d58b2f71b8d05 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesSegmentOptions.java @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue.models; + +import com.azure.storage.queue.QueueServiceAsyncClient; +import com.azure.storage.queue.QueueServiceClient; + +/** + * A set of options for selecting queues from Storage Queue service. + * + *
    + *
  • + * Providing {@link QueuesSegmentOptions#prefix() prefix} will filter {@link QueueItem queues} that begin + * with the prefix. + *
  • + *
  • + * Providing {@link QueuesSegmentOptions#maxResults() maxResults} will limit the number of {@link QueueItem queues} + * returned in a single page. + *
  • + *
  • + * Setting {@link QueuesSegmentOptions#includeMetadata() includeMetadata} to true will include the metadata of + * each {@link QueueItem queue}, if false {@link QueueItem#metadata() metadata} for each queue will be {@code null}. + *
  • + *
+ * + * @see QueueServiceClient + * @see QueueServiceAsyncClient + */ +public final class QueuesSegmentOptions { + private boolean includeMetadata; + + private String prefix; + + private Integer maxResults; + + /** + * @return the status of including metadata when listing queues + */ + public boolean includeMetadata() { + return includeMetadata; + } + + /** + * Sets the status of including queue metadata when listing queues + * + * @param includeMetadata Flag indicating if metadata should be included in the listing + * @return An updated QueuesSegmentOptions object + */ + public QueuesSegmentOptions includeMetadata(boolean includeMetadata) { + this.includeMetadata = includeMetadata; + return this; + } + + /** + * @return the prefix the queue name must match to be included in the listing + */ + public String prefix() { + return prefix; + } + + /** + * Sets the prefix that a queue must match to be included in the listing + * + * @param prefix The prefix that queues must start with to pass the filter + * @return An updated QueuesSegmentOptions object + */ + public QueuesSegmentOptions prefix(String prefix) { + this.prefix = prefix; + return this; + } + + /** + * @return the maximum number of queues to include in a single response + */ + public Integer maxResults() { + return maxResults; + } + + /** + * Sets the maximum number of queues to include in a single response + * + * @param maxResults Maximum number of results to include in a single response + * @return An updated QueuesSegmentOptions object + */ + public QueuesSegmentOptions maxResults(Integer maxResults) { + this.maxResults = maxResults; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/UpdatedMessage.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/UpdatedMessage.java new file mode 100644 index 0000000000000..fa6a4d5970153 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/UpdatedMessage.java @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue.models; + +import java.time.OffsetDateTime; + +/** + * Response from the service when updating a message. Contains the information needed to continue working with + * the specific message. + */ +public final class UpdatedMessage { + private final String popReceipt; + private final OffsetDateTime timeNextVisible; + + /** + * Creates an instance of updated message information. + * + * @param popReceipt Unique identifier that verifies the operation on a message is valid + * @param timeNextVisible The next time the message will be visible to other operations in the queue + */ + public UpdatedMessage(String popReceipt, OffsetDateTime timeNextVisible) { + this.popReceipt = popReceipt; + this.timeNextVisible = timeNextVisible; + } + + /** + * @return the unique identifier used to verify that the operation is allowed on the message + */ + public String popReceipt() { + return popReceipt; + } + + /** + * @return the next time the message will be visible to other operations in the queue + */ + public OffsetDateTime timeNextVisible() { + return timeNextVisible; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/package-info.java b/storage/client/queue/src/main/java/com/azure/storage/queue/package-info.java new file mode 100644 index 0000000000000..e6671d8292fac --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/package-info.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/** + * This package contains the classes to perform actions on Azure Storage Queue. + */ +package com.azure.storage.queue; diff --git a/storage/client/queue/src/samples/java/com/azure/storage/queue/AsyncSamples.java b/storage/client/queue/src/samples/java/com/azure/storage/queue/AsyncSamples.java new file mode 100644 index 0000000000000..39cc17db37ca2 --- /dev/null +++ b/storage/client/queue/src/samples/java/com/azure/storage/queue/AsyncSamples.java @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.queue; + +import static com.azure.storage.queue.SampleHelper.generateRandomName; + +/* + * This example mimics some arbitrary number of clients continuously sending messages up to a queue in a parallel and + * a server dequeuing the messages and processing them. + */ +public class AsyncSamples { + private static final String ACCOUNT_NAME = System.getenv("AZURE_STORAGE_ACCOUNT_NAME"); + private static final String SAS_TOKEN = System.getenv("PRIMARY_SAS_TOKEN"); + private static final String QUEUE_NAME = generateRandomName("async-call", 16); + + /** + * The main method shows how we do the basic operations of enqueueing and dequeueing messages on async queue client. + * @param args No args needed for main method. + */ + public static void main(String[] args) { + // Create an async queue client. + String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", ACCOUNT_NAME, QUEUE_NAME, SAS_TOKEN); + QueueAsyncClient queueAsyncClient = new QueueClientBuilder().endpoint(queueURL).buildAsyncClient(); + + // Create a queue, enqueue two messages. + queueAsyncClient.create() + .doOnSuccess(response -> queueAsyncClient.enqueueMessage("This is message 1")) + .then(queueAsyncClient.enqueueMessage("This is message 2")) + .subscribe( + response -> { + System.out.println("Message successfully equeueed by queueAsyncClient. Message id:" + response.value().messageId()); + }, + err -> { + System.out.println("Error thrown when enqueue the message. Error message: " + err.getMessage()); + }, + () -> { + System.out.println("The enqueue has been completed."); + } + ); + } +} diff --git a/storage/client/queue/src/samples/java/com/azure/storage/queue/MessageSamples.java b/storage/client/queue/src/samples/java/com/azure/storage/queue/MessageSamples.java new file mode 100644 index 0000000000000..1372d45b9e808 --- /dev/null +++ b/storage/client/queue/src/samples/java/com/azure/storage/queue/MessageSamples.java @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.queue; + +import com.azure.core.http.rest.Response; +import com.azure.storage.queue.models.DequeuedMessage; + +import java.time.Duration; + +import static com.azure.storage.queue.SampleHelper.generateRandomName; + +public class MessageSamples { + private static final String ACCOUNT_NAME = System.getenv("AZURE_STORAGE_ACCOUNT_NAME"); + private static final String SAS_TOKEN = System.getenv("PRIMARY_SAS_TOKEN"); + + /** + * The main method illustrate the basic operations for enqueue and dequeue messages using sync client. + * @param args No args needed for main method. + * @throws InterruptedException If the Thread.sleep operation gets interrupted. + */ + public static void main(String[] args) throws InterruptedException { + // Build Queue Client using SAS Token + String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", ACCOUNT_NAME, SAS_TOKEN); + QueueServiceClient queueServiceClient = new QueueServiceClientBuilder().endpoint(queueServiceURL).buildClient(); + + // Create a queue client + Response queueClientResponse = queueServiceClient.createQueue(generateRandomName("enqueue", 16)); + QueueClient queueClient = queueClientResponse.value(); + // Using queue client to enqueue several "Hello World" messages into queue. + for (int i = 0; i < 3; i++) { + queueClient.enqueueMessage("Hello World"); + } + + // Enqueue json file into message. + // TODO + + // Get the total count of msg in the queue + int count = queueClient.getProperties().value().approximateMessagesCount(); + + // Peek all messages in queue. It is supposed to print "Hello World" 3 times. + queueClient.peekMessages(count).forEach( + peekedMessage -> { + System.out.println("Here is the msg: " + peekedMessage.messageText()); + } + ); + + // Dequeue all messages in queue and update the message "Hello World" to Hello, world!" + queueClient.dequeueMessages(count, Duration.ZERO).forEach( + queueMessage -> { + String msgToReplace = String.format("Hello, world!"); + queueClient.updateMessage(queueMessage.messageId(), msgToReplace, queueMessage.popReceipt(), Duration.ZERO); + } + ); + + // Delete the first available msg. + // Since there is no invisible time for above dequeue, the following if condition should be true. + if (queueClient.dequeueMessages().iterator().hasNext()) { + DequeuedMessage queueMessage = queueClient.dequeueMessages().iterator().next(); + queueClient.deleteMessage(queueMessage.messageId(), queueMessage.popReceipt()); + } else { + System.out.println("OOps, the messages disappear!"); + } + + // Clear all messages in the queue + // Sleep to guarantee we skip the default invisible time. + Thread.sleep(500); + queueClient.clearMessages(); + + // Finally, we delete the queue. + queueClient.delete(); + } +} diff --git a/storage/client/queue/src/samples/java/com/azure/storage/queue/QueueExceptionSamples.java b/storage/client/queue/src/samples/java/com/azure/storage/queue/QueueExceptionSamples.java new file mode 100644 index 0000000000000..d0ee4c8f2aed4 --- /dev/null +++ b/storage/client/queue/src/samples/java/com/azure/storage/queue/QueueExceptionSamples.java @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.queue; + +import com.azure.core.http.rest.Response; +import com.azure.storage.queue.models.StorageErrorCode; +import com.azure.storage.queue.models.StorageErrorException; + +import static com.azure.storage.queue.SampleHelper.generateRandomName; + +public class QueueExceptionSamples { + private static final String ACCOUNT_NAME = System.getenv("AZURE_STORAGE_ACCOUNT_NAME"); + private static final String SAS_TOKEN = System.getenv("PRIMARY_SAS_TOKEN"); + + /** + * The main method shows how to handle the storage exception. + * @param args No args needed for the main method. + * @throws RuntimeException If queueServiceClient failed to create a queue. + */ + public static void main(String[] args) { + // Create a queue service client. + String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", ACCOUNT_NAME, SAS_TOKEN); + QueueServiceClient queueServiceClient = new QueueServiceClientBuilder().endpoint(queueServiceURL).buildClient(); + + // Create queue client. + Response queueClientResponse; + try { + queueClientResponse = queueServiceClient.createQueue(generateRandomName("delete-not-exist", 16)); + System.out.println("Successfully create the queue! Status code: " + String.valueOf(queueClientResponse.statusCode())); + } catch (StorageErrorException e) { + System.out.println(String.format("Error creating a queue. Error message: %s", e.value().message())); + throw new RuntimeException(e); + } + QueueClient queueClient = queueClientResponse.value(); + queueClient.enqueueMessage("Hello, message 1!"); + queueClient.enqueueMessage("Hello, message 2!"); + + // Delete message with wrong message id. + try { + queueClientResponse.value().dequeueMessages().forEach( + msg -> { + queueClient.deleteMessage("wrong id", msg.popReceipt()); + } + ); + } catch (StorageErrorException e) { + if (e.getMessage().contains(StorageErrorCode.MESSAGE_NOT_FOUND.toString())) { + System.out.println("This is the error expected to throw"); + } else { + System.out.println("This is not the error we expect!"); + } + } + + // Delete message with wrong pop receipt. + try { + queueClient.dequeueMessages().forEach( + msg -> { + queueClient.deleteMessage(msg.messageId(), "Wrong Pop Receipt"); + } + ); + } catch (StorageErrorException e) { + if (e.getMessage().contains(StorageErrorCode.INVALID_QUERY_PARAMETER_VALUE.toString())) { + System.out.println("This is the error expected to throw"); + } else { + System.out.println("This is not the error we expect!"); + } + } + } +} diff --git a/storage/client/queue/src/samples/java/com/azure/storage/queue/QueueServiceSamples.java b/storage/client/queue/src/samples/java/com/azure/storage/queue/QueueServiceSamples.java new file mode 100644 index 0000000000000..ed1a9875a3d03 --- /dev/null +++ b/storage/client/queue/src/samples/java/com/azure/storage/queue/QueueServiceSamples.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.queue; + +import static com.azure.storage.queue.SampleHelper.generateRandomName; + +public class QueueServiceSamples { + private static final String ACCOUNT_NAME = System.getenv("AZURE_STORAGE_ACCOUNT_NAME"); + private static final String SAS_TOKEN = System.getenv("PRIMARY_SAS_TOKEN"); + + /** + * The main method illustrated the basic operations of creating and deleting queues using queue service sync client. + * @param args No args needed for main method. + */ + public static void main(String[] args) { + // Build Queue Service Client using SAS Token + String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", ACCOUNT_NAME, SAS_TOKEN); + QueueServiceClient queueServiceClient = new QueueServiceClientBuilder().endpoint(queueServiceURL).buildClient(); + queueServiceClient.createQueue(generateRandomName("create-queue", 16)); + + // Create another queue and list all queues, print the name and then delete the queue. + queueServiceClient.createQueue(generateRandomName("create-extra", 16)); + queueServiceClient.listQueues().forEach( + queueItem -> { + System.out.println("The queue name is: " + queueItem.name()); + queueServiceClient.deleteQueue(queueItem.name()); + } + ); + } +} diff --git a/storage/client/queue/src/samples/java/com/azure/storage/queue/SampleHelper.java b/storage/client/queue/src/samples/java/com/azure/storage/queue/SampleHelper.java new file mode 100644 index 0000000000000..094a52026ffe6 --- /dev/null +++ b/storage/client/queue/src/samples/java/com/azure/storage/queue/SampleHelper.java @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.queue; + +import java.util.UUID; + +class SampleHelper { + static String generateRandomName(String prefix, int length) { + int len = length > prefix.length() ? length - prefix.length() : 0; + return prefix + UUID.randomUUID().toString().substring(0, len); + } +} diff --git a/storage/client/queue/src/samples/java/com/azure/storage/queue/javadoc/QueueJavaDocCodeSamples.java b/storage/client/queue/src/samples/java/com/azure/storage/queue/javadoc/QueueJavaDocCodeSamples.java new file mode 100644 index 0000000000000..24b0405a49350 --- /dev/null +++ b/storage/client/queue/src/samples/java/com/azure/storage/queue/javadoc/QueueJavaDocCodeSamples.java @@ -0,0 +1,668 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue.javadoc; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.common.credentials.SASTokenCredential; +import com.azure.storage.common.credentials.SharedKeyCredential; +import com.azure.storage.queue.QueueAsyncClient; +import com.azure.storage.queue.QueueClient; +import com.azure.storage.queue.QueueClientBuilder; +import com.azure.storage.queue.models.AccessPolicy; +import com.azure.storage.queue.models.DequeuedMessage; +import com.azure.storage.queue.models.EnqueuedMessage; +import com.azure.storage.queue.models.QueueProperties; +import com.azure.storage.queue.models.SignedIdentifier; +import com.azure.storage.queue.models.UpdatedMessage; +import java.time.Duration; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * Contains code snippets when generating javadocs through doclets for {@link QueueClient} and {@link QueueAsyncClient}. + */ + +public class QueueJavaDocCodeSamples { + /** + * Generates code sample for creating a {@link QueueClient}. + */ + public void buildQueueClient() { + // BEGIN: com.azure.storage.queue.queueClient.instantiation + QueueClient client = new QueueClientBuilder() + .connectionString("connectionstring") + .endpoint("endpoint") + .buildClient(); + // END: com.azure.storage.queue.queueClient.instantiation + } + + /** + * Generates code sample for creating a {@link QueueAsyncClient}. + */ + public void buildQueueAsyncClient() { + // BEGIN: com.azure.storage.queue.queueAsyncClient.instantiation + QueueAsyncClient client = new QueueClientBuilder() + .connectionString("connectionstring") + .endpoint("endpoint") + .buildAsyncClient(); + // END: com.azure.storage.queue.queueAsyncClient.instantiation + } + + /** + * Generates code sample for creating a {@link QueueClient} with {@link QueueClient} + * @return An instance of {@link QueueClient} + */ + public QueueClient createClientWithSASToken() { + // BEGIN: com.azure.storage.queue.queueClient.instantiation.sastoken + QueueClient queueClient = new QueueClientBuilder() + .endpoint("https://${accountName}.queue.core.windows.net?${SASToken}") + .buildClient(); + // END: com.azure.storage.queue.queueClient.instantiation.sastoken + return queueClient; + } + + /** + * Generates code sample for creating a {@link QueueAsyncClient} with {@link SASTokenCredential} + * @return An instance of {@link QueueAsyncClient} + */ + public QueueAsyncClient createAsyncClientWithSASToken() { + // BEGIN: com.azure.storage.queue.queueAsyncClient.instantiation.sastoken + QueueAsyncClient queueAsyncClient = new QueueClientBuilder() + .endpoint("https://{accountName}.queue.core.windows.net?{SASToken}") + .buildAsyncClient(); + // END: com.azure.storage.queue.queueAsyncClient.instantiation.sastoken + return queueAsyncClient; + } + + /** + * Generates code sample for creating a {@link QueueClient} with {@link SASTokenCredential} + * @return An instance of {@link QueueClient} + */ + public QueueClient createClientWithCredential() { + // BEGIN: com.azure.storage.queue.queueClient.instantiation.credential + QueueClient queueClient = new QueueClientBuilder() + .endpoint("https://${accountName}.queue.core.windows.net") + .queueName("myqueue") + .credential(SASTokenCredential.fromQuery("{SASTokenQueryParams}")) + .buildClient(); + // END: com.azure.storage.queue.queueClient.instantiation.credential + return queueClient; + } + + /** + * Generates code sample for creating a {@link QueueAsyncClient} with {@link SASTokenCredential} + * @return An instance of {@link QueueAsyncClient} + */ + public QueueAsyncClient createAsyncClientWithCredential() { + // BEGIN: com.azure.storage.queue.queueAsyncClient.instantiation.credential + QueueAsyncClient queueAsyncClient = new QueueClientBuilder() + .endpoint("https://{accountName}.queue.core.windows.net") + .queueName("myqueue") + .credential(SASTokenCredential.fromQuery("{SASTokenQueryParams}")) + .buildAsyncClient(); + // END: com.azure.storage.queue.queueAsyncClient.instantiation.credential + return queueAsyncClient; + } + + /** + * Generates code sample for creating a {@link QueueClient} with {@code connectionString} which turns into {@link SharedKeyCredential} + * @return An instance of {@link QueueClient} + */ + public QueueClient createClientWithConnectionString() { + // BEGIN: com.azure.storage.queue.queueClient.instantiation.connectionstring + String connectionString = "DefaultEndpointsProtocol=https;AccountName={name};" + + "AccountKey={key};EndpointSuffix={core.windows.net}"; + QueueClient queueClient = new QueueClientBuilder() + .connectionString(connectionString) + .buildClient(); + // END: com.azure.storage.queue.queueClient.instantiation.connectionstring + return queueClient; + } + + /** + * Generates code sample for creating a {@link QueueAsyncClient} with {@code connectionString} which turns into {@link SharedKeyCredential} + * @return An instance of {@link QueueAsyncClient} + */ + public QueueAsyncClient createAsyncClientWithConnectionString() { + // BEGIN: com.azure.storage.queue.queueAsyncClient.instantiation.connectionstring + String connectionString = "DefaultEndpointsProtocol=https;AccountName={name};" + + "AccountKey={key};EndpointSuffix={core.windows.net}"; + QueueAsyncClient queueAsyncClient = new QueueClientBuilder() + .connectionString(connectionString) + .buildAsyncClient(); + // END: com.azure.storage.queue.queueAsyncClient.instantiation.connectionstring + return queueAsyncClient; + } + + /** + * Generates a code sample for using {@link QueueClient#create()} + */ + public void createQueue() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.create + VoidResponse response = queueClient.create(); + System.out.println("Complete creating queue with status code: " + response.statusCode()); + // END: com.azure.storage.queue.queueClient.create + } + + /** + * Generates a code sample for using {@link QueueAsyncClient#create()} + */ + public void createQueueAsync() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.create + queueAsyncClient.create().subscribe( + response -> { }, + error -> System.err.print(error.toString()), + () -> System.out.println("Complete creating the queue!") + ); + // END: com.azure.storage.queue.queueAsyncClient.create + } + + /** + * Generates a code sample for using {@link QueueClient#create(Map)} + */ + public void createQueueMaxOverload() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.create#map + VoidResponse response = queueClient.create(Collections.singletonMap("queue", "metadataMap")); + System.out.println("Complete creating queue with status code: " + response.statusCode()); + // END: com.azure.storage.queue.queueClient.create#map + } + + /** + * Generates a code sample for using {@link QueueAsyncClient#create(Map)} + */ + public void createQueueAsyncMaxOverload() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.create#map + queueAsyncClient.create(Collections.singletonMap("queue", "metadataMap")).subscribe( + response -> { }, + error -> System.err.print(error.toString()), + () -> System.out.println("Complete creating the queue!") + ); + // END: com.azure.storage.queue.queueAsyncClient.create#map + } + + /** + * Generates a code sample for using {@link QueueClient#enqueueMessage(String)} + */ + public void enqueueMessage() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.enqueueMessage#string + Response response = queueClient.enqueueMessage("hello msg"); + System.out.println("Complete enqueuing the message with status code: " + response.statusCode()); + // END: com.azure.storage.queue.queueClient.enqueueMessage#string + } + + /** + * Generates a code sample for using {@link QueueAsyncClient#enqueueMessage(String)} + */ + public void enqueueMessageAsync() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.enqueueMessage#string + queueAsyncClient.enqueueMessage("Hello, Azure").subscribe( + response -> { }, + error -> System.err.print(error.toString()), + () -> System.out.println("Complete enqueuing the message!") + ); + // END: com.azure.storage.queue.queueAsyncClient.enqueueMessage#string + } + + /** + * Generates a code sample for using {@link QueueClient#enqueueMessage(String, Duration, Duration)} + */ + public void enqueueMessageWithTimeoutOverload() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.enqueueMessage#string-duration-duration + EnqueuedMessage enqueuedMessage = queueClient.enqueueMessage("Hello, Azure", + Duration.ofSeconds(5), null).value(); + System.out.printf("Message %s expires at %s", enqueuedMessage.messageId(), enqueuedMessage.expirationTime()); + // END: com.azure.storage.queue.queueClient.enqueueMessage#string-duration-duration + } + + /** + * Generates a code sample for using {@link QueueAsyncClient#enqueueMessage(String, Duration, Duration)} + */ + public void enqueueMessageAsyncWithTimeoutOverload() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.enqueueMessage#string-duration-duration + queueAsyncClient.enqueueMessage("Hello, Azure", + Duration.ofSeconds(5), null).subscribe( + response -> System.out.printf("Message %s expires at %s", response.value().messageId(), + response.value().expirationTime()), + error -> System.err.print(error.toString()), + () -> System.out.println("Complete enqueuing the message!") + ); + // END: com.azure.storage.queue.queueAsyncClient.enqueueMessage#string-duration-duration + } + + /** + * Generates a code sample for using {@link QueueClient#enqueueMessage(String, Duration, Duration)} + */ + public void enqueueMessageWithLiveTimeOverload() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.enqueueMessageLiveTime#string-duration-duration + EnqueuedMessage enqueuedMessage = queueClient.enqueueMessage("Goodbye, Azure", + null, Duration.ofSeconds(5)).value(); + System.out.printf("Message %s expires at %s", enqueuedMessage.messageId(), enqueuedMessage.expirationTime()); + // END: com.azure.storage.queue.queueClient.enqueueMessageLiveTime#string-duration-duration + } + + /** + * Generates a code sample for using {@link QueueAsyncClient#enqueueMessage(String, Duration, Duration)} + */ + public void enqueueMessageAsyncWithLiveTimeOverload() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.enqueueMessageLiveTime#string-duration-duration + queueAsyncClient.enqueueMessage("Goodbye, Azure", + null, Duration.ofSeconds(5)).subscribe( + response -> System.out.printf("Message %s expires at %s", response.value().messageId(), + response.value().expirationTime()), + error -> System.err.print(error.toString()), + () -> System.out.println("Complete enqueuing the message!") + ); + // END: com.azure.storage.queue.queueAsyncClient.enqueueMessageLiveTime#string-duration-duration + } + + /** + * Generates a code sample for using {@link QueueClient#dequeueMessages()} + */ + public void dequeueMessage() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.dequeueMessages + queueClient.dequeueMessages().forEach( + dequeuedMessage -> { + System.out.println("Complete dequeuing the message: " + dequeuedMessage.messageText()); + } + ); + // END: com.azure.storage.queue.queueClient.dequeueMessages + } + + + /** + * Generates a code sample for using {@link QueueAsyncClient#dequeueMessages()} + */ + public void dequeueMessageAsync() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.dequeueMessages + queueAsyncClient.dequeueMessages().subscribe( + dequeuedMessage -> System.out.println("The message got from dequeue operation: " + + dequeuedMessage.messageText()), + error -> System.err.print(error.toString()), + () -> System.out.println("Complete dequeuing the message!") + ); + // END: com.azure.storage.queue.queueAsyncClient.dequeueMessages + } + + /** + * Generates a code sample for using {@link QueueClient#dequeueMessages(Integer)} + */ + public void dequeueMessageWithOverload() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.dequeueMessages#integer + for (DequeuedMessage dequeuedMessage : queueClient.dequeueMessages(5)) { + System.out.printf("Dequeued %s and it becomes visible at %s", + dequeuedMessage.messageId(), dequeuedMessage.timeNextVisible()); + } + // END: com.azure.storage.queue.queueClient.dequeueMessages#integer + } + + /** + * Generates a code sample for using {@link QueueAsyncClient#dequeueMessages(Integer)} + */ + public void dequeueMessageAsyncWithOverload() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.dequeueMessages#integer + queueAsyncClient.dequeueMessages(5).subscribe( + dequeuedMessage -> System.out.println("The message got from dequeue operation: " + + dequeuedMessage.messageText()), + error -> System.err.print(error.toString()), + () -> System.out.println("Complete dequeuing the message!") + ); + // END: com.azure.storage.queue.queueAsyncClient.dequeueMessages#integer + } + + /** + * Generates a code sample for using {@link QueueClient#dequeueMessages(Integer, Duration)} + */ + public void dequeueMessageMaxOverload() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.dequeueMessages#integer-duration + for (DequeuedMessage dequeuedMessage : queueClient.dequeueMessages(5, Duration.ofSeconds(60))) { + System.out.printf("Dequeued %s and it becomes visible at %s", + dequeuedMessage.messageId(), dequeuedMessage.timeNextVisible()); + } + // END: com.azure.storage.queue.queueClient.dequeueMessages#integer-duration + } + + /** + * Generates a code sample for using {@link QueueAsyncClient#dequeueMessages(Integer, Duration)} + */ + public void dequeueMessageAsyncMaxOverload() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.dequeueMessages#integer-duration + queueAsyncClient.dequeueMessages(5, Duration.ofSeconds(60)).subscribe( + dequeuedMessage -> System.out.println("The message got from dequeue operation: " + + dequeuedMessage.messageText()), + error -> System.err.print(error.toString()), + () -> System.out.println("Complete dequeuing the message!") + ); + // END: com.azure.storage.queue.queueAsyncClient.dequeueMessages#integer-duration + } + + /** + * Generates a code sample for using {@link QueueClient#peekMessages()} + */ + public void peekMessage() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.peekMessages + queueClient.peekMessages().forEach( + peekedMessage -> { + System.out.println("Complete peeking the message: " + peekedMessage.messageText()); + } + ); + // END: com.azure.storage.queue.queueClient.peekMessages + } + + + /** + * Generates a code sample for using {@link QueueAsyncClient#peekMessages()} + */ + public void peekMessageAsync() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.peekMessages + queueAsyncClient.peekMessages().subscribe( + peekMessages -> System.out.println("The message got from peek operation: " + peekMessages.messageText()), + error -> System.err.print(error.toString()), + () -> System.out.println("Complete peeking the message!") + ); + // END: com.azure.storage.queue.queueAsyncClient.peekMessages + } + + /** + * Generates a code sample for using {@link QueueClient#peekMessages(Integer)} + */ + public void peekMessageMaxOverload() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.peekMessages#integer + queueClient.peekMessages(5).forEach( + peekMessage -> System.out.printf("Peeked message %s has been dequeued %d times", + peekMessage.messageId(), peekMessage.dequeueCount()) + ); + // END: com.azure.storage.queue.queueClient.peekMessages#integer + } + + + /** + * Generates a code sample for using {@link QueueAsyncClient#peekMessages(Integer)} + */ + public void peekMessageAsyncMaxOverload() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.peekMessages#integer + queueAsyncClient.peekMessages(5).subscribe( + peekMessage -> System.out.printf("Peeked message %s has been dequeued %d times", + peekMessage.messageId(), peekMessage.dequeueCount()), + error -> System.err.print(error.toString()), + () -> System.out.println("Complete peeking the message!") + ); + // END: com.azure.storage.queue.queueAsyncClient.peekMessages#integer + } + + /** + * Generates a code sample for using {@link QueueClient#updateMessage(String, String, String, Duration)} + */ + public void updateMessage() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.updateMessage + queueClient.dequeueMessages().forEach( + dequeuedMessage -> { + Response response = queueClient.updateMessage("newText", + dequeuedMessage.messageId(), dequeuedMessage.popReceipt(), null); + System.out.println("Complete updating the message with status code " + response.statusCode()); + } + ); + // END: com.azure.storage.queue.queueClient.updateMessage + } + + + /** + * Generates a code sample for using {@link QueueAsyncClient#updateMessage(String, String, String, Duration)} + */ + public void updateMessageAsync() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.updateMessage + queueAsyncClient.dequeueMessages().subscribe( + dequeuedMessage -> { + queueAsyncClient.updateMessage("newText", dequeuedMessage.messageId(), + dequeuedMessage.popReceipt(), null).subscribe( + response -> { }, + updateError -> System.err.print(updateError.toString()), + () -> System.out.println("Complete updating the message!") + ); + }, + dequeueError -> System.err.print(dequeueError.toString()), + () -> System.out.println("Complete dequeueing the message!") + ); + // END: com.azure.storage.queue.queueAsyncClient.updateMessage + } + + /** + * Generates a code sample for using {@link QueueClient#deleteMessage(String, String)} + */ + public void deleteMessage() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.deleteMessage + queueClient.dequeueMessages().forEach( + dequeuedMessage -> { + VoidResponse response = queueClient.deleteMessage(dequeuedMessage.messageId(), + dequeuedMessage.popReceipt()); + System.out.println("Complete deleting the message with status code " + response.statusCode()); + } + ); + // END: com.azure.storage.queue.queueClient.deleteMessage + } + + + /** + * Generates a code sample for using {@link QueueAsyncClient#deleteMessage(String, String)} + */ + public void deleteMessageAsync() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.deleteMessage + queueAsyncClient.dequeueMessages().subscribe( + dequeuedMessage -> { + queueAsyncClient.deleteMessage(dequeuedMessage.messageId(), dequeuedMessage.popReceipt()).subscribe( + response -> { }, + deleteError -> System.err.print(deleteError.toString()), + () -> System.out.println("Complete deleting the message!") + ); + }, + dequeueError -> System.err.print(dequeueError.toString()), + () -> System.out.println("Complete dequeueing the message!") + ); + // END: com.azure.storage.queue.queueAsyncClient.deleteMessage + } + + /** + * Generates a code sample for using {@link QueueClient#delete()} + */ + public void deleteQueue() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.delete + VoidResponse response = queueClient.delete(); + System.out.println("Complete deleting the queue with status code: " + response.statusCode()); + // END: com.azure.storage.queue.queueClient.delete + } + + + /** + * Generates a code sample for using {@link QueueAsyncClient#delete()} + */ + public void deleteQueueAsync() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.delete + queueAsyncClient.delete().subscribe( + response -> System.out.println("Deleting the queue completed with status code: " + response.statusCode()) + ); + // END: com.azure.storage.queue.queueAsyncClient.delete + } + + /** + * Generates a code sample for using {@link QueueClient#getProperties()} + */ + public void getProperties() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.getProperties + QueueProperties properties = queueClient.getProperties().value(); + System.out.printf("Metadata: %s, Approximate message count: %d", properties.metadata(), + properties.approximateMessagesCount()); + // END: com.azure.storage.queue.queueClient.getProperties + } + + /** + * Generates a code sample for using {@link QueueAsyncClient#getProperties()} + */ + public void getPropertiesAsync() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.getProperties + queueAsyncClient.getProperties() + .subscribe(response -> { + QueueProperties properties = response.value(); + System.out.printf("Metadata: %s, Approximate message count: %d", properties.metadata(), + properties.approximateMessagesCount()); + }); + // END: com.azure.storage.queue.queueAsyncClient.getProperties + } + + /** + * Generate a code sample for using {@link QueueClient#setMetadata(Map)} to set metadata. + */ + public void setMetadata() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.setMetadata#map + VoidResponse response = queueClient.setMetadata(Collections.singletonMap("queue", "metadataMap")); + System.out.printf("Setting metadata completed with status code %d", response.statusCode()); + // END: com.azure.storage.queue.queueClient.setMetadata#map + } + + /** + * Generate a code sample for using {@link QueueAsyncClient#setMetadata(Map)} to set metadata. + */ + public void setMetadataAsync() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.setMetadata#map + queueAsyncClient.setMetadata(Collections.singletonMap("queue", "metadataMap")) + .subscribe(response -> System.out.printf("Setting metadata completed with status code %d", + response.statusCode())); + // END: com.azure.storage.queue.queueAsyncClient.setMetadata#map + } + + /** + * Generate a code sample for using {@link QueueClient#setMetadata(Map)} to clear metadata. + */ + public void clearMetadata() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.clearMetadata#map + VoidResponse response = queueClient.setMetadata(null); + System.out.printf("Clearing metadata completed with status code %d", response.statusCode()); + // END: com.azure.storage.queue.queueClient.clearMetadata#map + } + + /** + * Generate a code sample for using {@link QueueAsyncClient#setMetadata(Map)} to clear metadata. + */ + public void clearMetadataAsync() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.clearMetadata#map + queueAsyncClient.setMetadata(null) + .subscribe(response -> System.out.printf("Clearing metadata completed with status code %d", + response.statusCode())); + // END: com.azure.storage.queue.queueAsyncClient.clearMetadata#map + } + + /** + * Generates a code sample for using {@link QueueClient#getAccessPolicy()} + */ + public void getAccessPolicy() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.getAccessPolicy + for (SignedIdentifier permission : queueClient.getAccessPolicy()) { + System.out.printf("Access policy %s allows these permissions: %s", permission.id(), + permission.accessPolicy().permission()); + } + // END: com.azure.storage.queue.queueClient.getAccessPolicy + } + + /** + * Generates a code sample for using {@link QueueAsyncClient#getAccessPolicy()} + */ + public void getAccessPolicyAsync() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.getAccessPolicy + queueAsyncClient.getAccessPolicy() + .subscribe(result -> System.out.printf("Access policy %s allows these permissions: %s", + result.id(), result.accessPolicy().permission())); + // END: com.azure.storage.queue.queueAsyncClient.getAccessPolicy + } + + /** + * Generates a code sample for using {@link QueueClient#setAccessPolicy(List)} + */ + public void setAccessPolicy() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.setAccessPolicy + AccessPolicy accessPolicy = new AccessPolicy().permission("r") + .start(OffsetDateTime.now(ZoneOffset.UTC)) + .expiry(OffsetDateTime.now(ZoneOffset.UTC).plusDays(10)); + SignedIdentifier permission = new SignedIdentifier().id("mypolicy").accessPolicy(accessPolicy); + VoidResponse response = queueClient.setAccessPolicy(Collections.singletonList(permission)); + System.out.printf("Setting access policies completed with status code %d", response.statusCode()); + // END: com.azure.storage.queue.queueClient.setAccessPolicy + } + + /** + * Generates a code sample for using {@link QueueAsyncClient#setAccessPolicy(List)} + */ + public void setAccessPolicyAsync() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.setAccessPolicy + AccessPolicy accessPolicy = new AccessPolicy().permission("r") + .start(OffsetDateTime.now(ZoneOffset.UTC)) + .expiry(OffsetDateTime.now(ZoneOffset.UTC).plusDays(10)); + + SignedIdentifier permission = new SignedIdentifier().id("mypolicy").accessPolicy(accessPolicy); + queueAsyncClient.setAccessPolicy(Collections.singletonList(permission)) + .subscribe(response -> System.out.printf("Setting access policies completed with status code %d", + response.statusCode())); + // END: com.azure.storage.queue.queueAsyncClient.setAccessPolicy + } + + /** + * Generates a code sample for using {@link QueueClient#clearMessages()} + */ + public void clearMessages() { + QueueClient queueClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueClient.clearMessages + VoidResponse response = queueClient.clearMessages(); + System.out.printf("Clearing messages completed with status code %d", response.statusCode()); + // END: com.azure.storage.queue.queueClient.clearMessages + } + + + /** + * Generates a code sample for using {@link QueueAsyncClient#clearMessages()} + */ + public void clearMessagesAsync() { + QueueAsyncClient queueAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueAsyncClient.clearMessages + queueAsyncClient.clearMessages().subscribe( + response -> System.out.println("Clearing messages completed with status code: " + response.statusCode()) + ); + // END: com.azure.storage.queue.queueAsyncClient.clearMessages + } + +} diff --git a/storage/client/queue/src/samples/java/com/azure/storage/queue/javadoc/QueueServiceJavaDocCodeSamples.java b/storage/client/queue/src/samples/java/com/azure/storage/queue/javadoc/QueueServiceJavaDocCodeSamples.java new file mode 100644 index 0000000000000..3ed03621fbf76 --- /dev/null +++ b/storage/client/queue/src/samples/java/com/azure/storage/queue/javadoc/QueueServiceJavaDocCodeSamples.java @@ -0,0 +1,369 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue.javadoc; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.common.credentials.SASTokenCredential; +import com.azure.storage.common.credentials.SharedKeyCredential; +import com.azure.storage.queue.QueueClient; +import com.azure.storage.queue.QueueServiceAsyncClient; +import com.azure.storage.queue.QueueServiceClient; +import com.azure.storage.queue.QueueServiceClientBuilder; +import com.azure.storage.queue.models.QueuesSegmentOptions; +import com.azure.storage.queue.models.StorageServiceProperties; +import com.azure.storage.queue.models.StorageServiceStats; +import java.util.Collections; +import java.util.Map; + +/** + * Contains code snippets when generating javadocs through doclets for {@link QueueServiceClient} and {@link QueueServiceAsyncClient}. + */ +public class QueueServiceJavaDocCodeSamples { + /** + * Generates code sample for creating a {@link QueueServiceClient}. + */ + public void buildQueueServiceClient() { + // BEGIN: com.azure.storage.queue.queueServiceClient.instantiation + QueueServiceClient client = new QueueServiceClientBuilder() + .connectionString("connectionstring") + .endpoint("endpoint") + .buildClient(); + // END: com.azure.storage.queue.queueServiceClient.instantiation + } + + /** + * Generates code sample for creating a {@link QueueServiceAsyncClient}. + */ + public void buildQueueServiceAsyncClient() { + // BEGIN: com.azure.storage.queue.queueServiceAsyncClient.instantiation + QueueServiceAsyncClient client = new QueueServiceClientBuilder() + .connectionString("connectionstring") + .endpoint("endpoint") + .buildAsyncClient(); + // END: com.azure.storage.queue.queueServiceAsyncClient.instantiation + } + + /** + * Generates code sample for creating a {@link QueueServiceClient} with {@link SASTokenCredential} + * @return An instance of {@link QueueServiceClient} + */ + public QueueServiceClient createClientWithSASToken() { + // BEGIN: com.azure.storage.queue.queueServiceClient.instantiation.sastoken + QueueServiceClient queueServiceClient = new QueueServiceClientBuilder() + .endpoint("https://${accountName}.queue.core.windows.net?${SASToken}") + .buildClient(); + // END: com.azure.storage.queue.queueServiceClient.instantiation.sastoken + return queueServiceClient; + } + + /** + * Generates code sample for creating a {@link QueueServiceAsyncClient} with {@link SASTokenCredential} + * @return An instance of {@link QueueServiceAsyncClient} + */ + public QueueServiceAsyncClient createAsyncClientWithSASToken() { + // BEGIN: com.azure.storage.queue.queueServiceAsyncClient.instantiation.sastoken + QueueServiceAsyncClient queueServiceAsyncClient = new QueueServiceClientBuilder() + .endpoint("https://{accountName}.queue.core.windows.net?{SASToken}") + .buildAsyncClient(); + // END: com.azure.storage.queue.queueServiceAsyncClient.instantiation.sastoken + return queueServiceAsyncClient; + } + + /** + * Generates code sample for creating a {@link QueueServiceClient} with {@link SASTokenCredential} + * @return An instance of {@link QueueServiceClient} + */ + public QueueServiceClient createClientWithCredential() { + // BEGIN: com.azure.storage.queue.queueServiceClient.instantiation.credential + QueueServiceClient queueServiceClient = new QueueServiceClientBuilder() + .endpoint("https://${accountName}.queue.core.windows.net") + .credential(SASTokenCredential.fromQuery("{SASTokenQueryParams}")) + .buildClient(); + // END: com.azure.storage.queue.queueServiceClient.instantiation.credential + return queueServiceClient; + } + + /** + * Generates code sample for creating a {@link QueueServiceAsyncClient} with {@link SASTokenCredential} + * @return An instance of {@link QueueServiceAsyncClient} + */ + public QueueServiceAsyncClient createAsyncClientWithCredential() { + // BEGIN: com.azure.storage.queue.queueServiceAsyncClient.instantiation.credential + QueueServiceAsyncClient queueServiceAsyncClient = new QueueServiceClientBuilder() + .endpoint("https://{accountName}.queue.core.windows.net") + .credential(SASTokenCredential.fromQuery("{SASTokenQueryParams}")) + .buildAsyncClient(); + // END: com.azure.storage.queue.queueServiceAsyncClient.instantiation.credential + return queueServiceAsyncClient; + } + + /** + * Generates code sample for creating a {@link QueueServiceClient} with {@code connectionString} which turns into {@link SharedKeyCredential} + * @return An instance of {@link QueueServiceClient} + */ + public QueueServiceClient createClientWithConnectionString() { + // BEGIN: com.azure.storage.queue.queueServiceClient.instantiation.connectionstring + String connectionString = "DefaultEndpointsProtocol=https;AccountName={name};" + + "AccountKey={key};EndpointSuffix={core.windows.net}"; + QueueServiceClient queueServiceClient = new QueueServiceClientBuilder() + .connectionString(connectionString) + .buildClient(); + // END: com.azure.storage.queue.queueServiceClient.instantiation.connectionstring + return queueServiceClient; + } + + /** + * Generates code sample for creating a {@link QueueServiceAsyncClient} with {@code connectionString} which turns into {@link SharedKeyCredential} + * @return An instance of {@link QueueServiceAsyncClient} + */ + public QueueServiceAsyncClient createAsyncClientWithConnectionString() { + // BEGIN: com.azure.storage.queue.queueServiceAsyncClient.instantiation.connectionstring + String connectionString = "DefaultEndpointsProtocol=https;AccountName={name};" + + "AccountKey={key};EndpointSuffix={core.windows.net}"; + QueueServiceAsyncClient queueServiceAsyncClient = new QueueServiceClientBuilder() + .connectionString(connectionString) + .buildAsyncClient(); + // END: com.azure.storage.queue.queueServiceAsyncClient.instantiation.connectionstring + return queueServiceAsyncClient; + } + + /** + * Generates a code sample for using {@link QueueServiceClient#createQueue(String)} + */ + public void createQueue() { + QueueServiceClient queueServiceClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceClient.createQueue#string + Response response = queueServiceClient.createQueue("myqueue"); + System.out.println("Complete creating queue with status code: " + response.statusCode()); + // END: com.azure.storage.queue.queueServiceClient.createQueue#string + } + + /** + * Generates a code sample for using {@link QueueServiceAsyncClient#createQueue(String)} + */ + public void createQueueAsync() { + QueueServiceAsyncClient queueServiceAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceAsyncClient.createQueue#string + queueServiceAsyncClient.createQueue("myqueue").subscribe( + response -> { }, + error -> System.err.print(error.toString()), + () -> System.out.println("Complete creating the queue!") + ); + // END: com.azure.storage.queue.queueServiceAsyncClient.createQueue#string + } + + /** + * Generates a code sample for using {@link QueueServiceClient#createQueue(String, Map)} + */ + public void createQueueMaxOverload() { + QueueServiceClient queueServiceClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceClient.createQueue#string-map + Response response = queueServiceClient.createQueue("myqueue", + Collections.singletonMap("queue", "metadata")); + System.out.println("Complete creating queue with status code: " + response.statusCode()); + // END: com.azure.storage.queue.queueServiceClient.createQueue#string-map + } + + /** + * Generates a code sample for using {@link QueueServiceAsyncClient#createQueue(String, Map)} + */ + public void createQueueAsyncMaxOverload() { + QueueServiceAsyncClient queueServiceAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceAsyncClient.createQueue#string-map + queueServiceAsyncClient.createQueue("myqueue", Collections.singletonMap("queue", "metadata")) + .subscribe( + response -> System.out.printf("Creating the queue with status code %d", response.statusCode()), + error -> System.err.print(error.toString()), + () -> System.out.println("Complete creating the queue!") + ); + // END: com.azure.storage.queue.queueServiceAsyncClient.createQueue#string-map + } + + /** + * Generates a code sample for using {@link QueueServiceClient#listQueues()} + */ + public void listQueues() { + QueueServiceClient queueServiceClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceClient.listQueues + queueServiceClient.listQueues().forEach( + queueItem -> System.out.printf("Queue %s exists in the account", queueItem.name()) + ); + // END: com.azure.storage.queue.queueServiceClient.listQueues + } + + /** + * Generates a code sample for using {@link QueueServiceAsyncClient#listQueues()} + */ + public void listQueuesAsync() { + QueueServiceAsyncClient queueServiceAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceAsyncClient.listQueues + queueServiceAsyncClient.listQueues().subscribe( + queueItem -> System.out.printf("Queue %s exists in the account", queueItem.name()), + error -> System.err.print(error.toString()), + () -> System.out.println("Complete listing the queues!") + ); + // END: com.azure.storage.queue.queueServiceAsyncClient.listQueues + } + + /** + * Generates a code sample for using {@link QueueServiceClient#listQueues(QueuesSegmentOptions)} )} + */ + public void listQueuesWithOverload() { + QueueServiceClient queueServiceClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceClient.listQueues#queueSergmentOptions + queueServiceClient.listQueues(new QueuesSegmentOptions().prefix("azure")).forEach( + queueItem -> System.out.printf("Queue %s exists in the account and has metadata %s", + queueItem.name(), queueItem.metadata()) + ); + // END: com.azure.storage.queue.queueServiceClient.listQueues#queueSergmentOptions + } + + /** + * Generates a code sample for using {@link QueueServiceAsyncClient#listQueues(QueuesSegmentOptions)} + */ + public void listQueuesAsyncWithOverload() { + QueueServiceAsyncClient queueServiceAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceAsyncClient.listQueues#queueSergmentOptions + queueServiceAsyncClient.listQueues(new QueuesSegmentOptions().prefix("azure")).subscribe( + queueItem -> System.out.printf("Queue %s exists in the account and has metadata %s", + queueItem.name(), queueItem.metadata()), + error -> System.err.print(error.toString()), + () -> System.out.println("Complete listing the queues!") + ); + // END: com.azure.storage.queue.queueServiceAsyncClient.listQueues#queueSergmentOptions + } + + /** + * Generates a code sample for using {@link QueueServiceClient#deleteQueue(String)} + */ + public void deleteQueue() { + QueueServiceClient queueServiceClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceClient.deleteQueue#string + VoidResponse response = queueServiceClient.deleteQueue("myqueue"); + System.out.println("Complete deleting the queue with status code: " + response.statusCode()); + // END: com.azure.storage.queue.queueServiceClient.deleteQueue#string + } + + /** + * Generates a code sample for using {@link QueueServiceAsyncClient#deleteQueue(String)} + */ + public void deleteQueueAsync() { + QueueServiceAsyncClient queueServiceAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceAsyncClient.deleteQueue#string + queueServiceAsyncClient.deleteQueue("myshare").subscribe( + response -> System.out.println("Deleting the queue completed with status code: " + response.statusCode()) + ); + // END: com.azure.storage.queue.queueServiceAsyncClient.deleteQueue#string + } + + /** + * Generates a code sample for using {@link QueueServiceClient#getProperties()} + */ + public void getProperties() { + QueueServiceClient queueServiceClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceClient.getProperties + StorageServiceProperties properties = queueServiceClient.getProperties().value(); + System.out.printf("Hour metrics enabled: %b, Minute metrics enabled: %b", + properties.hourMetrics().enabled(), properties.minuteMetrics().enabled()); + // END: com.azure.storage.queue.queueServiceClient.getProperties + } + + /** + * Generates a code sample for using {@link QueueServiceAsyncClient#getProperties()} + */ + public void getPropertiesAsync() { + QueueServiceAsyncClient queueServiceAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceAsyncClient.getProperties + queueServiceAsyncClient.getProperties() + .subscribe(response -> { + StorageServiceProperties properties = response.value(); + System.out.printf("Hour metrics enabled: %b, Minute metrics enabled: %b", + properties.hourMetrics().enabled(), properties.minuteMetrics().enabled()); + }); + // END: com.azure.storage.queue.queueServiceAsyncClient.getProperties + } + + /** + * Generates a code sample for using {@link QueueServiceClient#setProperties(StorageServiceProperties)} + */ + public void setProperties() { + QueueServiceClient queueServiceClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceClient.setProperties#storageServiceProperties + StorageServiceProperties properties = queueServiceClient.getProperties().value(); + properties.cors(Collections.emptyList()); + + VoidResponse response = queueServiceClient.setProperties(properties); + System.out.printf("Setting Queue service properties completed with status code %d", response.statusCode()); + // END: com.azure.storage.queue.queueServiceClient.setProperties#storageServiceProperties + } + + /** + * Generates a code sample for using {@link QueueServiceAsyncClient#setProperties(StorageServiceProperties)} + */ + public void setPropertiesAsync() { + QueueServiceAsyncClient queueServiceAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceAsyncClient.setProperties#storageServiceProperties + StorageServiceProperties properties = queueServiceAsyncClient.getProperties().block().value(); + queueServiceAsyncClient.setProperties(properties) + .subscribe(response -> System.out.printf("Setting Queue service properties completed with status code %d", + response.statusCode())); + // END: com.azure.storage.queue.queueServiceAsyncClient.setProperties#storageServiceProperties + } + + /** + * Generates a code sample for using {@link QueueServiceClient#setProperties(StorageServiceProperties)} with metrics enabled. + */ + public void setPropertiesEnableMetrics() { + QueueServiceClient queueServiceClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceClient.setPropertiesEnableMetrics#storageServiceProperties + StorageServiceProperties properties = queueServiceClient.getProperties().value(); + properties.minuteMetrics().enabled(true); + properties.hourMetrics().enabled(true); + VoidResponse response = queueServiceClient.setProperties(properties); + System.out.printf("Setting Queue service properties completed with status code %d", response.statusCode()); + // END: com.azure.storage.queue.queueServiceClient.setPropertiesEnableMetrics#storageServiceProperties + } + + /** + * Generates a code sample for using {@link QueueServiceAsyncClient#setProperties(StorageServiceProperties)} with metrics enabled. + */ + public void setPropertiesAsyncEnableMetrics() { + QueueServiceAsyncClient queueServiceAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceAsyncClient.setPropertiesEnableMetrics#storageServiceProperties + StorageServiceProperties properties = queueServiceAsyncClient.getProperties().block().value(); + properties.minuteMetrics().enabled(true); + properties.hourMetrics().enabled(true); + queueServiceAsyncClient.setProperties(properties) + .subscribe(response -> System.out.printf("Setting Queue service properties completed with status code %d", + response.statusCode())); + // END: com.azure.storage.queue.queueServiceAsyncClient.setPropertiesEnableMetrics#storageServiceProperties + } + + /** + * Generates a code sample for using {@link QueueServiceClient#getStatistics()} + */ + public void getStatistics() { + QueueServiceClient queueServiceClient = createClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceClient.getStatistics + StorageServiceStats stats = queueServiceClient.getStatistics().value(); + System.out.printf("Geo replication status: %s, Last synced: %s", + stats.geoReplication().status(), stats.geoReplication().lastSyncTime()); + // END: com.azure.storage.queue.queueServiceClient.getStatistics + } + + /** + * Generates a code sample for using {@link QueueServiceAsyncClient#getStatistics()} + */ + public void getStatisticsAsync() { + QueueServiceAsyncClient queueServiceAsyncClient = createAsyncClientWithSASToken(); + // BEGIN: com.azure.storage.queue.queueServiceAsyncClient.getStatistics + queueServiceAsyncClient.getStatistics() + .subscribe(response -> { + StorageServiceStats stats = response.value(); + System.out.printf("Geo replication status: %s, Last synced: %s", + stats.geoReplication().status(), stats.geoReplication().lastSyncTime()); + }); + // END: com.azure.storage.queue.queueServiceAsyncClient.getStatistics + } +} diff --git a/storage/client/queue/src/test/java/com/azure/storage/queue/QueueAsyncClientTests.java b/storage/client/queue/src/test/java/com/azure/storage/queue/QueueAsyncClientTests.java new file mode 100644 index 0000000000000..f658e2aff324b --- /dev/null +++ b/storage/client/queue/src/test/java/com/azure/storage/queue/QueueAsyncClientTests.java @@ -0,0 +1,695 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue; + +import com.azure.core.http.HttpClient; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.queue.models.AccessPolicy; +import com.azure.storage.queue.models.DequeuedMessage; +import com.azure.storage.queue.models.SignedIdentifier; +import com.azure.storage.queue.models.StorageErrorException; +import reactor.test.StepVerifier; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class QueueAsyncClientTests extends QueueClientTestsBase { + private final ClientLogger logger = new ClientLogger(QueueAsyncClientTests.class); + + private QueueAsyncClient client; + + @Override + protected void beforeTest() { + queueName = getQueueName(); + helper = new TestHelpers(); + + if (interceptorManager.isPlaybackMode()) { + client = helper.setupClient((connectionString, endpoint) -> new QueueClientBuilder() + .connectionString(connectionString) + .endpoint(endpoint) + .queueName(queueName) + .httpClient(interceptorManager.getPlaybackClient()) + .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) + .buildAsyncClient(), true, logger); + } else { + client = helper.setupClient((connectionString, endpoint) -> new QueueClientBuilder() + .connectionString(connectionString) + .endpoint(endpoint) + .queueName(queueName) + .httpClient(HttpClient.createDefault().wiretap(true)) + .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) + .addPolicy(interceptorManager.getRecordPolicy()) + .buildAsyncClient(), false, logger); + } + } + + @Override + protected void afterTest() { + try { + client.clearMessages().block(); + client.delete().block(); + } catch (StorageErrorException ex) { + // Queue already delete, that's what we wanted anyways. + } + } + + @Override + public void createWithSharedKey() { + + } + + @Override + public void createWithSASToken() { + // Need to find a way to get SAS tokens from the storage account + } + + @Override + public void createWithMetadata() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + StepVerifier.create(client.create(metadata)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.getProperties()) + .assertNext(response -> { + helper.assertResponseStatusCode(response, 200); + assertEquals(0, response.value().approximateMessagesCount()); + assertEquals(metadata, response.value().metadata()); + }) + .verifyComplete(); + } + + @Override + public void createTwiceSameMetadata() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + StepVerifier.create(client.create(metadata)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.create(metadata)) + .assertNext(response -> helper.assertResponseStatusCode(response, 204)) + .verifyComplete(); + } + + @Override + public void createTwiceDifferentMetadata() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.create(metadata)) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 409)); + } + + @Override + public void deleteExisting() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.enqueueMessage("This queue will be deleted")) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.delete()) + .assertNext(response -> helper.assertResponseStatusCode(response, 204)) + .verifyComplete(); + + helper.sleepInRecordMode(Duration.ofSeconds(30)); + + StepVerifier.create(client.enqueueMessage("This should fail")) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 404)); + } + + @Override + public void deleteNonExistent() { + StepVerifier.create(client.delete()) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 404)); + } + + @Override + public void getProperties() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + StepVerifier.create(client.create(metadata)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.getProperties()) + .assertNext(response -> { + helper.assertResponseStatusCode(response, 200); + assertEquals(0, response.value().approximateMessagesCount()); + assertEquals(metadata, response.value().metadata()); + }) + .verifyComplete(); + } + + @Override + public void getPropertiesQueueDoesNotExist() { + StepVerifier.create(client.getProperties()) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 404)); + } + + @Override + public void setMetadata() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.setMetadata(metadata)) + .assertNext(response -> helper.assertResponseStatusCode(response, 204)) + .verifyComplete(); + + StepVerifier.create(client.getProperties()) + .assertNext(response -> { + helper.assertResponseStatusCode(response, 200); + assertEquals(0, response.value().approximateMessagesCount()); + assertEquals(metadata, response.value().metadata()); + }) + .verifyComplete(); + } + + @Override + public void setMetadataQueueDoesNotExist() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + StepVerifier.create(client.setMetadata(metadata)) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 404)); + } + + @Override + public void setInvalidMetadata() { + Map badMetadata = Collections.singletonMap("", "bad metadata"); + + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.setMetadata(badMetadata)) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 400)); + } + + @Override + public void deleteMetadata() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + StepVerifier.create(client.create(metadata)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.getProperties()) + .assertNext(response -> { + helper.assertResponseStatusCode(response, 200); + assertEquals(0, response.value().approximateMessagesCount()); + assertEquals(metadata, response.value().metadata()); + }) + .verifyComplete(); + + StepVerifier.create(client.setMetadata(null)) + .assertNext(response -> helper.assertResponseStatusCode(response, 204)) + .verifyComplete(); + + StepVerifier.create(client.getProperties()) + .assertNext(response -> { + helper.assertResponseStatusCode(response, 200); + assertEquals(Collections.EMPTY_MAP, response.value().metadata()); + }) + .verifyComplete(); + } + + @Override + public void getAccessPolicy() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.getAccessPolicy()) + .expectNextCount(0) + .verifyComplete(); + } + + @Override + public void getAccessPolicyQueueDoesNotExist() { + StepVerifier.create(client.getAccessPolicy()) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 404)); + } + + @Override + public void setAccessPolicy() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + AccessPolicy accessPolicy = new AccessPolicy() + .permission("raup") + .start(OffsetDateTime.of(LocalDateTime.of(2000, 1, 1, 0, 0), ZoneOffset.UTC)) + .expiry(OffsetDateTime.of(LocalDateTime.of(2020, 1, 1, 0, 0), ZoneOffset.UTC)); + + SignedIdentifier permission = new SignedIdentifier() + .id("testpermission") + .accessPolicy(accessPolicy); + + StepVerifier.create(client.setAccessPolicy(Collections.singletonList(permission))) + .assertNext(response -> helper.assertResponseStatusCode(response, 204)) + .verifyComplete(); + + StepVerifier.create(client.getAccessPolicy()) + .assertNext(response -> helper.assertPermissionsAreEqual(permission, response)) + .verifyComplete(); + } + + @Override + public void setAccessPolicyQueueDoesNotExist() { + AccessPolicy accessPolicy = new AccessPolicy() + .permission("r") + .start(OffsetDateTime.now()) + .expiry(OffsetDateTime.now()); + + SignedIdentifier permission = new SignedIdentifier() + .id("test-permission") + .accessPolicy(accessPolicy); + + StepVerifier.create(client.setAccessPolicy(Collections.singletonList(permission))) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 400)); + } + + @Override + public void setInvalidAccessPolicy() { + AccessPolicy accessPolicy = new AccessPolicy() + .permission("r") + .start(OffsetDateTime.of(LocalDateTime.of(2000, 1, 1, 0, 0), ZoneOffset.UTC)) + .expiry(OffsetDateTime.of(LocalDateTime.of(2020, 1, 1, 0, 0), ZoneOffset.UTC)); + + SignedIdentifier permission = new SignedIdentifier() + .id("theidofthispermissionislongerthanwhatisallowedbytheserviceandshouldfail") + .accessPolicy(accessPolicy); + + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.setAccessPolicy(Collections.singletonList(permission))) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 400)); + } + + @Override + public void setTooManyAccessPolicies() { + AccessPolicy accessPolicy = new AccessPolicy() + .permission("r") + .start(OffsetDateTime.of(LocalDateTime.of(2000, 1, 1, 0, 0), ZoneOffset.UTC)) + .expiry(OffsetDateTime.of(LocalDateTime.of(2020, 1, 1, 0, 0), ZoneOffset.UTC)); + + List permissions = new ArrayList<>(); + for (int i = 0; i < 6; i++) { + permissions.add(new SignedIdentifier() + .id("policy" + i) + .accessPolicy(accessPolicy)); + } + + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.setAccessPolicy(permissions)) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 400)); + } + + @Override + public void enqueueMessage() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + String messageText = "test message"; + StepVerifier.create(client.enqueueMessage(messageText)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.peekMessages()) + .assertNext(peekedMessage -> assertEquals(messageText, peekedMessage.messageText())) + .verifyComplete(); + } + + @Override + public void enqueueEmptyMessage() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + String messageText = ""; + StepVerifier.create(client.enqueueMessage(messageText)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.peekMessages()) + .assertNext(peekedMessage -> assertNull(peekedMessage.messageText())) + .verifyComplete(); + } + + @Override + public void enqueueShortTimeToLiveMessage() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + String messageText = "test message"; + StepVerifier.create(client.enqueueMessage(messageText, Duration.ofSeconds(0), Duration.ofSeconds(2))) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.peekMessages().delaySubscription(Duration.ofSeconds(5))) + .expectNextCount(0) + .verifyComplete(); + } + + @Override + public void enqueueQueueDoesNotExist() { + StepVerifier.create(client.enqueueMessage("this should fail")) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 404)); + } + + @Override + public void dequeueMessage() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + String messageText = "test message"; + StepVerifier.create(client.enqueueMessage(messageText)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.dequeueMessages()) + .assertNext(dequeuedMessage -> assertEquals(messageText, dequeuedMessage.messageText())) + .verifyComplete(); + } + + @Override + public void dequeueMultipleMessages() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + String messageText = "test message"; + String messageText2 = "test message 2"; + StepVerifier.create(client.enqueueMessage(messageText)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.enqueueMessage(messageText2)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.dequeueMessages(2)) + .assertNext(dequeuedMessage -> assertEquals(messageText, dequeuedMessage.messageText())) + .assertNext(dequeuedMessage -> assertEquals(messageText2, dequeuedMessage.messageText())) + .verifyComplete(); + } + + @Override + public void dequeueTooManyMessages() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.dequeueMessages(64)) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 400)); + } + + @Override + public void dequeueQueueDoesNotExist() { + StepVerifier.create(client.dequeueMessages()) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 404)); + } + + @Override + public void peekMessage() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + String messageText = "test message"; + StepVerifier.create(client.enqueueMessage(messageText)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.peekMessages()) + .assertNext(peekedMessage -> assertEquals(messageText, peekedMessage.messageText())) + .verifyComplete(); + } + + @Override + public void peekMultipleMessages() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + String messageText = "test message"; + String messageText2 = "test message 2"; + StepVerifier.create(client.enqueueMessage(messageText)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.enqueueMessage(messageText2)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.peekMessages(2)) + .assertNext(peekedMessage -> assertEquals(messageText, peekedMessage.messageText())) + .assertNext(peekedMessage -> assertEquals(messageText2, peekedMessage.messageText())) + .verifyComplete(); + } + + @Override + public void peekTooManyMessages() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.peekMessages(64)) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 400)); + } + + @Override + public void peekQueueDoesNotExist() { + StepVerifier.create(client.peekMessages()) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 404)); + } + + @Override + public void clearMessages() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.enqueueMessage("test message")) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + StepVerifier.create(client.enqueueMessage("test message")) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + StepVerifier.create(client.enqueueMessage("test message")) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(client.getProperties()) + .assertNext(response -> { + helper.assertResponseStatusCode(response, 200); + assertEquals(3, response.value().approximateMessagesCount()); + }) + .verifyComplete(); + + StepVerifier.create(client.clearMessages()) + .assertNext(response -> helper.assertResponseStatusCode(response, 204)) + .verifyComplete(); + + StepVerifier.create(client.getProperties()) + .assertNext(response -> { + helper.assertResponseStatusCode(response, 200); + assertEquals(0, response.value().approximateMessagesCount()); + }) + .verifyComplete(); + } + + @Override + public void clearMessagesQueueDoesNotExist() { + StepVerifier.create(client.clearMessages()) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 404)); + } + + @Override + public void deleteMessage() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + String messageText = "test message"; + StepVerifier.create(client.enqueueMessage(messageText)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + DequeuedMessage dequeuedMessage = client.dequeueMessages().blockFirst(); + assertEquals(messageText, dequeuedMessage.messageText()); + StepVerifier.create(client.deleteMessage(dequeuedMessage.messageId(), dequeuedMessage.popReceipt())) + .assertNext(response -> helper.assertResponseStatusCode(response, 204)) + .verifyComplete(); + + StepVerifier.create(client.getProperties()) + .assertNext(response -> { + helper.assertResponseStatusCode(response, 200); + assertEquals(0, response.value().approximateMessagesCount()); + }) + .verifyComplete(); + } + + @Override + public void deleteMessageInvalidMessageId() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + String messageText = "test message"; + StepVerifier.create(client.enqueueMessage(messageText)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + DequeuedMessage dequeuedMessage = new DequeuedMessage(); + StepVerifier.create(client.dequeueMessages()) + .assertNext(response -> { + assertEquals(messageText, response.messageText()); + dequeuedMessage.popReceipt(response.popReceipt()).messageId(response.messageId()); + }) + .verifyComplete(); + + StepVerifier.create(client.deleteMessage(dequeuedMessage.messageId() + "random", dequeuedMessage.popReceipt())) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 404)); + } + + @Override + public void deleteMessageInvalidPopReceipt() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + String messageText = "test message"; + StepVerifier.create(client.enqueueMessage(messageText)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + DequeuedMessage dequeuedMessage = new DequeuedMessage(); + StepVerifier.create(client.dequeueMessages()) + .assertNext(response -> { + assertEquals(messageText, response.messageText()); + dequeuedMessage.popReceipt(response.popReceipt()).messageId(response.messageId()); + }) + .verifyComplete(); + + StepVerifier.create(client.deleteMessage(dequeuedMessage.messageId(), dequeuedMessage.popReceipt() + "random")) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 400)); + } + + @Override + public void deleteMessageQueueDoesNotExist() { + StepVerifier.create(client.deleteMessage("invalid", "call")) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 404)); + } + + @Override + public void updateMessage() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + String messageText = "test message"; + StepVerifier.create(client.enqueueMessage(messageText)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + DequeuedMessage dequeuedMessage = client.dequeueMessages().blockFirst(); + assertEquals(messageText, dequeuedMessage.messageText()); + + String updatedMessageText = "updated test message"; + StepVerifier.create(client.updateMessage(updatedMessageText, dequeuedMessage.messageId(), dequeuedMessage.popReceipt(), Duration.ofSeconds(1))) + .assertNext(response -> helper.assertResponseStatusCode(response, 204)) + .verifyComplete(); + + StepVerifier.create(client.peekMessages().delaySubscription(Duration.ofSeconds(2))) + .assertNext(response -> assertEquals(updatedMessageText, response.messageText())) + .verifyComplete(); + } + + @Override + public void updateMessageInvalidMessageId() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + String messageText = "test message"; + StepVerifier.create(client.enqueueMessage(messageText)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + DequeuedMessage dequeuedMessage = client.dequeueMessages().blockFirst(); + assertEquals(messageText, dequeuedMessage.messageText()); + + String updatedMessageText = "updated test message"; + StepVerifier.create(client.updateMessage(updatedMessageText, dequeuedMessage.messageId() + "random", dequeuedMessage.popReceipt(), Duration.ofSeconds(1))) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 404)); + } + + @Override + public void updateMessageInvalidPopReceipt() { + StepVerifier.create(client.create()) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + String messageText = "test message"; + StepVerifier.create(client.enqueueMessage(messageText)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + DequeuedMessage dequeuedMessage = client.dequeueMessages().blockFirst(); + assertEquals(messageText, dequeuedMessage.messageText()); + + String updatedMessageText = "updated test message"; + StepVerifier.create(client.updateMessage(updatedMessageText, dequeuedMessage.messageId(), dequeuedMessage.popReceipt() + "random", Duration.ofSeconds(1))) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 400)); + } + + @Override + public void updateMessageQueueDoesNotExist() { + StepVerifier.create(client.updateMessage("queue", "doesn't", "exist", Duration.ofSeconds(5))) + .verifyErrorSatisfies(throwable -> helper.assertExceptionStatusCode(throwable, 400)); + } +} diff --git a/storage/client/queue/src/test/java/com/azure/storage/queue/QueueClientTests.java b/storage/client/queue/src/test/java/com/azure/storage/queue/QueueClientTests.java new file mode 100644 index 0000000000000..c0da15213d8c7 --- /dev/null +++ b/storage/client/queue/src/test/java/com/azure/storage/queue/QueueClientTests.java @@ -0,0 +1,654 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue; + +import com.azure.core.http.HttpClient; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.rest.Response; +import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.queue.models.AccessPolicy; +import com.azure.storage.queue.models.DequeuedMessage; +import com.azure.storage.queue.models.PeekedMessage; +import com.azure.storage.queue.models.QueueProperties; +import com.azure.storage.queue.models.SignedIdentifier; +import com.azure.storage.queue.models.StorageErrorException; +import com.azure.storage.queue.models.UpdatedMessage; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +public class QueueClientTests extends QueueClientTestsBase { + private final ClientLogger logger = new ClientLogger(QueueClientTests.class); + + private QueueClient client; + + @Override + protected void beforeTest() { + queueName = getQueueName(); + helper = new TestHelpers(); + + if (interceptorManager.isPlaybackMode()) { + client = helper.setupClient((connectionString, endpoint) -> new QueueClientBuilder() + .connectionString(connectionString) + .endpoint(endpoint) + .queueName(queueName) + .httpClient(interceptorManager.getPlaybackClient()) + .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) + .buildClient(), true, logger); + } else { + client = helper.setupClient((connectionString, endpoint) -> new QueueClientBuilder() + .endpoint(endpoint) + .queueName(queueName) + .httpClient(HttpClient.createDefault().wiretap(true)) + .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) + .addPolicy(interceptorManager.getRecordPolicy()) + .buildClient(), false, logger); + } + } + + @Override + protected void afterTest() { + try { + client.clearMessages(); + client.delete(); + } catch (StorageErrorException ex) { + // Queue already delete, that's what we wanted anyways. + } + } + + @Override + public void createWithSharedKey() { + + } + + @Override + public void createWithSASToken() { + // Need to find a way to get SAS tokens from the storage account + } + + @Override + public void createWithMetadata() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + helper.assertResponseStatusCode(client.create(metadata), 201); + + QueueProperties properties = client.getProperties().value(); + assertEquals(metadata, properties.metadata()); + } + + @Override + public void createTwiceSameMetadata() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + helper.assertResponseStatusCode(client.create(metadata), 201); + helper.assertResponseStatusCode(client.create(metadata), 204); + } + + @Override + public void createTwiceDifferentMetadata() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + helper.assertResponseStatusCode(client.create(), 201); + + try { + client.create(metadata); + fail("Creating a queue twice with different metadata values should throw an exception."); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 409); + } + } + + @Override + public void deleteExisting() { + helper.assertResponseStatusCode(client.create(), 201); + helper.assertResponseStatusCode(client.enqueueMessage("This queue will be deleted"), 201); + helper.assertResponseStatusCode(client.delete(), 204); + + helper.sleepInRecordMode(Duration.ofSeconds(30)); + + try { + client.enqueueMessage("This should fail"); + fail("Attempting to work with a queue that has been deleted should throw an exception."); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 404); + } + } + + @Override + public void deleteNonExistent() { + try { + client.delete(); + fail("Attempting to delete a queue that doesn't exist should throw an exception"); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 404); + } + } + + @Override + public void getProperties() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + helper.assertResponseStatusCode(client.create(metadata), 201); + + Response response = client.getProperties(); + helper.assertResponseStatusCode(response, 200); + assertEquals(0, response.value().approximateMessagesCount()); + assertEquals(metadata, response.value().metadata()); + } + + @Override + public void getPropertiesQueueDoesNotExist() { + try { + client.getProperties(); + fail("Attempting to get properties of a queue that doesn't exist should throw an exception"); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 404); + } + } + + @Override + public void setMetadata() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + helper.assertResponseStatusCode(client.create(), 201); + + helper.assertResponseStatusCode(client.setMetadata(metadata), 204); + + Response response = client.getProperties(); + helper.assertResponseStatusCode(response, 200); + assertEquals(0, response.value().approximateMessagesCount()); + assertEquals(metadata, response.value().metadata()); + } + + @Override + public void setMetadataQueueDoesNotExist() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + try { + client.setMetadata(metadata); + fail("Attempting to set metadata on a queue that doesn't exist should throw an exception"); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 404); + } + } + + @Override + public void setInvalidMetadata() { + Map badMetadata = Collections.singletonMap("", "bad metadata"); + + helper.assertResponseStatusCode(client.create(), 201); + try { + client.setMetadata(badMetadata); + fail("Attempting to set invalid metadata on a queue that doesn't exist should throw an exception"); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 400); + } + } + + @Override + public void deleteMetadata() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + helper.assertResponseStatusCode(client.create(metadata), 201); + + Response response = client.getProperties(); + helper.assertResponseStatusCode(response, 200); + assertEquals(0, response.value().approximateMessagesCount()); + assertEquals(metadata, response.value().metadata()); + + helper.assertResponseStatusCode(client.setMetadata(null), 204); + + response = client.getProperties(); + helper.assertResponseStatusCode(response, 200); + assertEquals(0, response.value().approximateMessagesCount()); + assertEquals(Collections.EMPTY_MAP, response.value().metadata()); + } + + @Override + public void getAccessPolicy() { + helper.assertResponseStatusCode(client.create(), 201); + + Iterable accessPolicies = client.getAccessPolicy(); + assertFalse(accessPolicies.iterator().hasNext()); + } + + @Override + public void getAccessPolicyQueueDoesNotExist() { + try { + client.getAccessPolicy().iterator().hasNext(); + fail("Attempting to get access policies on a queue that doesn't exist should throw an exception"); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 404); + } + } + + @Override + public void setAccessPolicy() { + helper.assertResponseStatusCode(client.create(), 201); + + AccessPolicy accessPolicy = new AccessPolicy() + .permission("raup") + .start(OffsetDateTime.of(LocalDateTime.of(2000, 1, 1, 0, 0), ZoneOffset.UTC)) + .expiry(OffsetDateTime.of(LocalDateTime.of(2020, 1, 1, 0, 0), ZoneOffset.UTC)); + + SignedIdentifier permission = new SignedIdentifier() + .id("testpermission") + .accessPolicy(accessPolicy); + + helper.assertResponseStatusCode(client.setAccessPolicy(Collections.singletonList(permission)), 204); + + Iterator accessPolicies = client.getAccessPolicy().iterator(); + helper.assertPermissionsAreEqual(permission, accessPolicies.next()); + assertFalse(accessPolicies.hasNext()); + } + + @Override + public void setAccessPolicyQueueDoesNotExist() { + AccessPolicy accessPolicy = new AccessPolicy() + .permission("r") + .start(OffsetDateTime.now()) + .expiry(OffsetDateTime.now()); + + SignedIdentifier permission = new SignedIdentifier() + .id("test-permission") + .accessPolicy(accessPolicy); + + try { + client.setAccessPolicy(Collections.singletonList(permission)); + fail("Attempting to set access policies on a queue that doesn't exist should throw an exception"); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 400); + } + } + + @Override + public void setInvalidAccessPolicy() { + AccessPolicy accessPolicy = new AccessPolicy() + .permission("r") + .start(OffsetDateTime.of(LocalDateTime.of(2000, 1, 1, 0, 0), ZoneOffset.UTC)) + .expiry(OffsetDateTime.of(LocalDateTime.of(2020, 1, 1, 0, 0), ZoneOffset.UTC)); + + SignedIdentifier permission = new SignedIdentifier() + .id("theidofthispermissionislongerthanwhatisallowedbytheserviceandshouldfail") + .accessPolicy(accessPolicy); + + helper.assertResponseStatusCode(client.create(), 201); + + try { + client.setAccessPolicy(Collections.singletonList(permission)); + fail("Attempting to set invalid access policies on a queue that doesn't exist should throw an exception"); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 400); + } + } + + @Override + public void setTooManyAccessPolicies() { + List permissions = new ArrayList<>(); + + AccessPolicy accessPolicy = new AccessPolicy() + .permission("r") + .start(OffsetDateTime.of(LocalDateTime.of(2000, 1, 1, 0, 0), ZoneOffset.UTC)) + .expiry(OffsetDateTime.of(LocalDateTime.of(2020, 1, 1, 0, 0), ZoneOffset.UTC)); + + for (int i = 0; i < 6; i++) { + permissions.add(new SignedIdentifier() + .id("policy" + i) + .accessPolicy(accessPolicy)); + } + + helper.assertResponseStatusCode(client.create(), 201); + + try { + client.setAccessPolicy(permissions); + fail("Attempting to set more than five access policies on a queue that doesn't exist should throw an exception"); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 400); + } + } + + @Override + public void enqueueMessage() { + helper.assertResponseStatusCode(client.create(), 201); + + String messageText = "test message"; + helper.assertResponseStatusCode(client.enqueueMessage(messageText), 201); + + Iterator response = client.peekMessages().iterator(); + assertEquals(messageText, response.next().messageText()); + assertFalse(response.hasNext()); + } + + @Override + public void enqueueEmptyMessage() { + helper.assertResponseStatusCode(client.create(), 201); + + String messageText = ""; + helper.assertResponseStatusCode(client.enqueueMessage(messageText), 201); + + Iterator response = client.peekMessages().iterator(); + assertNull(response.next().messageText()); + assertFalse(response.hasNext()); + } + + @Override + public void enqueueShortTimeToLiveMessage() { + helper.assertResponseStatusCode(client.create(), 201); + + String messageText = "test message"; + helper.assertResponseStatusCode(client.enqueueMessage(messageText, Duration.ofSeconds(0), Duration.ofSeconds(2)), 201); + + helper.sleepInRecordMode(Duration.ofSeconds(5)); + Iterator response = client.peekMessages().iterator(); + assertFalse(response.hasNext()); + } + + @Override + public void enqueueQueueDoesNotExist() { + try { + client.enqueueMessage("This should fail"); + fail("Attempting to enqueue a message on a queue that doesn't exist should throw an exception"); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 404); + } + } + + @Override + public void dequeueMessage() { + helper.assertResponseStatusCode(client.create(), 201); + + String messageText = "test message"; + helper.assertResponseStatusCode(client.enqueueMessage(messageText), 201); + + Iterator response = client.dequeueMessages().iterator(); + assertEquals(messageText, response.next().messageText()); + assertFalse(response.hasNext()); + } + + @Override + public void dequeueMultipleMessages() { + helper.assertResponseStatusCode(client.create(), 201); + + String messageText = "test message"; + String messageText2 = "test message 2"; + helper.assertResponseStatusCode(client.enqueueMessage(messageText), 201); + helper.assertResponseStatusCode(client.enqueueMessage(messageText2), 201); + + Iterator response = client.dequeueMessages(2).iterator(); + assertEquals(messageText, response.next().messageText()); + assertEquals(messageText2, response.next().messageText()); + assertFalse(response.hasNext()); + } + + @Override + public void dequeueTooManyMessages() { + helper.assertResponseStatusCode(client.create(), 201); + + try { + client.dequeueMessages(64).iterator().hasNext(); + fail("Attempting to get more than 32 messages from a queue should throw an exception"); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 400); + } + } + + @Override + public void dequeueQueueDoesNotExist() { + try { + client.dequeueMessages().iterator().hasNext(); + fail("Attempting to get messages from a queue that doesn't exist should throw an exception"); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 404); + } + } + + @Override + public void peekMessage() { + helper.assertResponseStatusCode(client.create(), 201); + + String messageText = "test message"; + helper.assertResponseStatusCode(client.enqueueMessage(messageText), 201); + + Iterator response = client.peekMessages().iterator(); + assertEquals(messageText, response.next().messageText()); + assertFalse(response.hasNext()); + } + + @Override + public void peekMultipleMessages() { + helper.assertResponseStatusCode(client.create(), 201); + + String messageText = "test message"; + String messageText2 = "test message 2"; + helper.assertResponseStatusCode(client.enqueueMessage(messageText), 201); + helper.assertResponseStatusCode(client.enqueueMessage(messageText2), 201); + + Iterator response = client.peekMessages(2).iterator(); + assertEquals(messageText, response.next().messageText()); + assertEquals(messageText2, response.next().messageText()); + assertFalse(response.hasNext()); + } + + @Override + public void peekTooManyMessages() { + helper.assertResponseStatusCode(client.create(), 201); + + try { + client.peekMessages(64).iterator().hasNext(); + fail("Attempting to peek more than 32 messages from a queue should throw an exception"); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 400); + } + } + + @Override + public void peekQueueDoesNotExist() { + try { + client.peekMessages().iterator().hasNext(); + fail("Attempting to peek messages from a queue that doesn't exist should throw an exception"); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 404); + } + } + + @Override + public void clearMessages() { + helper.assertResponseStatusCode(client.create(), 201); + + for (int i = 0; i < 3; i++) { + helper.assertResponseStatusCode(client.enqueueMessage("test message"), 201); + } + + Response response = client.getProperties(); + helper.assertResponseStatusCode(response, 200); + assertEquals(3, response.value().approximateMessagesCount()); + + helper.assertResponseStatusCode(client.clearMessages(), 204); + + response = client.getProperties(); + helper.assertResponseStatusCode(response, 200); + assertEquals(0, response.value().approximateMessagesCount()); + } + + @Override + public void clearMessagesQueueDoesNotExist() { + try { + client.clearMessages(); + fail("Attempting to clear messages of a queue that doesn't exist should throw an exception"); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 404); + } + } + + @Override + public void deleteMessage() { + helper.assertResponseStatusCode(client.create(), 201); + + String messageText = "test message"; + helper.assertResponseStatusCode(client.enqueueMessage(messageText), 201); + + Iterator response = client.dequeueMessages().iterator(); + DequeuedMessage message = response.next(); + assertFalse(response.hasNext()); + assertEquals(messageText, message.messageText()); + + helper.assertResponseStatusCode(client.deleteMessage(message.messageId(), message.popReceipt()), 204); + + Response propertiesResponse = client.getProperties(); + helper.assertResponseStatusCode(propertiesResponse, 200); + assertEquals(0, propertiesResponse.value().approximateMessagesCount()); + } + + @Override + public void deleteMessageInvalidMessageId() { + helper.assertResponseStatusCode(client.create(), 201); + + String messageText = "test message"; + helper.assertResponseStatusCode(client.enqueueMessage(messageText), 201); + + Iterator response = client.dequeueMessages().iterator(); + DequeuedMessage message = response.next(); + assertFalse(response.hasNext()); + assertEquals(messageText, message.messageText()); + + try { + client.deleteMessage(message.messageId() + "random", message.popReceipt()); + fail("Attempting to delete a message with an invalid ID should throw an exception."); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 404); + } + } + + @Override + public void deleteMessageInvalidPopReceipt() { + helper.assertResponseStatusCode(client.create(), 201); + + String messageText = "test message"; + helper.assertResponseStatusCode(client.enqueueMessage(messageText), 201); + + Iterator response = client.dequeueMessages().iterator(); + DequeuedMessage message = response.next(); + assertFalse(response.hasNext()); + assertEquals(messageText, message.messageText()); + + try { + client.deleteMessage(message.messageId(), message.popReceipt() + "random"); + fail("Attempting to delete a message with an invalid popReceipt should throw an exception."); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 400); + } + } + + @Override + public void deleteMessageQueueDoesNotExist() { + try { + client.deleteMessage("invalid", "call"); + fail("Attempting to delete a message from a queue that doesn't exist should throw an exception."); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 404); + } + } + + @Override + public void updateMessage() { + helper.assertResponseStatusCode(client.create(), 201); + + String messageText = "test message"; + helper.assertResponseStatusCode(client.enqueueMessage(messageText), 201); + + Iterator response = client.dequeueMessages().iterator(); + DequeuedMessage message = response.next(); + assertEquals(messageText, message.messageText()); + assertFalse(response.hasNext()); + + String updatedMessageText = "updated test message"; + Response updatedMessageResponse = client.updateMessage(updatedMessageText, message.messageId(), message.popReceipt(), Duration.ofSeconds(1)); + helper.assertResponseStatusCode(updatedMessageResponse, 204); + + helper.sleepInRecordMode(Duration.ofSeconds(2)); + + Iterator peekedMessageIterator = client.peekMessages().iterator(); + PeekedMessage peekedMessage = peekedMessageIterator.next(); + assertEquals(updatedMessageText, peekedMessage.messageText()); + assertFalse(peekedMessageIterator.hasNext()); + } + + @Override + public void updateMessageInvalidMessageId() { + helper.assertResponseStatusCode(client.create(), 201); + + String messageText = "test message"; + helper.assertResponseStatusCode(client.enqueueMessage(messageText), 201); + + Iterator response = client.dequeueMessages().iterator(); + DequeuedMessage message = response.next(); + assertEquals(messageText, message.messageText()); + assertFalse(response.hasNext()); + + String updatedMessageText = "updated test message"; + try { + client.updateMessage(updatedMessageText, message.messageId() + "random", message.popReceipt(), Duration.ofSeconds(1)); + fail("Attempting to update a message with an invalid ID should throw an exception."); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 404); + } + } + + @Override + public void updateMessageInvalidPopReceipt() { + helper.assertResponseStatusCode(client.create(), 201); + + String messageText = "test message"; + helper.assertResponseStatusCode(client.enqueueMessage(messageText), 201); + + Iterator response = client.dequeueMessages().iterator(); + DequeuedMessage message = response.next(); + assertEquals(messageText, message.messageText()); + assertFalse(response.hasNext()); + + String updatedMessageText = "updated test message"; + try { + client.updateMessage(updatedMessageText, message.messageId(), message.popReceipt() + "random", Duration.ofSeconds(1)); + fail("Attempting to update a message with an invalid popReceipt should throw an exception."); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 400); + } + } + + @Override + public void updateMessageQueueDoesNotExist() { + try { + client.updateMessage("queue", "doesn't", "exist", Duration.ofSeconds(5)); + fail("Attempting to update a message on a queue that doesn't exist should throw an exception."); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 400); + } + } +} diff --git a/storage/client/queue/src/test/java/com/azure/storage/queue/QueueClientTestsBase.java b/storage/client/queue/src/test/java/com/azure/storage/queue/QueueClientTestsBase.java new file mode 100644 index 0000000000000..b83d9a1459bbc --- /dev/null +++ b/storage/client/queue/src/test/java/com/azure/storage/queue/QueueClientTestsBase.java @@ -0,0 +1,148 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue; + +import com.azure.core.test.TestBase; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +public abstract class QueueClientTestsBase extends TestBase { + String queueName; + TestHelpers helper; + + @Rule + public TestName testName = new TestName(); + + @Override + public String testName() { + return testName.getMethodName(); + } + + String getQueueName() { + return testResourceNamer.randomName("queue", 16).toLowerCase(); + } + + @Test + public abstract void createWithSharedKey(); + + @Test + public abstract void createWithSASToken(); + + @Test + public abstract void createWithMetadata(); + + @Test + public abstract void createTwiceSameMetadata(); + + @Test + public abstract void createTwiceDifferentMetadata(); + + @Test + public abstract void deleteExisting(); + + @Test + public abstract void deleteNonExistent(); + + @Test + public abstract void getProperties(); + + @Test + public abstract void getPropertiesQueueDoesNotExist(); + + @Test + public abstract void setMetadata(); + + @Test + public abstract void setMetadataQueueDoesNotExist(); + + @Test + public abstract void setInvalidMetadata(); + + @Test + public abstract void deleteMetadata(); + + @Test + public abstract void getAccessPolicy(); + + @Test + public abstract void getAccessPolicyQueueDoesNotExist(); + + @Test + public abstract void setAccessPolicy(); + + @Test + public abstract void setAccessPolicyQueueDoesNotExist(); + + @Test + public abstract void setInvalidAccessPolicy(); + + @Test + public abstract void setTooManyAccessPolicies(); + + @Test + public abstract void enqueueMessage(); + + @Test + public abstract void enqueueEmptyMessage(); + + @Test + public abstract void enqueueShortTimeToLiveMessage(); + + @Test + public abstract void enqueueQueueDoesNotExist(); + + @Test + public abstract void dequeueMessage(); + + @Test + public abstract void dequeueMultipleMessages(); + + @Test + public abstract void dequeueTooManyMessages(); + + @Test + public abstract void dequeueQueueDoesNotExist(); + + @Test + public abstract void peekMessage(); + + @Test + public abstract void peekMultipleMessages(); + + @Test + public abstract void peekTooManyMessages(); + + @Test + public abstract void peekQueueDoesNotExist(); + + @Test + public abstract void clearMessages(); + + @Test + public abstract void clearMessagesQueueDoesNotExist(); + + @Test + public abstract void deleteMessage(); + + @Test + public abstract void deleteMessageInvalidMessageId(); + + @Test + public abstract void deleteMessageInvalidPopReceipt(); + + @Test + public abstract void deleteMessageQueueDoesNotExist(); + + @Test + public abstract void updateMessage(); + + @Test + public abstract void updateMessageInvalidMessageId(); + + @Test + public abstract void updateMessageInvalidPopReceipt(); + + @Test + public abstract void updateMessageQueueDoesNotExist(); +} diff --git a/storage/client/queue/src/test/java/com/azure/storage/queue/QueueServiceAsyncClientTests.java b/storage/client/queue/src/test/java/com/azure/storage/queue/QueueServiceAsyncClientTests.java new file mode 100644 index 0000000000000..8d0b89aa9be07 --- /dev/null +++ b/storage/client/queue/src/test/java/com/azure/storage/queue/QueueServiceAsyncClientTests.java @@ -0,0 +1,250 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue; + +import com.azure.core.http.HttpClient; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.queue.models.Logging; +import com.azure.storage.queue.models.Metrics; +import com.azure.storage.queue.models.QueueItem; +import com.azure.storage.queue.models.QueuesSegmentOptions; +import com.azure.storage.queue.models.RetentionPolicy; +import com.azure.storage.queue.models.StorageErrorException; +import com.azure.storage.queue.models.StorageServiceProperties; +import reactor.test.StepVerifier; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class QueueServiceAsyncClientTests extends QueueServiceClientTestsBase { + private final ClientLogger logger = new ClientLogger(QueueServiceAsyncClientTests.class); + + private QueueServiceAsyncClient serviceClient; + + @Override + protected void beforeTest() { + queueName = getQueueName(); + helper = new TestHelpers(); + + if (interceptorManager.isPlaybackMode()) { + serviceClient = helper.setupClient((connectionString, endpoint) -> new QueueServiceClientBuilder() + .connectionString(connectionString) + .endpoint(endpoint) + .httpClient(interceptorManager.getPlaybackClient()) + .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) + .buildAsyncClient(), true, logger); + } else { + serviceClient = helper.setupClient((connectionString, endpoint) -> new QueueServiceClientBuilder() + .connectionString(connectionString) + .endpoint(endpoint) + .httpClient(HttpClient.createDefault().wiretap(true)) + .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) + .addPolicy(interceptorManager.getRecordPolicy()) + .buildAsyncClient(), false, logger); + } + } + + @Override + protected void afterTest() { + serviceClient.listQueues(new QueuesSegmentOptions().prefix(queueName)) + .collectList() + .block() + .forEach(queue -> { + QueueAsyncClient client = serviceClient.getQueueAsyncClient(queue.name()); + try { + client.clearMessages().then(client.delete()).block(); + } catch (StorageErrorException ex) { + // Queue already delete, that's what we wanted anyways. + } + }); + } + + @Override + public void getQueueDoesNotCreateAQueue() { + StepVerifier.create(serviceClient.getQueueAsyncClient(queueName).enqueueMessage("Expecting an exception")); + } + + @Override + public void createQueue() { + StepVerifier.create(serviceClient.createQueue(queueName).block().value().enqueueMessage("Testing service client creating a queue")) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + } + + @Override + public void createQueueWithMetadata() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + QueueAsyncClient client = serviceClient.createQueue(queueName, metadata).block().value(); + + StepVerifier.create(client.getProperties()) + .assertNext(response -> { + assertEquals(metadata, response.value().metadata()); + }) + .verifyComplete(); + } + + @Override + public void createQueueTwiceSameMetadata() { + final String messageText = "Testing service client creating the same queue twice does not modify the queue"; + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + StepVerifier.create(serviceClient.createQueue(queueName, metadata).block().value().enqueueMessage(messageText)) + .assertNext(response -> helper.assertResponseStatusCode(response, 201)) + .verifyComplete(); + + StepVerifier.create(serviceClient.createQueue(queueName, metadata).block().value().peekMessages()) + .assertNext(response -> assertEquals(messageText, response.messageText())) + .verifyComplete(); + } + + @Override + public void createQueueTwiceDifferentMetadata() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + try { + serviceClient.createQueue(queueName); + serviceClient.createQueue(queueName, metadata); + } catch (Exception exception) { + } + } + + @Override + public void deleteExistingQueue() { + QueueAsyncClient client = serviceClient.createQueue(queueName).block().value(); + serviceClient.deleteQueue(queueName).block(); + + StepVerifier.create(client.enqueueMessage("Expecting an exception")); + } + + @Override + public void deleteNonExistentQueue() { + try { + serviceClient.deleteQueue(queueName); + } catch (Exception exception) { + } + } + + @Override + public void listQueues() { + LinkedList testQueues = new LinkedList<>(); + for (int i = 0; i < 3; i++) { + QueueItem queue = new QueueItem().name(queueName + i); + testQueues.add(queue); + serviceClient.createQueue(queue.name(), queue.metadata()).block(); + } + + StepVerifier.create(serviceClient.listQueues(defaultSegmentOptions())) + .assertNext(result -> helper.assertQueuesAreEqual(testQueues.pop(), result)) + .assertNext(result -> helper.assertQueuesAreEqual(testQueues.pop(), result)) + .assertNext(result -> helper.assertQueuesAreEqual(testQueues.pop(), result)) + .verifyComplete(); + } + + @Override + public void listQueuesIncludeMetadata() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + LinkedList testQueues = new LinkedList<>(); + for (int i = 0; i < 3; i++) { + QueueItem queue = new QueueItem().name(queueName + i); + if (i % 2 == 0) { + queue.metadata(metadata); + } + + testQueues.add(queue); + serviceClient.createQueue(queue.name(), queue.metadata()).block(); + } + + StepVerifier.create(serviceClient.listQueues(defaultSegmentOptions().includeMetadata(true))) + .assertNext(result -> helper.assertQueuesAreEqual(testQueues.pop(), result)) + .assertNext(result -> helper.assertQueuesAreEqual(testQueues.pop(), result)) + .assertNext(result -> helper.assertQueuesAreEqual(testQueues.pop(), result)) + .verifyComplete(); + } + + @Override + public void listQueuesWithPrefix() { + LinkedList testQueues = new LinkedList<>(); + for (int i = 0; i < 3; i++) { + QueueItem queue = new QueueItem(); + if (i % 2 == 0) { + queue.name(queueName + "prefix" + i); + testQueues.add(queue); + } else { + queue.name(queueName + i); + } + + serviceClient.createQueue(queue.name(), queue.metadata()).block(); + } + + StepVerifier.create(serviceClient.listQueues(defaultSegmentOptions().prefix(queueName + "prefix"))) + .assertNext(result -> helper.assertQueuesAreEqual(testQueues.pop(), result)) + .assertNext(result -> helper.assertQueuesAreEqual(testQueues.pop(), result)) + .verifyComplete(); + } + + @Override + public void listQueuesWithLimit() { + LinkedList testQueues = new LinkedList<>(); + for (int i = 0; i < 3; i++) { + QueueItem queue = new QueueItem().name(queueName + i); + testQueues.add(queue); + serviceClient.createQueue(queue.name(), queue.metadata()).block(); + } + + StepVerifier.create(serviceClient.listQueues(defaultSegmentOptions().maxResults(2))) + .verifyComplete(); + } + + @Override + public void setProperties() { + StorageServiceProperties originalProperties = serviceClient.getProperties().block().value(); + + RetentionPolicy retentionPolicy = new RetentionPolicy().enabled(true) + .days(3); + + Logging logging = new Logging().version("1.0") + .delete(true) + .write(true) + .retentionPolicy(retentionPolicy); + + Metrics metrics = new Metrics().enabled(true) + .includeAPIs(false) + .retentionPolicy(retentionPolicy) + .version("1.0"); + + StorageServiceProperties updatedProperties = new StorageServiceProperties().logging(logging) + .hourMetrics(metrics) + .minuteMetrics(metrics) + .cors(new ArrayList<>()); + + StepVerifier.create(serviceClient.setProperties(updatedProperties)) + .assertNext(response -> helper.assertResponseStatusCode(response, 202)) + .verifyComplete(); + + StepVerifier.create(serviceClient.getProperties()) + .assertNext(response -> helper.assertQueueServicePropertiesAreEqual(updatedProperties, response.value())) + .verifyComplete(); + + StepVerifier.create(serviceClient.setProperties(originalProperties)) + .assertNext(response -> helper.assertResponseStatusCode(response, 202)) + .verifyComplete(); + + StepVerifier.create(serviceClient.getProperties()) + .assertNext(response -> helper.assertQueueServicePropertiesAreEqual(originalProperties, response.value())) + .verifyComplete(); + } +} diff --git a/storage/client/queue/src/test/java/com/azure/storage/queue/QueueServiceClientTests.java b/storage/client/queue/src/test/java/com/azure/storage/queue/QueueServiceClientTests.java new file mode 100644 index 0000000000000..c6587872c6fb7 --- /dev/null +++ b/storage/client/queue/src/test/java/com/azure/storage/queue/QueueServiceClientTests.java @@ -0,0 +1,257 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue; + +import com.azure.core.http.HttpClient; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.VoidResponse; +import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.queue.models.EnqueuedMessage; +import com.azure.storage.queue.models.Logging; +import com.azure.storage.queue.models.Metrics; +import com.azure.storage.queue.models.PeekedMessage; +import com.azure.storage.queue.models.QueueItem; +import com.azure.storage.queue.models.QueueProperties; +import com.azure.storage.queue.models.QueuesSegmentOptions; +import com.azure.storage.queue.models.RetentionPolicy; +import com.azure.storage.queue.models.StorageErrorException; +import com.azure.storage.queue.models.StorageServiceProperties; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +public class QueueServiceClientTests extends QueueServiceClientTestsBase { + private final ClientLogger logger = new ClientLogger(QueueServiceClientTests.class); + + private QueueServiceClient serviceClient; + + @Override + protected void beforeTest() { + queueName = getQueueName(); + helper = new TestHelpers(); + + if (interceptorManager.isPlaybackMode()) { + serviceClient = helper.setupClient((connectionString, endpoint) -> new QueueServiceClientBuilder() + .connectionString(connectionString) + .endpoint(endpoint) + .httpClient(interceptorManager.getPlaybackClient()) + .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) + .buildClient(), true, logger); + } else { + serviceClient = helper.setupClient((connectionString, endpoint) -> new QueueServiceClientBuilder() + .connectionString(connectionString) + .endpoint(endpoint) + .httpClient(HttpClient.createDefault().wiretap(true)) + .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) + .addPolicy(interceptorManager.getRecordPolicy()) + .buildClient(), false, logger); + } + } + + @Override + protected void afterTest() { + serviceClient.listQueues(new QueuesSegmentOptions().prefix(queueName)) + .forEach(queueToDelete -> { + try { + QueueClient client = serviceClient.getQueueClient(queueToDelete.name()); + client.clearMessages(); + client.delete(); + } catch (StorageErrorException ex) { + // Queue already delete, that's what we wanted anyways. + } + }); + } + + @Override + public void getQueueDoesNotCreateAQueue() { + try { + serviceClient.getQueueClient(queueName).enqueueMessage("Expecting an exception"); + fail("getQueueClient doesn't create a queue in Azure Storage."); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 404); + } + } + + @Override + public void createQueue() { + QueueClient client = serviceClient.createQueue(queueName).value(); + Response response = client.enqueueMessage("Testing service client creating a queue"); + helper.assertResponseStatusCode(response, 201); + } + + @Override + public void createQueueWithMetadata() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + QueueClient client = serviceClient.createQueue(queueName, metadata).value(); + + Response propertiesResponse = client.getProperties(); + helper.assertResponseStatusCode(propertiesResponse, 200); + assertEquals(metadata, propertiesResponse.value().metadata()); + } + + @Override + public void createQueueTwiceSameMetadata() { + final String messageText = "Testing service client creating the same queue twice does not modify the queue"; + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + EnqueuedMessage enqueuedMessage = serviceClient.createQueue(queueName, metadata).value().enqueueMessage(messageText).value(); + assertNotNull(enqueuedMessage); + + PeekedMessage peekedMessage = serviceClient.createQueue(queueName, metadata).value().peekMessages().iterator().next(); + assertEquals(messageText, peekedMessage.messageText()); + } + + @Override + public void createQueueTwiceDifferentMetadata() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + try { + serviceClient.createQueue(queueName); + serviceClient.createQueue(queueName, metadata); + fail("Creating a queue twice with different metadata should throw an exception."); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 409); + } + } + + @Override + public void deleteExistingQueue() { + QueueClient client = serviceClient.createQueue(queueName).value(); + serviceClient.deleteQueue(queueName); + + try { + client.enqueueMessage("Expecting an exception"); + fail("Attempting to enqueue a message on a client that has been delete should throw an exception."); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 404); + } + } + + @Override + public void deleteNonExistentQueue() { + try { + serviceClient.deleteQueue(queueName); + fail("Attempting to delete a queue that doesn't exist should throw an exception."); + } catch (Exception exception) { + helper.assertExceptionStatusCode(exception, 404); + } + } + + @Override + public void listQueues() { + LinkedList testQueues = new LinkedList<>(); + for (int i = 0; i < 3; i++) { + QueueItem queue = new QueueItem().name(queueName + i); + testQueues.add(queue); + serviceClient.createQueue(queue.name(), queue.metadata()); + } + + for (QueueItem queue : serviceClient.listQueues(defaultSegmentOptions())) { + helper.assertQueuesAreEqual(testQueues.pop(), queue); + } + } + + @Override + public void listQueuesIncludeMetadata() { + Map metadata = new HashMap<>(); + metadata.put("metadata1", "value1"); + metadata.put("metadata2", "value2"); + + LinkedList testQueues = new LinkedList<>(); + for (int i = 0; i < 3; i++) { + QueueItem queue = new QueueItem().name(queueName + i); + if (i % 2 == 0) { + queue.metadata(metadata); + } + + testQueues.add(queue); + serviceClient.createQueue(queue.name(), queue.metadata()); + } + + for (QueueItem queue : serviceClient.listQueues(defaultSegmentOptions().includeMetadata(true))) { + helper.assertQueuesAreEqual(testQueues.pop(), queue); + } + } + + @Override + public void listQueuesWithPrefix() { + LinkedList testQueues = new LinkedList<>(); + for (int i = 0; i < 3; i++) { + QueueItem queue = new QueueItem(); + if (i % 2 == 0) { + queue.name(queueName + "prefix" + i); + testQueues.add(queue); + } else { + queue.name(queueName + i); + } + + serviceClient.createQueue(queue.name(), queue.metadata()); + } + + for (QueueItem queue : serviceClient.listQueues(defaultSegmentOptions().prefix(queueName + "prefix"))) { + helper.assertQueuesAreEqual(testQueues.pop(), queue); + } + } + + @Override + public void listQueuesWithLimit() { + LinkedList testQueues = new LinkedList<>(); + for (int i = 0; i < 3; i++) { + QueueItem queue = new QueueItem().name(queueName + i); + testQueues.add(queue); + serviceClient.createQueue(queue.name(), queue.metadata()); + } + + for (QueueItem queue : serviceClient.listQueues(defaultSegmentOptions().maxResults(2))) { + helper.assertQueuesAreEqual(testQueues.pop(), queue); + } + } + + @Override + public void setProperties() { + StorageServiceProperties originalProperties = serviceClient.getProperties().value(); + + RetentionPolicy retentionPolicy = new RetentionPolicy().enabled(true) + .days(3); + + Logging logging = new Logging().version("1.0") + .delete(true) + .write(true) + .retentionPolicy(retentionPolicy); + + Metrics metrics = new Metrics().enabled(true) + .includeAPIs(false) + .retentionPolicy(retentionPolicy) + .version("1.0"); + + StorageServiceProperties updatedProperties = new StorageServiceProperties().logging(logging) + .hourMetrics(metrics) + .minuteMetrics(metrics) + .cors(new ArrayList<>()); + + VoidResponse setResponse = serviceClient.setProperties(updatedProperties); + helper.assertResponseStatusCode(setResponse, 202); + + Response getResponse = serviceClient.getProperties(); + helper.assertQueueServicePropertiesAreEqual(updatedProperties, getResponse.value()); + + setResponse = serviceClient.setProperties(originalProperties); + helper.assertResponseStatusCode(setResponse, 202); + + getResponse = serviceClient.getProperties(); + helper.assertQueueServicePropertiesAreEqual(originalProperties, getResponse.value()); + } +} diff --git a/storage/client/queue/src/test/java/com/azure/storage/queue/QueueServiceClientTestsBase.java b/storage/client/queue/src/test/java/com/azure/storage/queue/QueueServiceClientTestsBase.java new file mode 100644 index 0000000000000..3b86144d6f225 --- /dev/null +++ b/storage/client/queue/src/test/java/com/azure/storage/queue/QueueServiceClientTestsBase.java @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue; + +import com.azure.core.test.TestBase; +import com.azure.storage.queue.models.QueuesSegmentOptions; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +public abstract class QueueServiceClientTestsBase extends TestBase { + String queueName; + TestHelpers helper; + + @Rule + public TestName testName = new TestName(); + + @Override + public String testName() { + return testName.getMethodName(); + } + + String getQueueName() { + return testResourceNamer.randomName("queue", 16).toLowerCase(); + } + + @Test + public abstract void getQueueDoesNotCreateAQueue(); + + @Test + public abstract void createQueue(); + + @Test + public abstract void createQueueWithMetadata(); + + @Test + public abstract void createQueueTwiceSameMetadata(); + + @Test + public abstract void createQueueTwiceDifferentMetadata(); + + @Test + public abstract void deleteExistingQueue(); + + @Test + public abstract void deleteNonExistentQueue(); + + @Test + public abstract void listQueues(); + + @Test + public abstract void listQueuesIncludeMetadata(); + + @Test + public abstract void listQueuesWithPrefix(); + + // TODO (alzimmer): This test is off for now until we determine how to handle paging with limited results + //@Test + public abstract void listQueuesWithLimit(); + + @Test + public abstract void setProperties(); + + QueuesSegmentOptions defaultSegmentOptions() { + return new QueuesSegmentOptions().prefix(queueName); + } +} diff --git a/storage/client/queue/src/test/java/com/azure/storage/queue/TestHelpers.java b/storage/client/queue/src/test/java/com/azure/storage/queue/TestHelpers.java new file mode 100644 index 0000000000000..bac3f552860fa --- /dev/null +++ b/storage/client/queue/src/test/java/com/azure/storage/queue/TestHelpers.java @@ -0,0 +1,161 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.queue; + +import com.azure.core.http.rest.Response; +import com.azure.core.implementation.util.ImplUtils; +import com.azure.core.util.configuration.ConfigurationManager; +import com.azure.core.util.logging.ClientLogger; +import com.azure.storage.queue.models.CorsRule; +import com.azure.storage.queue.models.Logging; +import com.azure.storage.queue.models.Metrics; +import com.azure.storage.queue.models.QueueItem; +import com.azure.storage.queue.models.RetentionPolicy; +import com.azure.storage.queue.models.SignedIdentifier; +import com.azure.storage.queue.models.StorageErrorException; +import com.azure.storage.queue.models.StorageServiceProperties; + +import java.time.Duration; +import java.util.List; +import java.util.function.BiFunction; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Contains helper methods for unit tests. + */ +class TestHelpers { + private final String azureStorageConnectionString = "AZURE_STORAGE_CONNECTION_STRING"; + private final String azureStorageQueueEndpoint = "AZURE_STORAGE_QUEUE_ENDPOINT"; + + T setupClient(BiFunction clientBuilder, boolean isPlaybackMode, ClientLogger logger) { + String connectionString = "DefaultEndpointsProtocol=https;AccountName=teststorage;AccountKey=atestaccountkey;EndpointSuffix=core.windows.net"; + String queueEndpoint = "https://teststorage.queue.core.windows.net/"; + + if (!isPlaybackMode) { + connectionString = ConfigurationManager.getConfiguration().get(azureStorageConnectionString); + queueEndpoint = ConfigurationManager.getConfiguration().get(azureStorageQueueEndpoint); + } + + if (ImplUtils.isNullOrEmpty(connectionString) && ImplUtils.isNullOrEmpty(queueEndpoint)) { + logger.asWarning().log("{} and {} must be set to build the testing client", azureStorageConnectionString, azureStorageQueueEndpoint); + fail(); + return null; + } + + return clientBuilder.apply(connectionString, queueEndpoint); + } + + void assertQueuesAreEqual(QueueItem expected, QueueItem actual) { + if (expected == null) { + assertNull(actual); + } else { + assertEquals(expected.name(), actual.name()); + + if (expected.metadata() != null && !ImplUtils.isNullOrEmpty(actual.metadata())) { + assertEquals(expected.metadata(), actual.metadata()); + } + } + } + + void assertQueueServicePropertiesAreEqual(StorageServiceProperties expected, StorageServiceProperties actual) { + if (expected == null) { + assertNull(actual); + } else { + assertMetricsAreEqual(expected.hourMetrics(), actual.hourMetrics()); + assertMetricsAreEqual(expected.minuteMetrics(), actual.minuteMetrics()); + assertLoggingAreEqual(expected.logging(), actual.logging()); + assertCorsAreEqual(expected.cors(), actual.cors()); + } + } + + private void assertMetricsAreEqual(Metrics expected, Metrics actual) { + if (expected == null) { + assertNull(actual); + } else { + assertEquals(expected.enabled(), actual.enabled()); + assertEquals(expected.includeAPIs(), actual.includeAPIs()); + assertEquals(expected.version(), actual.version()); + assertRetentionPoliciesAreEqual(expected.retentionPolicy(), actual.retentionPolicy()); + } + } + + private void assertLoggingAreEqual(Logging expected, Logging actual) { + if (expected == null) { + assertNull(actual); + } else { + assertEquals(expected.read(), actual.read()); + assertEquals(expected.write(), actual.write()); + assertEquals(expected.delete(), actual.delete()); + assertEquals(expected.version(), actual.version()); + assertRetentionPoliciesAreEqual(expected.retentionPolicy(), actual.retentionPolicy()); + } + } + + private void assertRetentionPoliciesAreEqual(RetentionPolicy expected, RetentionPolicy actual) { + if (expected == null) { + assertNull(actual); + } else { + assertEquals(expected.days(), actual.days()); + assertEquals(expected.enabled(), actual.enabled()); + } + } + + private void assertCorsAreEqual(List expected, List actual) { + if (expected == null) { + assertTrue(ImplUtils.isNullOrEmpty(actual)); + } else { + assertEquals(expected.size(), actual.size()); + for (int i = 0; i < expected.size(); i++) { + assertCorRulesAreEqual(expected.get(i), actual.get(i)); + } + } + } + + private void assertCorRulesAreEqual(CorsRule expected, CorsRule actual) { + if (expected == null) { + assertNull(actual); + } else { + assertEquals(expected.allowedHeaders(), actual.allowedHeaders()); + assertEquals(expected.allowedMethods(), actual.allowedMethods()); + assertEquals(expected.allowedOrigins(), actual.allowedOrigins()); + assertEquals(expected.exposedHeaders(), actual.exposedHeaders()); + assertEquals(expected.maxAgeInSeconds(), actual.maxAgeInSeconds()); + } + } + + void assertPermissionsAreEqual(SignedIdentifier expected, SignedIdentifier actual) { + assertEquals(expected.id(), actual.id()); + assertEquals(expected.accessPolicy().permission(), actual.accessPolicy().permission()); + assertEquals(expected.accessPolicy().start(), actual.accessPolicy().start()); + assertEquals(expected.accessPolicy().expiry(), actual.accessPolicy().expiry()); + } + + void assertResponseStatusCode(Response response, int expectedStatusCode) { + assertEquals(expectedStatusCode, response.statusCode()); + } + + void assertExceptionStatusCode(Throwable throwable, int expectedStatusCode) { + assertTrue(throwable instanceof StorageErrorException); + StorageErrorException storageErrorException = (StorageErrorException) throwable; + assertEquals(expectedStatusCode, storageErrorException.response().statusCode()); + } + + void sleepInRecordMode(Duration duration) { + String azureTestMode = ConfigurationManager.getConfiguration().get("AZURE_TEST_MODE"); + if ("RECORD".equalsIgnoreCase(azureTestMode)) { + sleep(duration); + } + } + + void sleep(Duration duration) { + try { + Thread.sleep(duration.toMillis()); + } catch (InterruptedException ex) { + // Ignore the error + } + } +} diff --git a/storage/client/queue/src/test/resources/session-records/clearMessages.json b/storage/client/queue/src/test/resources/session-records/clearMessages.json new file mode 100644 index 0000000000000..dab05b23fcfd5 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/clearMessages.json @@ -0,0 +1,161 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue39460410", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd222863-4003-0028-6775-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:00 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue39460410/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd2228a8-4003-0028-1b75-37b82d000000", + "Body" : "23ac390a-a15c-4036-b933-506b593e817aWed, 10 Jul 2019 23:18:01 GMTWed, 17 Jul 2019 23:18:01 GMTAgAAAAMAAAAAAAAAeGrWt3U31QE=Wed, 10 Jul 2019 23:18:01 GMT", + "Date" : "Wed, 10 Jul 2019 23:18:00 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue39460410/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd2228d0-4003-0028-3a75-37b82d000000", + "Body" : "0820c842-8ea6-466f-801e-8fdb0240f573Wed, 10 Jul 2019 23:18:01 GMTWed, 17 Jul 2019 23:18:01 GMTAgAAAAMAAAAAAAAARoLet3U31QE=Wed, 10 Jul 2019 23:18:01 GMT", + "Date" : "Wed, 10 Jul 2019 23:18:00 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue39460410/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd2228f8-4003-0028-5975-37b82d000000", + "Body" : "1a2b254b-4f28-4dba-8a56-5947173e08faWed, 10 Jul 2019 23:18:01 GMTWed, 17 Jul 2019 23:18:01 GMTAgAAAAMAAAAAAAAA5kvmt3U31QE=Wed, 10 Jul 2019 23:18:01 GMT", + "Date" : "Wed, 10 Jul 2019 23:18:00 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue39460410?comp=metadata", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "Content-Length" : "0", + "x-ms-approximate-messages-count" : "3", + "StatusCode" : "200", + "x-ms-request-id" : "dd222917-4003-0028-7175-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:00 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue39460410/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd22292f-4003-0028-0775-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:00 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue39460410?comp=metadata", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "Content-Length" : "0", + "x-ms-approximate-messages-count" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd222940-4003-0028-1575-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue39460410/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd22295c-4003-0028-2975-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue39460410", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd222973-4003-0028-3e75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT" + } + } ], + "variables" : [ "queue39460410" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/clearMessagesQueueDoesNotExist.json b/storage/client/queue/src/test/resources/session-records/clearMessagesQueueDoesNotExist.json new file mode 100644 index 0000000000000..9fb11f03c6960 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/clearMessagesQueueDoesNotExist.json @@ -0,0 +1,42 @@ +{ + "networkCallRecords" : [ { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue0499487b/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd223222-4003-0028-3175-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd223222-4003-0028-3175-37b82d000000\nTime:2019-07-10T23:18:05.7976908Z", + "Date" : "Wed, 10 Jul 2019 23:18:05 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue0499487b/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd223243-4003-0028-4e75-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd223243-4003-0028-4e75-37b82d000000\nTime:2019-07-10T23:18:05.8547315Z", + "Date" : "Wed, 10 Jul 2019 23:18:05 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue0499487b" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/createQueue.json b/storage/client/queue/src/test/resources/session-records/createQueue.json new file mode 100644 index 0000000000000..51d4b6d64f5b5 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/createQueue.json @@ -0,0 +1,90 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue09262a67", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "0d29065a-6003-009e-2f76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:47 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue09262a67/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "0d290667-6003-009e-3b76-37b6d5000000", + "Body" : "94fd0809-1708-49c0-91ea-d4cf2141af7fWed, 10 Jul 2019 23:24:47 GMTWed, 17 Jul 2019 23:24:47 GMTAgAAAAMAAAAAAAAAREDwqXY31QE=Wed, 10 Jul 2019 23:24:47 GMT", + "Date" : "Wed, 10 Jul 2019 23:24:47 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?prefix=queue09262a67&include=&comp=list", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d29067f-6003-009e-5376-37b6d5000000", + "Body" : "queue09262a67queue09262a67", + "Date" : "Wed, 10 Jul 2019 23:24:47 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue09262a67/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290694-6003-009e-6676-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:47 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue09262a67", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d2906a1-6003-009e-7376-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:47 GMT" + } + } ], + "variables" : [ "queue09262a67" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/createQueueTwiceDifferentMetadata.json b/storage/client/queue/src/test/resources/session-records/createQueueTwiceDifferentMetadata.json new file mode 100644 index 0000000000000..e7297afd23b18 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/createQueueTwiceDifferentMetadata.json @@ -0,0 +1,90 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue2172697c", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "0d290a57-6003-009e-6676-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:49 GMT" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue2172697c", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueAlreadyExists", + "retry-after" : "0", + "Content-Length" : "222", + "StatusCode" : "409", + "x-ms-request-id" : "0d290a73-6003-009e-7e76-37b6d5000000", + "Body" : "QueueAlreadyExistsThe specified queue already exists.\nRequestId:0d290a73-6003-009e-7e76-37b6d5000000\nTime:2019-07-10T23:24:49.9481623Z", + "Date" : "Wed, 10 Jul 2019 23:24:49 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?prefix=queue2172697c&include=&comp=list", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d290a84-6003-009e-0f76-37b6d5000000", + "Body" : "queue2172697cqueue2172697c", + "Date" : "Wed, 10 Jul 2019 23:24:49 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue2172697c/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290a9d-6003-009e-2776-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:50 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue2172697c", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290aa4-6003-009e-2d76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:50 GMT" + } + } ], + "variables" : [ "queue2172697c" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/createQueueTwiceSameMetadata.json b/storage/client/queue/src/test/resources/session-records/createQueueTwiceSameMetadata.json new file mode 100644 index 0000000000000..5f637cb224b88 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/createQueueTwiceSameMetadata.json @@ -0,0 +1,125 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue3315117d", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "0d29094b-6003-009e-0a76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:49 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue3315117d/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "0d29096a-6003-009e-2176-37b6d5000000", + "Body" : "e59cbb06-dc9a-4fd8-89c9-a62bec05127eWed, 10 Jul 2019 23:24:49 GMTWed, 17 Jul 2019 23:24:49 GMTAgAAAAMAAAAAAAAAh80Wq3Y31QE=Wed, 10 Jul 2019 23:24:49 GMT", + "Date" : "Wed, 10 Jul 2019 23:24:49 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue3315117d", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290979-6003-009e-2d76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:49 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue3315117d/messages?peekonly=true", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d29099f-6003-009e-4b76-37b6d5000000", + "Body" : "e59cbb06-dc9a-4fd8-89c9-a62bec05127eWed, 10 Jul 2019 23:24:49 GMTWed, 17 Jul 2019 23:24:49 GMT0Testing service client creating the same queue twice does not modify the queue", + "Date" : "Wed, 10 Jul 2019 23:24:49 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?prefix=queue3315117d&include=&comp=list", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d2909d4-6003-009e-7a76-37b6d5000000", + "Body" : "queue3315117dqueue3315117d", + "Date" : "Wed, 10 Jul 2019 23:24:49 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue3315117d/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d2909eb-6003-009e-0e76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:49 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue3315117d", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d2909f9-6003-009e-1b76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:49 GMT" + } + } ], + "variables" : [ "queue3315117d" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/createQueueWithMetadata.json b/storage/client/queue/src/test/resources/session-records/createQueueWithMetadata.json new file mode 100644 index 0000000000000..3c8381cb87770 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/createQueueWithMetadata.json @@ -0,0 +1,91 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue2741227a", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "0d290770-6003-009e-1d76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:48 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue2741227a?comp=metadata", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "Content-Length" : "0", + "x-ms-approximate-messages-count" : "0", + "x-ms-meta-metadata1" : "value1", + "StatusCode" : "200", + "x-ms-request-id" : "0d290788-6003-009e-3176-37b6d5000000", + "x-ms-meta-metadata2" : "value2", + "Date" : "Wed, 10 Jul 2019 23:24:48 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?prefix=queue2741227a&include=&comp=list", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d2907ab-6003-009e-4e76-37b6d5000000", + "Body" : "queue2741227aqueue2741227a", + "Date" : "Wed, 10 Jul 2019 23:24:48 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue2741227a/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d2907b9-6003-009e-5976-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:48 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue2741227a", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d2907c4-6003-009e-6276-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:48 GMT" + } + } ], + "variables" : [ "queue2741227a" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/createTwiceDifferentMetadata.json b/storage/client/queue/src/test/resources/session-records/createTwiceDifferentMetadata.json new file mode 100644 index 0000000000000..2c1103e32db9c --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/createTwiceDifferentMetadata.json @@ -0,0 +1,71 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue0432116e", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd226070-4003-0028-4675-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue0432116e", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueAlreadyExists", + "retry-after" : "0", + "Content-Length" : "222", + "StatusCode" : "409", + "x-ms-request-id" : "dd22608d-4003-0028-5f75-37b82d000000", + "Body" : "QueueAlreadyExistsThe specified queue already exists.\nRequestId:dd22608d-4003-0028-5f75-37b82d000000\nTime:2019-07-10T23:18:38.0176580Z", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue0432116e/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd22609f-4003-0028-7175-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue0432116e", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd2260a4-4003-0028-7675-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT" + } + } ], + "variables" : [ "queue0432116e" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/createTwiceSameMetadata.json b/storage/client/queue/src/test/resources/session-records/createTwiceSameMetadata.json new file mode 100644 index 0000000000000..67e8f6692f9ce --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/createTwiceSameMetadata.json @@ -0,0 +1,68 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue1490420b", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd225ee9-4003-0028-6675-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:36 GMT" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue1490420b", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd225f04-4003-0028-7875-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:36 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue1490420b/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd225f21-4003-0028-1175-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:36 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue1490420b", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd225f32-4003-0028-2175-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:36 GMT" + } + } ], + "variables" : [ "queue1490420b" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/createWithMetadata.json b/storage/client/queue/src/test/resources/session-records/createWithMetadata.json new file mode 100644 index 0000000000000..e81225ed944ad --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/createWithMetadata.json @@ -0,0 +1,72 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue98908a15", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd2231c8-4003-0028-6375-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:05 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue98908a15?comp=metadata", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "Content-Length" : "0", + "x-ms-approximate-messages-count" : "0", + "x-ms-meta-metadata1" : "value1", + "StatusCode" : "200", + "x-ms-request-id" : "dd2231df-4003-0028-7475-37b82d000000", + "x-ms-meta-metadata2" : "value2", + "Date" : "Wed, 10 Jul 2019 23:18:05 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue98908a15/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd2231f6-4003-0028-0975-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:05 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue98908a15", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd223209-4003-0028-1b75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:05 GMT" + } + } ], + "variables" : [ "queue98908a15" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/createWithSASToken.json b/storage/client/queue/src/test/resources/session-records/createWithSASToken.json new file mode 100644 index 0000000000000..b0f0da481c199 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/createWithSASToken.json @@ -0,0 +1,23 @@ +{ + "networkCallRecords" : [ { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue99626420/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd222843-4003-0028-5275-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd222843-4003-0028-5275-37b82d000000\nTime:2019-07-10T23:18:01.0102891Z", + "Date" : "Wed, 10 Jul 2019 23:18:00 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue99626420" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/createWithSharedKey.json b/storage/client/queue/src/test/resources/session-records/createWithSharedKey.json new file mode 100644 index 0000000000000..45ad59b25dadb --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/createWithSharedKey.json @@ -0,0 +1,23 @@ +{ + "networkCallRecords" : [ { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue46849fbc/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd226200-4003-0028-1275-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd226200-4003-0028-1275-37b82d000000\nTime:2019-07-10T23:18:39.1594759Z", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue46849fbc" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/deleteExisting.json b/storage/client/queue/src/test/resources/session-records/deleteExisting.json new file mode 100644 index 0000000000000..ffaa890d17294 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/deleteExisting.json @@ -0,0 +1,94 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue69325b7f", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd223362-4003-0028-4f75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:05 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue69325b7f/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd223387-4003-0028-7075-37b82d000000", + "Body" : "23c03c48-1eb9-48c9-aded-b6c6adb39e9eWed, 10 Jul 2019 23:18:06 GMTWed, 17 Jul 2019 23:18:06 GMTAgAAAAMAAAAAAAAA1NHmunU31QE=Wed, 10 Jul 2019 23:18:06 GMT", + "Date" : "Wed, 10 Jul 2019 23:18:05 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue69325b7f", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd223398-4003-0028-0175-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:05 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue69325b7f/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd225eb4-4003-0028-3c75-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd225eb4-4003-0028-3c75-37b82d000000\nTime:2019-07-10T23:18:36.4715552Z", + "Date" : "Wed, 10 Jul 2019 23:18:35 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue69325b7f/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd225ecd-4003-0028-5175-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd225ecd-4003-0028-5175-37b82d000000\nTime:2019-07-10T23:18:36.5175891Z", + "Date" : "Wed, 10 Jul 2019 23:18:36 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue69325b7f" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/deleteExistingQueue.json b/storage/client/queue/src/test/resources/session-records/deleteExistingQueue.json new file mode 100644 index 0000000000000..414ed34da046c --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/deleteExistingQueue.json @@ -0,0 +1,75 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue15727eac", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "0d290577-6003-009e-6976-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:46 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue15727eac", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d2905e7-6003-009e-4776-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:46 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue15727eac/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "0d290618-6003-009e-7176-37b6d5000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:0d290618-6003-009e-7176-37b6d5000000\nTime:2019-07-10T23:24:47.1091308Z", + "Date" : "Wed, 10 Jul 2019 23:24:47 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?prefix=queue15727eac&include=&comp=list", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d290643-6003-009e-1b76-37b6d5000000", + "Body" : "queue15727eac", + "Date" : "Wed, 10 Jul 2019 23:24:47 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue15727eac" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/deleteMessage.json b/storage/client/queue/src/test/resources/session-records/deleteMessage.json new file mode 100644 index 0000000000000..4682bf4a1a131 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/deleteMessage.json @@ -0,0 +1,124 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue1154048f", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd226162-4003-0028-1e75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue1154048f/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd226172-4003-0028-2a75-37b82d000000", + "Body" : "5d20d094-2ec7-4544-9ad1-86fc3aa14140Wed, 10 Jul 2019 23:18:38 GMTWed, 17 Jul 2019 23:18:38 GMTAgAAAAMAAAAAAAAAskA9znU31QE=Wed, 10 Jul 2019 23:18:38 GMT", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue1154048f/messages?numofmessages=1&visibilitytimeout=30", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd226183-4003-0028-3675-37b82d000000", + "Body" : "5d20d094-2ec7-4544-9ad1-86fc3aa14140Wed, 10 Jul 2019 23:18:38 GMTWed, 17 Jul 2019 23:18:38 GMTAgAAAAMAAAAAAAAAOIYm4HU31QE=Wed, 10 Jul 2019 23:19:08 GMT1test message", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue1154048f/messages/5d20d094-2ec7-4544-9ad1-86fc3aa14140?popreceipt=AgAAAAMAAAAAAAAAOIYm4HU31QE%3d", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd226190-4003-0028-3f75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue1154048f?comp=metadata", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "Content-Length" : "0", + "x-ms-approximate-messages-count" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd2261a5-4003-0028-4e75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue1154048f/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd2261ba-4003-0028-5e75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue1154048f", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd2261ce-4003-0028-6c75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT" + } + } ], + "variables" : [ "queue1154048f" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/deleteMessageInvalidMessageId.json b/storage/client/queue/src/test/resources/session-records/deleteMessageInvalidMessageId.json new file mode 100644 index 0000000000000..4eccb534a46f3 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/deleteMessageInvalidMessageId.json @@ -0,0 +1,109 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue96938aad", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd221ea5-4003-0028-1075-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:17:53 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue96938aad/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd221eb9-4003-0028-2375-37b82d000000", + "Body" : "17aa480c-b8aa-47ce-9fdb-753a00853819Wed, 10 Jul 2019 23:17:54 GMTWed, 17 Jul 2019 23:17:54 GMTAgAAAAMAAAAAAAAALPXXs3U31QE=Wed, 10 Jul 2019 23:17:54 GMT", + "Date" : "Wed, 10 Jul 2019 23:17:54 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue96938aad/messages?numofmessages=1&visibilitytimeout=30", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd221ecb-4003-0028-3575-37b82d000000", + "Body" : "17aa480c-b8aa-47ce-9fdb-753a00853819Wed, 10 Jul 2019 23:17:54 GMTWed, 17 Jul 2019 23:17:54 GMTAgAAAAMAAAAAAAAA4IjBxXU31QE=Wed, 10 Jul 2019 23:18:24 GMT1test message", + "Date" : "Wed, 10 Jul 2019 23:17:54 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue96938aad/messages/17aa480c-b8aa-47ce-9fdb-753a00853819random?popreceipt=AgAAAAMAAAAAAAAA4IjBxXU31QE%3d", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "MessageNotFound", + "retry-after" : "0", + "Content-Length" : "221", + "StatusCode" : "404", + "x-ms-request-id" : "dd221ee5-4003-0028-4d75-37b82d000000", + "Body" : "MessageNotFoundThe specified message does not exist.\nRequestId:dd221ee5-4003-0028-4d75-37b82d000000\nTime:2019-07-10T23:17:54.6327585Z", + "Date" : "Wed, 10 Jul 2019 23:17:54 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue96938aad/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd221ef8-4003-0028-5f75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:17:54 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue96938aad", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd221f17-4003-0028-7c75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:17:54 GMT" + } + } ], + "variables" : [ "queue96938aad" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/deleteMessageInvalidPopReceipt.json b/storage/client/queue/src/test/resources/session-records/deleteMessageInvalidPopReceipt.json new file mode 100644 index 0000000000000..01154b0b743de --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/deleteMessageInvalidPopReceipt.json @@ -0,0 +1,109 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue67327535", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd221e11-4003-0028-0575-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:17:53 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue67327535/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd221e1c-4003-0028-0f75-37b82d000000", + "Body" : "a848cec9-d421-43a6-ac39-6a941d76d21bWed, 10 Jul 2019 23:17:54 GMTWed, 17 Jul 2019 23:17:54 GMTAgAAAAMAAAAAAAAAJDmgs3U31QE=Wed, 10 Jul 2019 23:17:54 GMT", + "Date" : "Wed, 10 Jul 2019 23:17:53 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue67327535/messages?numofmessages=1&visibilitytimeout=30", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd221e2b-4003-0028-1e75-37b82d000000", + "Body" : "a848cec9-d421-43a6-ac39-6a941d76d21bWed, 10 Jul 2019 23:17:54 GMTWed, 17 Jul 2019 23:17:54 GMTAgAAAAMAAAAAAAAANWmKxXU31QE=Wed, 10 Jul 2019 23:18:24 GMT1test message", + "Date" : "Wed, 10 Jul 2019 23:17:53 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue67327535/messages/a848cec9-d421-43a6-ac39-6a941d76d21b?popreceipt=AgAAAAMAAAAAAAAANWmKxXU31QE%3drandom", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "InvalidQueryParameterValue", + "retry-after" : "0", + "Content-Length" : "444", + "StatusCode" : "400", + "x-ms-request-id" : "dd221e4c-4003-0028-3c75-37b82d000000", + "Body" : "InvalidQueryParameterValueValue for one of the query parameters specified in the request URI is invalid.\nRequestId:dd221e4c-4003-0028-3c75-37b82d000000\nTime:2019-07-10T23:17:54.2735030ZpopreceiptAgAAAAMAAAAAAAAANWmKxXU31QE=randomInvalid pop receipt format", + "Date" : "Wed, 10 Jul 2019 23:17:53 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue67327535/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd221e6a-4003-0028-5575-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:17:53 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue67327535", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd221e7b-4003-0028-6675-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:17:53 GMT" + } + } ], + "variables" : [ "queue67327535" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/deleteMessageQueueDoesNotExist.json b/storage/client/queue/src/test/resources/session-records/deleteMessageQueueDoesNotExist.json new file mode 100644 index 0000000000000..c03dedb5c4887 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/deleteMessageQueueDoesNotExist.json @@ -0,0 +1,42 @@ +{ + "networkCallRecords" : [ { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue055108e6/messages/invalid?popreceipt=call", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd226381-4003-0028-5575-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd226381-4003-0028-5575-37b82d000000\nTime:2019-07-10T23:18:40.1101585Z", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue055108e6/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd226390-4003-0028-6375-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd226390-4003-0028-6375-37b82d000000\nTime:2019-07-10T23:18:40.1591931Z", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue055108e6" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/deleteMetadata.json b/storage/client/queue/src/test/resources/session-records/deleteMetadata.json new file mode 100644 index 0000000000000..8ba83a6d8d215 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/deleteMetadata.json @@ -0,0 +1,106 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue679519e2", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd2263ff-4003-0028-4975-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue679519e2?comp=metadata", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "Content-Length" : "0", + "x-ms-approximate-messages-count" : "0", + "x-ms-meta-metadata1" : "value1", + "StatusCode" : "200", + "x-ms-request-id" : "dd226409-4003-0028-5275-37b82d000000", + "x-ms-meta-metadata2" : "value2", + "Date" : "Wed, 10 Jul 2019 23:18:40 GMT" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue679519e2?comp=metadata", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd226418-4003-0028-6075-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:40 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue679519e2?comp=metadata", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "Content-Length" : "0", + "x-ms-approximate-messages-count" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd226420-4003-0028-6875-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:40 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue679519e2/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd226434-4003-0028-7b75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:40 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue679519e2", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd22644c-4003-0028-1275-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:40 GMT" + } + } ], + "variables" : [ "queue679519e2" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/deleteNonExistent.json b/storage/client/queue/src/test/resources/session-records/deleteNonExistent.json new file mode 100644 index 0000000000000..2fa6701c17acb --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/deleteNonExistent.json @@ -0,0 +1,42 @@ +{ + "networkCallRecords" : [ { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue04551c5d", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd226108-4003-0028-4e75-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd226108-4003-0028-4e75-37b82d000000\nTime:2019-07-10T23:18:38.4209499Z", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue04551c5d/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd226119-4003-0028-5e75-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd226119-4003-0028-5e75-37b82d000000\nTime:2019-07-10T23:18:38.4689812Z", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue04551c5d" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/deleteNonExistentQueue.json b/storage/client/queue/src/test/resources/session-records/deleteNonExistentQueue.json new file mode 100644 index 0000000000000..bf9105b3ccdc4 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/deleteNonExistentQueue.json @@ -0,0 +1,42 @@ +{ + "networkCallRecords" : [ { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue82016a1d", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "0d290bd9-6003-009e-4476-37b6d5000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:0d290bd9-6003-009e-4476-37b6d5000000\nTime:2019-07-10T23:24:50.9128531Z", + "Date" : "Wed, 10 Jul 2019 23:24:50 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?prefix=queue82016a1d&include=&comp=list", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d290bf6-6003-009e-5b76-37b6d5000000", + "Body" : "queue82016a1d", + "Date" : "Wed, 10 Jul 2019 23:24:50 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue82016a1d" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/dequeueMessage.json b/storage/client/queue/src/test/resources/session-records/dequeueMessage.json new file mode 100644 index 0000000000000..6473031c5a50f --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/dequeueMessage.json @@ -0,0 +1,90 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue679346d1", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd221d34-4003-0028-3d75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:17:52 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue679346d1/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd221d8c-4003-0028-0a75-37b82d000000", + "Body" : "b6c999ca-9091-4109-b579-c4bca39d216dWed, 10 Jul 2019 23:17:53 GMTWed, 17 Jul 2019 23:17:53 GMTAgAAAAMAAAAAAAAA9bc/s3U31QE=Wed, 10 Jul 2019 23:17:53 GMT", + "Date" : "Wed, 10 Jul 2019 23:17:53 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue679346d1/messages?numofmessages=1&visibilitytimeout=30", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd221da4-4003-0028-2275-37b82d000000", + "Body" : "b6c999ca-9091-4109-b579-c4bca39d216dWed, 10 Jul 2019 23:17:53 GMTWed, 17 Jul 2019 23:17:53 GMTAgAAAAMAAAAAAAAA11EwxXU31QE=Wed, 10 Jul 2019 23:18:23 GMT1test message", + "Date" : "Wed, 10 Jul 2019 23:17:53 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue679346d1/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd221da9-4003-0028-2775-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:17:53 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue679346d1", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd221db5-4003-0028-3275-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:17:53 GMT" + } + } ], + "variables" : [ "queue679346d1" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/dequeueMultipleMessages.json b/storage/client/queue/src/test/resources/session-records/dequeueMultipleMessages.json new file mode 100644 index 0000000000000..104a637b766db --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/dequeueMultipleMessages.json @@ -0,0 +1,109 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue6570759e", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd226228-4003-0028-2f75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue6570759e/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd22623f-4003-0028-4475-37b82d000000", + "Body" : "3d48ff69-e261-4bea-839c-ca0edfc2af4cWed, 10 Jul 2019 23:18:39 GMTWed, 17 Jul 2019 23:18:39 GMTAgAAAAMAAAAAAAAAYwGHznU31QE=Wed, 10 Jul 2019 23:18:39 GMT", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue6570759e/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd226254-4003-0028-5375-37b82d000000", + "Body" : "fd6a25b1-b3d3-4743-b5b3-072add1a4a86Wed, 10 Jul 2019 23:18:39 GMTWed, 17 Jul 2019 23:18:39 GMTAgAAAAMAAAAAAAAAz3yOznU31QE=Wed, 10 Jul 2019 23:18:39 GMT", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue6570759e/messages?numofmessages=2&visibilitytimeout=30", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd226269-4003-0028-6475-37b82d000000", + "Body" : "3d48ff69-e261-4bea-839c-ca0edfc2af4cWed, 10 Jul 2019 23:18:39 GMTWed, 17 Jul 2019 23:18:39 GMTAgAAAAMAAAAAAAAAWsJ34HU31QE=Wed, 10 Jul 2019 23:19:09 GMT1test messagefd6a25b1-b3d3-4743-b5b3-072add1a4a86Wed, 10 Jul 2019 23:18:39 GMTWed, 17 Jul 2019 23:18:39 GMTAgAAAAMAAAAAAAAAWsJ34HU31QE=Wed, 10 Jul 2019 23:19:09 GMT1test message 2", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue6570759e/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd226296-4003-0028-0975-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue6570759e", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd2262a9-4003-0028-1975-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT" + } + } ], + "variables" : [ "queue6570759e" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/dequeueQueueDoesNotExist.json b/storage/client/queue/src/test/resources/session-records/dequeueQueueDoesNotExist.json new file mode 100644 index 0000000000000..3bef9c37aaf6e --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/dequeueQueueDoesNotExist.json @@ -0,0 +1,42 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue39822dce/messages?numofmessages=1&visibilitytimeout=30", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd2260e6-4003-0028-3075-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd2260e6-4003-0028-3075-37b82d000000\nTime:2019-07-10T23:18:38.3148712Z", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue39822dce/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd2260f8-4003-0028-4175-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd2260f8-4003-0028-4175-37b82d000000\nTime:2019-07-10T23:18:38.3619056Z", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue39822dce" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/dequeueTooManyMessages.json b/storage/client/queue/src/test/resources/session-records/dequeueTooManyMessages.json new file mode 100644 index 0000000000000..757caa567efa5 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/dequeueTooManyMessages.json @@ -0,0 +1,71 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue03015bde", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd2226b1-4003-0028-0675-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:17:59 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue03015bde/messages?numofmessages=64&visibilitytimeout=30", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "OutOfRangeQueryParameterValue", + "retry-after" : "0", + "Content-Length" : "456", + "StatusCode" : "400", + "x-ms-request-id" : "dd2226cd-4003-0028-1d75-37b82d000000", + "Body" : "OutOfRangeQueryParameterValueOne of the query parameters specified in the request URI is outside the permissible range.\nRequestId:dd2226cd-4003-0028-1d75-37b82d000000\nTime:2019-07-10T23:18:00.2767678Znumofmessages64132", + "Date" : "Wed, 10 Jul 2019 23:17:59 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue03015bde/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd2226e0-4003-0028-2e75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:17:59 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue03015bde", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd2226fd-4003-0028-4a75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:17:59 GMT" + } + } ], + "variables" : [ "queue03015bde" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/enqueueEmptyMessage.json b/storage/client/queue/src/test/resources/session-records/enqueueEmptyMessage.json new file mode 100644 index 0000000000000..ed0aaef6517fc --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/enqueueEmptyMessage.json @@ -0,0 +1,90 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue76420ef8", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd2262ce-4003-0028-3475-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue76420ef8/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd2262e1-4003-0028-4275-37b82d000000", + "Body" : "e1efc34f-03c7-4037-9597-6955381e8889Wed, 10 Jul 2019 23:18:39 GMTWed, 17 Jul 2019 23:18:39 GMTAgAAAAMAAAAAAAAAl6+7znU31QE=Wed, 10 Jul 2019 23:18:39 GMT", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue76420ef8/messages?peekonly=true", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd2262ef-4003-0028-5075-37b82d000000", + "Body" : "e1efc34f-03c7-4037-9597-6955381e8889Wed, 10 Jul 2019 23:18:39 GMTWed, 17 Jul 2019 23:18:39 GMT0", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue76420ef8/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd2262fe-4003-0028-5e75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue76420ef8", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd22630f-4003-0028-6f75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT" + } + } ], + "variables" : [ "queue76420ef8" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/enqueueMessage.json b/storage/client/queue/src/test/resources/session-records/enqueueMessage.json new file mode 100644 index 0000000000000..ff3e72aedaacf --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/enqueueMessage.json @@ -0,0 +1,90 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue17032768", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd222a23-4003-0028-4b75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue17032768/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd222a4a-4003-0028-6c75-37b82d000000", + "Body" : "7422f1b3-c1b1-4385-a945-6365e2e01caaWed, 10 Jul 2019 23:18:01 GMTWed, 17 Jul 2019 23:18:01 GMTAgAAAAMAAAAAAAAAQm1FuHU31QE=Wed, 10 Jul 2019 23:18:01 GMT", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue17032768/messages?peekonly=true", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd222a74-4003-0028-1275-37b82d000000", + "Body" : "7422f1b3-c1b1-4385-a945-6365e2e01caaWed, 10 Jul 2019 23:18:01 GMTWed, 17 Jul 2019 23:18:01 GMT0test message", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue17032768/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd222aa3-4003-0028-3975-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue17032768", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd222ac4-4003-0028-5675-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT" + } + } ], + "variables" : [ "queue17032768" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/enqueueQueueDoesNotExist.json b/storage/client/queue/src/test/resources/session-records/enqueueQueueDoesNotExist.json new file mode 100644 index 0000000000000..9433eea40c38b --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/enqueueQueueDoesNotExist.json @@ -0,0 +1,43 @@ +{ + "networkCallRecords" : [ { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue39910e47/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd2229a6-4003-0028-6475-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd2229a6-4003-0028-6475-37b82d000000\nTime:2019-07-10T23:18:01.6777634Z", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue39910e47/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd2229bd-4003-0028-7575-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd2229bd-4003-0028-7575-37b82d000000\nTime:2019-07-10T23:18:01.7277985Z", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue39910e47" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/enqueueShortTimeToLiveMessage.json b/storage/client/queue/src/test/resources/session-records/enqueueShortTimeToLiveMessage.json new file mode 100644 index 0000000000000..bb6b2172664f2 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/enqueueShortTimeToLiveMessage.json @@ -0,0 +1,90 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue69359315", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd221f37-4003-0028-1c75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:17:54 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue69359315/messages?visibilitytimeout=0&messagettl=2", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd221f43-4003-0028-2775-37b82d000000", + "Body" : "c96e7db1-1d4a-4743-b165-a5835968722aWed, 10 Jul 2019 23:17:54 GMTWed, 10 Jul 2019 23:17:56 GMTAgAAAAMAAAAAAAAApcYOtHU31QE=Wed, 10 Jul 2019 23:17:54 GMT", + "Date" : "Wed, 10 Jul 2019 23:17:54 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue69359315/messages?peekonly=true", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd222634-4003-0028-1675-37b82d000000", + "Body" : "", + "Date" : "Wed, 10 Jul 2019 23:17:59 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue69359315/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd22264c-4003-0028-2c75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:17:59 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue69359315", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd222666-4003-0028-4375-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:17:59 GMT" + } + } ], + "variables" : [ "queue69359315" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/getAccessPolicy.json b/storage/client/queue/src/test/resources/session-records/getAccessPolicy.json new file mode 100644 index 0000000000000..79f9317b619d1 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/getAccessPolicy.json @@ -0,0 +1,71 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue276184e3", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd222bac-4003-0028-2175-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:02 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue276184e3?comp=acl", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd222bc0-4003-0028-3175-37b82d000000", + "Body" : "", + "Date" : "Wed, 10 Jul 2019 23:18:02 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue276184e3/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd222be3-4003-0028-4d75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:02 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue276184e3", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd222bfe-4003-0028-6375-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:02 GMT" + } + } ], + "variables" : [ "queue276184e3" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/getAccessPolicyQueueDoesNotExist.json b/storage/client/queue/src/test/resources/session-records/getAccessPolicyQueueDoesNotExist.json new file mode 100644 index 0000000000000..8c772f655188e --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/getAccessPolicyQueueDoesNotExist.json @@ -0,0 +1,42 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue66823709?comp=acl", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd22604d-4003-0028-2a75-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd22604d-4003-0028-2a75-37b82d000000\nTime:2019-07-10T23:18:37.8315254Z", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue66823709/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd226056-4003-0028-3275-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd226056-4003-0028-3275-37b82d000000\nTime:2019-07-10T23:18:37.8795608Z", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue66823709" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/getProperties.json b/storage/client/queue/src/test/resources/session-records/getProperties.json new file mode 100644 index 0000000000000..a7c0a0ec5332d --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/getProperties.json @@ -0,0 +1,72 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue36601253", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd2227b8-4003-0028-6075-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:00 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue36601253?comp=metadata", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "Content-Length" : "0", + "x-ms-approximate-messages-count" : "0", + "x-ms-meta-metadata1" : "value1", + "StatusCode" : "200", + "x-ms-request-id" : "dd2227d1-4003-0028-7675-37b82d000000", + "x-ms-meta-metadata2" : "value2", + "Date" : "Wed, 10 Jul 2019 23:18:00 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue36601253/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd2227f9-4003-0028-1775-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:00 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue36601253", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd222807-4003-0028-2575-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:00 GMT" + } + } ], + "variables" : [ "queue36601253" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/getPropertiesQueueDoesNotExist.json b/storage/client/queue/src/test/resources/session-records/getPropertiesQueueDoesNotExist.json new file mode 100644 index 0000000000000..fe98b22946df5 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/getPropertiesQueueDoesNotExist.json @@ -0,0 +1,42 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue7527481d?comp=metadata", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd222681-4003-0028-5b75-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd222681-4003-0028-5b75-37b82d000000\nTime:2019-07-10T23:18:00.1126512Z", + "Date" : "Wed, 10 Jul 2019 23:17:59 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue7527481d/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd22269d-4003-0028-7375-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd22269d-4003-0028-7375-37b82d000000\nTime:2019-07-10T23:18:00.1626872Z", + "Date" : "Wed, 10 Jul 2019 23:17:59 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue7527481d" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/getQueueDoesNotCreateAQueue.json b/storage/client/queue/src/test/resources/session-records/getQueueDoesNotCreateAQueue.json new file mode 100644 index 0000000000000..7776d4fed4783 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/getQueueDoesNotCreateAQueue.json @@ -0,0 +1,43 @@ +{ + "networkCallRecords" : [ { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue48695d7f/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "0d290a18-6003-009e-3676-37b6d5000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:0d290a18-6003-009e-3676-37b6d5000000\nTime:2019-07-10T23:24:49.7390111Z", + "Date" : "Wed, 10 Jul 2019 23:24:49 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?prefix=queue48695d7f&include=&comp=list", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d290a2f-6003-009e-4876-37b6d5000000", + "Body" : "queue48695d7f", + "Date" : "Wed, 10 Jul 2019 23:24:49 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue48695d7f" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/listQueues.json b/storage/client/queue/src/test/resources/session-records/listQueues.json new file mode 100644 index 0000000000000..361f47abd400a --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/listQueues.json @@ -0,0 +1,186 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue455724b60", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "0d2907f4-6003-009e-0976-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:48 GMT" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue455724b61", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "0d290805-6003-009e-1376-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:48 GMT" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue455724b62", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "0d29080b-6003-009e-1876-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:48 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?prefix=queue455724b6&include=&comp=list", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d290816-6003-009e-2276-37b6d5000000", + "Body" : "queue455724b6queue455724b60queue455724b61queue455724b62", + "Date" : "Wed, 10 Jul 2019 23:24:48 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?prefix=queue455724b6&include=&comp=list", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d29083e-6003-009e-4676-37b6d5000000", + "Body" : "queue455724b6queue455724b60queue455724b61queue455724b62", + "Date" : "Wed, 10 Jul 2019 23:24:48 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue455724b60/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290871-6003-009e-6e76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:48 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue455724b60", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290896-6003-009e-0676-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:48 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue455724b61/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d2908bc-6003-009e-2476-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:48 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue455724b61", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d2908df-6003-009e-3e76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:49 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue455724b62/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d2908fd-6003-009e-5676-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:49 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue455724b62", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d29091f-6003-009e-6a76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:49 GMT" + } + } ], + "variables" : [ "queue455724b6" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/listQueuesIncludeMetadata.json b/storage/client/queue/src/test/resources/session-records/listQueuesIncludeMetadata.json new file mode 100644 index 0000000000000..a0e836cf26701 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/listQueuesIncludeMetadata.json @@ -0,0 +1,186 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue58738ae80", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "0d290c20-6003-009e-7b76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:51 GMT" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue58738ae81", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "0d290c34-6003-009e-0a76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:51 GMT" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue58738ae82", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "0d290c4e-6003-009e-1f76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:51 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?prefix=queue58738ae8&include=metadata&comp=list", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d290c6b-6003-009e-3376-37b6d5000000", + "Body" : "queue58738ae8queue58738ae80value1value2queue58738ae81queue58738ae82value1value2", + "Date" : "Wed, 10 Jul 2019 23:24:51 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?prefix=queue58738ae8&include=&comp=list", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d290c8e-6003-009e-5176-37b6d5000000", + "Body" : "queue58738ae8queue58738ae80queue58738ae81queue58738ae82", + "Date" : "Wed, 10 Jul 2019 23:24:51 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue58738ae80/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290caa-6003-009e-6876-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:51 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue58738ae80", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290cc1-6003-009e-7a76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:51 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue58738ae81/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290cde-6003-009e-1176-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:51 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue58738ae81", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290cf2-6003-009e-2376-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:51 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue58738ae82/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290d14-6003-009e-4076-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:51 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue58738ae82", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290d2b-6003-009e-5476-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:51 GMT" + } + } ], + "variables" : [ "queue58738ae8" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/listQueuesWithPrefix.json b/storage/client/queue/src/test/resources/session-records/listQueuesWithPrefix.json new file mode 100644 index 0000000000000..ff107058e29fc --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/listQueuesWithPrefix.json @@ -0,0 +1,186 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue423382efprefix0", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "0d290acd-6003-009e-5476-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:50 GMT" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue423382ef1", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "0d290ae3-6003-009e-6876-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:50 GMT" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue423382efprefix2", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "0d290afd-6003-009e-8076-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:50 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?prefix=queue423382efprefix&include=&comp=list", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d290b0d-6003-009e-0f76-37b6d5000000", + "Body" : "queue423382efprefixqueue423382efprefix0queue423382efprefix2", + "Date" : "Wed, 10 Jul 2019 23:24:50 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?prefix=queue423382ef&include=&comp=list", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d290b16-6003-009e-1776-37b6d5000000", + "Body" : "queue423382efqueue423382ef1queue423382efprefix0queue423382efprefix2", + "Date" : "Wed, 10 Jul 2019 23:24:50 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue423382ef1/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290b38-6003-009e-3576-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:50 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue423382ef1", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290b4c-6003-009e-4776-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:50 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue423382efprefix0/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290b60-6003-009e-5976-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:50 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue423382efprefix0", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290b71-6003-009e-6676-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:50 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue423382efprefix2/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290b81-6003-009e-7576-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:50 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue423382efprefix2", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "0d290b9a-6003-009e-0b76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:50 GMT" + } + } ], + "variables" : [ "queue423382ef" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/peekMessage.json b/storage/client/queue/src/test/resources/session-records/peekMessage.json new file mode 100644 index 0000000000000..540c460785a11 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/peekMessage.json @@ -0,0 +1,90 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue54577e60", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd225fa8-4003-0028-0d75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:36 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue54577e60/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd225fb8-4003-0028-1c75-37b82d000000", + "Body" : "53096a37-63bf-45d9-9172-4c8713ff282eWed, 10 Jul 2019 23:18:37 GMTWed, 17 Jul 2019 23:18:37 GMTAgAAAAMAAAAAAAAATsJgzXU31QE=Wed, 10 Jul 2019 23:18:37 GMT", + "Date" : "Wed, 10 Jul 2019 23:18:36 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue54577e60/messages?peekonly=true", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd225fd2-4003-0028-3375-37b82d000000", + "Body" : "53096a37-63bf-45d9-9172-4c8713ff282eWed, 10 Jul 2019 23:18:37 GMTWed, 17 Jul 2019 23:18:37 GMT0test message", + "Date" : "Wed, 10 Jul 2019 23:18:36 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue54577e60/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd225fe6-4003-0028-4775-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:36 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue54577e60", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd225ff7-4003-0028-5875-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT" + } + } ], + "variables" : [ "queue54577e60" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/peekMultipleMessages.json b/storage/client/queue/src/test/resources/session-records/peekMultipleMessages.json new file mode 100644 index 0000000000000..5ea0a89b15f98 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/peekMultipleMessages.json @@ -0,0 +1,109 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue17925938", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd222afc-4003-0028-0875-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue17925938/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd222b1e-4003-0028-2375-37b82d000000", + "Body" : "86c3b192-2c4f-4bd4-89bf-07553c141ac0Wed, 10 Jul 2019 23:18:02 GMTWed, 17 Jul 2019 23:18:02 GMTAgAAAAMAAAAAAAAAI8dyuHU31QE=Wed, 10 Jul 2019 23:18:02 GMT", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue17925938/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd222b4a-4003-0028-4775-37b82d000000", + "Body" : "1b2d50b7-3540-4dd4-a480-8549b5207fe7Wed, 10 Jul 2019 23:18:02 GMTWed, 17 Jul 2019 23:18:02 GMTAgAAAAMAAAAAAAAAqWl6uHU31QE=Wed, 10 Jul 2019 23:18:02 GMT", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue17925938/messages?numofmessages=2&peekonly=true", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd222b67-4003-0028-6175-37b82d000000", + "Body" : "86c3b192-2c4f-4bd4-89bf-07553c141ac0Wed, 10 Jul 2019 23:18:02 GMTWed, 17 Jul 2019 23:18:02 GMT0test message1b2d50b7-3540-4dd4-a480-8549b5207fe7Wed, 10 Jul 2019 23:18:02 GMTWed, 17 Jul 2019 23:18:02 GMT0test message 2", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue17925938/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd222b7e-4003-0028-7675-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue17925938", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd222b8e-4003-0028-0675-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT" + } + } ], + "variables" : [ "queue17925938" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/peekQueueDoesNotExist.json b/storage/client/queue/src/test/resources/session-records/peekQueueDoesNotExist.json new file mode 100644 index 0000000000000..c9de737c16179 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/peekQueueDoesNotExist.json @@ -0,0 +1,42 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue5442745c/messages?peekonly=true", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd221dd8-4003-0028-5075-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd221dd8-4003-0028-5075-37b82d000000\nTime:2019-07-10T23:17:53.9252561Z", + "Date" : "Wed, 10 Jul 2019 23:17:53 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue5442745c/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd221df7-4003-0028-6d75-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd221df7-4003-0028-6d75-37b82d000000\nTime:2019-07-10T23:17:54.0093158Z", + "Date" : "Wed, 10 Jul 2019 23:17:53 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue5442745c" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/peekTooManyMessages.json b/storage/client/queue/src/test/resources/session-records/peekTooManyMessages.json new file mode 100644 index 0000000000000..f653e97e1e0ce --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/peekTooManyMessages.json @@ -0,0 +1,71 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue80227035", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd22612f-4003-0028-7275-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue80227035/messages?numofmessages=64&peekonly=true", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "OutOfRangeQueryParameterValue", + "retry-after" : "0", + "Content-Length" : "456", + "StatusCode" : "400", + "x-ms-request-id" : "dd226138-4003-0028-7a75-37b82d000000", + "Body" : "OutOfRangeQueryParameterValueOne of the query parameters specified in the request URI is outside the permissible range.\nRequestId:dd226138-4003-0028-7a75-37b82d000000\nTime:2019-07-10T23:18:38.5780592Znumofmessages64132", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue80227035/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd22613d-4003-0028-7f75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue80227035", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd226149-4003-0028-0975-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:38 GMT" + } + } ], + "variables" : [ "queue80227035" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/setAccessPolicy.json b/storage/client/queue/src/test/resources/session-records/setAccessPolicy.json new file mode 100644 index 0000000000000..ac6e9881a669f --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/setAccessPolicy.json @@ -0,0 +1,88 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue656812ca", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd225f53-4003-0028-4075-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:36 GMT" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue656812ca?comp=acl", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd225f6a-4003-0028-5575-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:36 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue656812ca?comp=acl", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd225f7e-4003-0028-6675-37b82d000000", + "Body" : "testpermission2000-01-01T00:00:00.0000000Z2020-01-01T00:00:00.0000000Zraup", + "Date" : "Wed, 10 Jul 2019 23:18:36 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue656812ca/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd225f8c-4003-0028-7475-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:36 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue656812ca", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd225f98-4003-0028-7e75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:36 GMT" + } + } ], + "variables" : [ "queue656812ca" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/setAccessPolicyQueueDoesNotExist.json b/storage/client/queue/src/test/resources/session-records/setAccessPolicyQueueDoesNotExist.json new file mode 100644 index 0000000000000..b2b42bce18c37 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/setAccessPolicyQueueDoesNotExist.json @@ -0,0 +1,43 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue01052e33?comp=acl", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "InvalidXmlDocument", + "retry-after" : "0", + "Content-Length" : "294", + "StatusCode" : "400", + "x-ms-request-id" : "dd22645d-4003-0028-2375-37b82d000000", + "Body" : "InvalidXmlDocumentXML specified is not syntactically valid.\nRequestId:dd22645d-4003-0028-2375-37b82d000000\nTime:2019-07-10T23:18:40.8086534Z00", + "Date" : "Wed, 10 Jul 2019 23:18:40 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue01052e33/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd22646a-4003-0028-2f75-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd22646a-4003-0028-2f75-37b82d000000\nTime:2019-07-10T23:18:40.8566884Z", + "Date" : "Wed, 10 Jul 2019 23:18:40 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue01052e33" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/setInvalidAccessPolicy.json b/storage/client/queue/src/test/resources/session-records/setInvalidAccessPolicy.json new file mode 100644 index 0000000000000..fe186f2b4ac1c --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/setInvalidAccessPolicy.json @@ -0,0 +1,72 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue424460ef", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd226338-4003-0028-1475-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue424460ef?comp=acl", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "InvalidXmlDocument", + "retry-after" : "0", + "Content-Length" : "371", + "StatusCode" : "400", + "x-ms-request-id" : "dd22634c-4003-0028-2575-37b82d000000", + "Body" : "InvalidXmlDocumentXML specified is not syntactically valid.\nRequestId:dd22634c-4003-0028-2575-37b82d000000\nTime:2019-07-10T23:18:39.9250246Z1304Signed identifier ID cannot be empty or over 64 characters in length", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue424460ef/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd22635d-4003-0028-3675-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue424460ef", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd226363-4003-0028-3a75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT" + } + } ], + "variables" : [ "queue424460ef" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/setInvalidMetadata.json b/storage/client/queue/src/test/resources/session-records/setInvalidMetadata.json new file mode 100644 index 0000000000000..eb9faafed36f9 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/setInvalidMetadata.json @@ -0,0 +1,71 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue38693e14", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd22272a-4003-0028-7175-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:17:59 GMT" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue38693e14?comp=metadata", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "EmptyMetadataKey", + "retry-after" : "0", + "Content-Length" : "285", + "StatusCode" : "400", + "x-ms-request-id" : "dd22274f-4003-0028-0b75-37b82d000000", + "Body" : "EmptyMetadataKeyThe key for one of the metadata key-value pairs is empty.\nRequestId:dd22274f-4003-0028-0b75-37b82d000000\nTime:2019-07-10T23:18:00.5359517Zbad metadata", + "Date" : "Wed, 10 Jul 2019 23:18:00 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue38693e14/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd222779-4003-0028-2875-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:00 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue38693e14", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd222798-4003-0028-4375-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:00 GMT" + } + } ], + "variables" : [ "queue38693e14" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/setMetadata.json b/storage/client/queue/src/test/resources/session-records/setMetadata.json new file mode 100644 index 0000000000000..5d60ce89a352d --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/setMetadata.json @@ -0,0 +1,88 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue625780b6", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd2263a4-4003-0028-7675-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue625780b6?comp=metadata", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd2263c0-4003-0028-0f75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue625780b6?comp=metadata", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "Content-Length" : "0", + "x-ms-approximate-messages-count" : "0", + "x-ms-meta-metadata1" : "value1", + "StatusCode" : "200", + "x-ms-request-id" : "dd2263d2-4003-0028-2075-37b82d000000", + "x-ms-meta-metadata2" : "value2", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue625780b6/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd2263dd-4003-0028-2a75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue625780b6", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd2263ea-4003-0028-3775-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:39 GMT" + } + } ], + "variables" : [ "queue625780b6" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/setMetadataQueueDoesNotExist.json b/storage/client/queue/src/test/resources/session-records/setMetadataQueueDoesNotExist.json new file mode 100644 index 0000000000000..4d7536d402ced --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/setMetadataQueueDoesNotExist.json @@ -0,0 +1,42 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue570099c0?comp=metadata", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd2260d2-4003-0028-2175-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd2260d2-4003-0028-2175-37b82d000000\nTime:2019-07-10T23:18:38.2057923Z", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue570099c0/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd2260d9-4003-0028-2775-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd2260d9-4003-0028-2775-37b82d000000\nTime:2019-07-10T23:18:38.2538267Z", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue570099c0" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/setProperties.json b/storage/client/queue/src/test/resources/session-records/setProperties.json new file mode 100644 index 0000000000000..3c832f439b708 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/setProperties.json @@ -0,0 +1,114 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?restype=service&comp=properties", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d2906b5-6003-009e-0476-37b6d5000000", + "Body" : "1.0falsefalsefalsefalse1.0truetruetrue71.0falsefalse", + "Date" : "Wed, 10 Jul 2019 23:24:47 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net?restype=service&comp=properties", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "202", + "x-ms-request-id" : "0d2906d0-6003-009e-1a76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:47 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?restype=service&comp=properties", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d290712-6003-009e-4e76-37b6d5000000", + "Body" : "1.0falsetruetruetrue31.0truefalsetrue31.0truefalsetrue3", + "Date" : "Wed, 10 Jul 2019 23:24:47 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net?restype=service&comp=properties", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "202", + "x-ms-request-id" : "0d290721-6003-009e-5b76-37b6d5000000", + "Date" : "Wed, 10 Jul 2019 23:24:48 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?restype=service&comp=properties", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d290739-6003-009e-7076-37b6d5000000", + "Body" : "1.0falsefalsefalsefalse1.0truetruetrue71.0falsefalse", + "Date" : "Wed, 10 Jul 2019 23:24:48 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net?prefix=queue49487893&include=&comp=list", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "0d29074d-6003-009e-0176-37b6d5000000", + "Body" : "queue49487893", + "Date" : "Wed, 10 Jul 2019 23:24:48 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue49487893" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/setTooManyAccessPolicies.json b/storage/client/queue/src/test/resources/session-records/setTooManyAccessPolicies.json new file mode 100644 index 0000000000000..adee338b14141 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/setTooManyAccessPolicies.json @@ -0,0 +1,72 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue265747a2", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd22600f-4003-0028-7075-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue265747a2?comp=acl", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "InvalidXmlDocument", + "retry-after" : "0", + "Content-Length" : "294", + "StatusCode" : "400", + "x-ms-request-id" : "dd226022-4003-0028-0175-37b82d000000", + "Body" : "InvalidXmlDocumentXML specified is not syntactically valid.\nRequestId:dd226022-4003-0028-0175-37b82d000000\nTime:2019-07-10T23:18:37.6694120Z00", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue265747a2/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd226034-4003-0028-1175-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue265747a2", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd226043-4003-0028-2075-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:37 GMT" + } + } ], + "variables" : [ "queue265747a2" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/updateMessage.json b/storage/client/queue/src/test/resources/session-records/updateMessage.json new file mode 100644 index 0000000000000..46e184bda045c --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/updateMessage.json @@ -0,0 +1,128 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue4236461c", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd222c30-4003-0028-0f75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:02 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue4236461c/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd222c40-4003-0028-1c75-37b82d000000", + "Body" : "c3781181-9103-468e-b645-f6dbb100bd9cWed, 10 Jul 2019 23:18:02 GMTWed, 17 Jul 2019 23:18:02 GMTAgAAAAMAAAAAAAAAjQ/SuHU31QE=Wed, 10 Jul 2019 23:18:02 GMT", + "Date" : "Wed, 10 Jul 2019 23:18:02 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue4236461c/messages?numofmessages=1&visibilitytimeout=30", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd222c62-4003-0028-3b75-37b82d000000", + "Body" : "c3781181-9103-468e-b645-f6dbb100bd9cWed, 10 Jul 2019 23:18:02 GMTWed, 17 Jul 2019 23:18:02 GMTAgAAAAMAAAAAAAAAEAO9ynU31QE=Wed, 10 Jul 2019 23:18:32 GMT1test message", + "Date" : "Wed, 10 Jul 2019 23:18:02 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue4236461c/messages/c3781181-9103-468e-b645-f6dbb100bd9c?popreceipt=AgAAAAMAAAAAAAAAEAO9ynU31QE%3d&visibilitytimeout=1", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-time-next-visible" : "Wed, 10 Jul 2019 23:18:04 GMT", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd222c7f-4003-0028-5475-37b82d000000", + "x-ms-popreceipt" : "AwAAAAMAAAAAAAAAZuN9uXU31QEBAAAA", + "Date" : "Wed, 10 Jul 2019 23:18:02 GMT" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue4236461c/messages?peekonly=true", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd2230d0-4003-0028-1b75-37b82d000000", + "Body" : "c3781181-9103-468e-b645-f6dbb100bd9cWed, 10 Jul 2019 23:18:02 GMTWed, 17 Jul 2019 23:18:02 GMT1updated test message", + "Date" : "Wed, 10 Jul 2019 23:18:04 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue4236461c/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd2230e9-4003-0028-2e75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:04 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue4236461c", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd223113-4003-0028-4f75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:04 GMT" + } + } ], + "variables" : [ "queue4236461c" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/updateMessageInvalidMessageId.json b/storage/client/queue/src/test/resources/session-records/updateMessageInvalidMessageId.json new file mode 100644 index 0000000000000..eae58afb9650c --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/updateMessageInvalidMessageId.json @@ -0,0 +1,110 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue10019121", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd223139-4003-0028-6d75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:04 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue10019121/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd223159-4003-0028-0475-37b82d000000", + "Body" : "e3dbec12-5e3c-47f4-abd9-fbdf6e44746dWed, 10 Jul 2019 23:18:05 GMTWed, 17 Jul 2019 23:18:05 GMTAgAAAAMAAAAAAAAA7UtBunU31QE=Wed, 10 Jul 2019 23:18:05 GMT", + "Date" : "Wed, 10 Jul 2019 23:18:04 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue10019121/messages?numofmessages=1&visibilitytimeout=30", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd223169-4003-0028-1475-37b82d000000", + "Body" : "e3dbec12-5e3c-47f4-abd9-fbdf6e44746dWed, 10 Jul 2019 23:18:05 GMTWed, 17 Jul 2019 23:18:05 GMTAgAAAAMAAAAAAAAAc5EqzHU31QE=Wed, 10 Jul 2019 23:18:35 GMT1test message", + "Date" : "Wed, 10 Jul 2019 23:18:04 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue10019121/messages/e3dbec12-5e3c-47f4-abd9-fbdf6e44746drandom?popreceipt=AgAAAAMAAAAAAAAAc5EqzHU31QE%3d&visibilitytimeout=1", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "MessageNotFound", + "retry-after" : "0", + "Content-Length" : "221", + "StatusCode" : "404", + "x-ms-request-id" : "dd22317f-4003-0028-2775-37b82d000000", + "Body" : "MessageNotFoundThe specified message does not exist.\nRequestId:dd22317f-4003-0028-2775-37b82d000000\nTime:2019-07-10T23:18:05.3974051Z", + "Date" : "Wed, 10 Jul 2019 23:18:04 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue10019121/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd223195-4003-0028-3975-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:04 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue10019121", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd2231a9-4003-0028-4975-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:05 GMT" + } + } ], + "variables" : [ "queue10019121" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/updateMessageInvalidPopReceipt.json b/storage/client/queue/src/test/resources/session-records/updateMessageInvalidPopReceipt.json new file mode 100644 index 0000000000000..f7795c878f27f --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/updateMessageInvalidPopReceipt.json @@ -0,0 +1,110 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue41380e30", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd22326c-4003-0028-6c75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:05 GMT" + } + }, { + "Method" : "POST", + "Uri" : "https://sima.queue.core.windows.net/queue41380e30/messages?visibilitytimeout=0&messagettl=604800", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "dd22329c-4003-0028-1475-37b82d000000", + "Body" : "8900ad74-7404-4cd2-8b4b-41e70995dc1fWed, 10 Jul 2019 23:18:06 GMTWed, 17 Jul 2019 23:18:06 GMTAgAAAAMAAAAAAAAA/TyvunU31QE=Wed, 10 Jul 2019 23:18:06 GMT", + "Date" : "Wed, 10 Jul 2019 23:18:05 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "GET", + "Uri" : "https://sima.queue.core.windows.net/queue41380e30/messages?numofmessages=1&visibilitytimeout=30", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "Cache-Control" : "no-cache", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "dd2232d5-4003-0028-4575-37b82d000000", + "Body" : "8900ad74-7404-4cd2-8b4b-41e70995dc1fWed, 10 Jul 2019 23:18:06 GMTWed, 17 Jul 2019 23:18:06 GMTAgAAAAMAAAAAAAAA+kWZzHU31QE=Wed, 10 Jul 2019 23:18:36 GMT1test message", + "Date" : "Wed, 10 Jul 2019 23:18:05 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue41380e30/messages/8900ad74-7404-4cd2-8b4b-41e70995dc1f?popreceipt=AgAAAAMAAAAAAAAA%2bkWZzHU31QE%3drandom&visibilitytimeout=1", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "InvalidQueryParameterValue", + "retry-after" : "0", + "Content-Length" : "444", + "StatusCode" : "400", + "x-ms-request-id" : "dd2232ff-4003-0028-6d75-37b82d000000", + "Body" : "InvalidQueryParameterValueValue for one of the query parameters specified in the request URI is invalid.\nRequestId:dd2232ff-4003-0028-6d75-37b82d000000\nTime:2019-07-10T23:18:06.1209188ZpopreceiptAgAAAAMAAAAAAAAA+kWZzHU31QE=randomInvalid pop receipt format", + "Date" : "Wed, 10 Jul 2019 23:18:05 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue41380e30/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd22331d-4003-0028-0a75-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:05 GMT" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue41380e30", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "204", + "x-ms-request-id" : "dd223333-4003-0028-2075-37b82d000000", + "Date" : "Wed, 10 Jul 2019 23:18:05 GMT" + } + } ], + "variables" : [ "queue41380e30" ] +} \ No newline at end of file diff --git a/storage/client/queue/src/test/resources/session-records/updateMessageQueueDoesNotExist.json b/storage/client/queue/src/test/resources/session-records/updateMessageQueueDoesNotExist.json new file mode 100644 index 0000000000000..9341ea4a79897 --- /dev/null +++ b/storage/client/queue/src/test/resources/session-records/updateMessageQueueDoesNotExist.json @@ -0,0 +1,43 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://sima.queue.core.windows.net/queue77530b22/messages/doesn't?popreceipt=exist&visibilitytimeout=5", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0", + "Content-Type" : "application/xml; charset=utf-8" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "InvalidQueryParameterValue", + "retry-after" : "0", + "Content-Length" : "415", + "StatusCode" : "400", + "x-ms-request-id" : "dd2229e1-4003-0028-1475-37b82d000000", + "Body" : "InvalidQueryParameterValueValue for one of the query parameters specified in the request URI is invalid.\nRequestId:dd2229e1-4003-0028-1475-37b82d000000\nTime:2019-07-10T23:18:01.7878412ZpopreceiptexistInvalid pop receipt format", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT", + "Content-Type" : "application/xml" + } + }, { + "Method" : "DELETE", + "Uri" : "https://sima.queue.core.windows.net/queue77530b22/messages", + "Headers" : { + "x-ms-version" : "2018-03-28", + "User-Agent" : "azsdk-java-storage-queue/1.0.0-SNAPSHOT 1.8.0_201; Windows 10 10.0" + }, + "Response" : { + "x-ms-version" : "2018-03-28", + "Server" : "Windows-Azure-Queue/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-error-code" : "QueueNotFound", + "retry-after" : "0", + "Content-Length" : "217", + "StatusCode" : "404", + "x-ms-request-id" : "dd2229fb-4003-0028-2a75-37b82d000000", + "Body" : "QueueNotFoundThe specified queue does not exist.\nRequestId:dd2229fb-4003-0028-2a75-37b82d000000\nTime:2019-07-10T23:18:01.8368763Z", + "Date" : "Wed, 10 Jul 2019 23:18:01 GMT", + "Content-Type" : "application/xml" + } + } ], + "variables" : [ "queue77530b22" ] +} \ No newline at end of file From 366b477d0faf1c55f742596bfc80d6861af513ee Mon Sep 17 00:00:00 2001 From: alzimmermsft <48699787+alzimmermsft@users.noreply.github.com> Date: Mon, 22 Jul 2019 18:25:14 -0700 Subject: [PATCH 5/8] Beginning of code snippets for BlobAsyncClient --- .../azure/storage/blob/BlobAsyncClient.java | 42 ++- .../storage/blob}/AzureIdentityExample.java | 4 +- .../azure/storage/blob}/BasicExample.java | 6 +- .../BlobAsyncClientJavaDocCodeSnippets.java | 263 ++++++++++++++++++ .../blob/BlobClientJavaDocCodeSnippets.java | 4 + .../storage/blob}/FileTransferExample.java | 6 +- .../blob/JavaDocCodeSnippetsHelpers.java | 22 ++ .../storage/blob}/ListContainersExample.java | 4 +- .../azure/storage/blob}/SampleHelper.java | 2 + .../SetMetadataAndHTTPHeadersExample.java | 6 +- .../blob}/StorageErrorHandlingExample.java | 5 +- 11 files changed, 340 insertions(+), 24 deletions(-) rename storage/client/blob/src/samples/java/{ => com/azure/storage/blob}/AzureIdentityExample.java (93%) rename storage/client/blob/src/samples/java/{ => com/azure/storage/blob}/BasicExample.java (96%) create mode 100644 storage/client/blob/src/samples/java/com/azure/storage/blob/BlobAsyncClientJavaDocCodeSnippets.java create mode 100644 storage/client/blob/src/samples/java/com/azure/storage/blob/BlobClientJavaDocCodeSnippets.java rename storage/client/blob/src/samples/java/{ => com/azure/storage/blob}/FileTransferExample.java (97%) create mode 100644 storage/client/blob/src/samples/java/com/azure/storage/blob/JavaDocCodeSnippetsHelpers.java rename storage/client/blob/src/samples/java/{ => com/azure/storage/blob}/ListContainersExample.java (95%) rename storage/client/blob/src/samples/java/{ => com/azure/storage/blob}/SampleHelper.java (94%) rename storage/client/blob/src/samples/java/{ => com/azure/storage/blob}/SetMetadataAndHTTPHeadersExample.java (94%) rename storage/client/blob/src/samples/java/{ => com/azure/storage/blob}/StorageErrorHandlingExample.java (94%) diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java index c8ada7d8722fb..232b712c1b1d4 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java @@ -157,7 +157,11 @@ public URL getBlobUrl() { } /** - * Gets if the blob this client represents exists in the cloud. + * Determines if the blob this client represents exists in the cloud. + * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.exists} * * @return true if the blob exists, false if it doesn't */ @@ -171,8 +175,14 @@ public Mono> exists() { } /** - * Copies the data at the source URL to a blob. For more information, see the - * Azure Docs + * Copies the data at the source URL to a blob. + * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.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. @@ -182,8 +192,14 @@ public Mono> startCopyFromURL(URL sourceURL) { } /** - * Copies the data at the source URL to a blob. For more information, see the - * Azure Docs + * Copies the data at the source URL to a blob. + * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.startCopyFromURL#URL-Metadata-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} @@ -216,6 +232,10 @@ public Mono> startCopyFromURL(URL sourceURL, Metadata metadata, /** * 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.abortCopyFromURL#String} + * * @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. @@ -227,6 +247,10 @@ public Mono abortCopyFromURL(String copyId) { /** * 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.abortCopyFromURL#String-LeaseAccessConditions} + * * @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 @@ -242,6 +266,10 @@ public Mono abortCopyFromURL(String copyId, LeaseAccessConditions /** * 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.copyFromURL#URL} + * * @param copySource The source URL to copy from. * @return A reactive response containing the copy ID for the long running operation. */ @@ -252,6 +280,10 @@ public Mono> copyFromURL(URL copySource) { /** * 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.copyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions} + * * @param copySource The source URL to copy from. URLs outside of Azure may only be copied to block blobs. * @param metadata {@link Metadata} * @param sourceModifiedAccessConditions {@link ModifiedAccessConditions} against the source. Standard HTTP Access diff --git a/storage/client/blob/src/samples/java/AzureIdentityExample.java b/storage/client/blob/src/samples/java/com/azure/storage/blob/AzureIdentityExample.java similarity index 93% rename from storage/client/blob/src/samples/java/AzureIdentityExample.java rename to storage/client/blob/src/samples/java/com/azure/storage/blob/AzureIdentityExample.java index 6550c8c02a76d..061c01f4a4e26 100644 --- a/storage/client/blob/src/samples/java/AzureIdentityExample.java +++ b/storage/client/blob/src/samples/java/com/azure/storage/blob/AzureIdentityExample.java @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +package com.azure.storage.blob; + import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.storage.blob.StorageClient; -import com.azure.storage.blob.StorageClientBuilder; import java.util.Locale; diff --git a/storage/client/blob/src/samples/java/BasicExample.java b/storage/client/blob/src/samples/java/com/azure/storage/blob/BasicExample.java similarity index 96% rename from storage/client/blob/src/samples/java/BasicExample.java rename to storage/client/blob/src/samples/java/com/azure/storage/blob/BasicExample.java index 3f8edbd367cb8..ec4c93a4dcea0 100644 --- a/storage/client/blob/src/samples/java/BasicExample.java +++ b/storage/client/blob/src/samples/java/com/azure/storage/blob/BasicExample.java @@ -1,10 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import com.azure.storage.blob.BlockBlobClient; -import com.azure.storage.blob.ContainerClient; -import com.azure.storage.blob.StorageClient; -import com.azure.storage.blob.StorageClientBuilder; +package com.azure.storage.blob; + import com.azure.storage.common.credentials.SharedKeyCredential; import java.io.ByteArrayInputStream; diff --git a/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobAsyncClientJavaDocCodeSnippets.java b/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobAsyncClientJavaDocCodeSnippets.java new file mode 100644 index 0000000000000..a516e22b8ed07 --- /dev/null +++ b/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobAsyncClientJavaDocCodeSnippets.java @@ -0,0 +1,263 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +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.ReliableDownloadOptions; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URL; +import java.time.OffsetDateTime; +import java.util.Collections; + +/** + * Code snippets for {@link BlobAsyncClient} + */ +public class BlobAsyncClientJavaDocCodeSnippets { + + private String blobName = "blob"; + private BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + private String leaseId = "lease"; + private String copyId = "copyId"; + private URL url = JavaDocCodeSnippetsHelpers.generateURL("https://sample.com"); + private String file = "file"; + + /** + * Code snippet for {@link BlobAsyncClient#exists()} + */ + public void existsCodeSnippet() { + // BEGIN: com.azure.storage.blob.exists + client.exists().subscribe(response -> System.out.printf("Exists? %b%n", response.value())); + // END: com.azure.storage.blob.exists + } + + /** + * Code snippets for {@link BlobAsyncClient#startCopyFromURL(URL)} and + * {@link BlobAsyncClient#startCopyFromURL(URL, Metadata, ModifiedAccessConditions, BlobAccessConditions)} + */ + public void startCopyFromURL() { + // BEGIN: com.azure.storage.blob.startCopyFromURL#URL + client.startCopyFromURL(url) + .subscribe(response -> System.out.printf("Copy identifier: %s%n", response.value())); + // END: com.azure.storage.blob.startCopyFromURL#URL + + // BEGIN: com.azure.storage.blob.startCopyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions + Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions().ifUnmodifiedSince(OffsetDateTime.now().minusDays(7)); + BlobAccessConditions blobAccessConditions = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); + + client.startCopyFromURL(url, metadata, modifiedAccessConditions, blobAccessConditions) + .subscribe(response -> System.out.printf("Copy identifier: %s%n", response.value())); + // END: com.azure.storage.blob.startCopyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions + } + + /** + * Code snippets for {@link BlobAsyncClient#abortCopyFromURL(String)} and + * {@link BlobAsyncClient#abortCopyFromURL(String, LeaseAccessConditions)} + */ + public void abortCopyFromURL() { + // BEGIN: com.azure.storage.blob.abortCopyFromURL#String + client.abortCopyFromURL(copyId) + .subscribe(response -> System.out.printf("Aborted copy completed with status %d%n", response.statusCode())); + // END: com.azure.storage.blob.abortCopyFromURL#String + + // BEGIN: com.azure.storage.blob.abortCopyFromURL#String-LeaseAccessConditions + LeaseAccessConditions leaseAccessConditions = new LeaseAccessConditions().leaseId(leaseId); + client.abortCopyFromURL(copyId, leaseAccessConditions) + .subscribe(response -> System.out.printf("Aborted copy completed with status %d%n", response.statusCode())); + // END: com.azure.storage.blob.abortCopyFromURL#String-LeaseAccessConditions + } + + /** + * Code snippets for {@link BlobAsyncClient#copyFromURL(URL)} and + * {@link BlobAsyncClient#copyFromURL(URL, Metadata, ModifiedAccessConditions, BlobAccessConditions)} + */ + public void copyFromURL() { + // BEGIN: com.azure.storage.blob.copyFromURL#URL + client.copyFromURL(url).subscribe(response -> System.out.printf("Copy identifier: %s%n", response.value())); + // END: com.azure.storage.blob.copyFromURL#URL + + // BEGIN: com.azure.storage.blob.copyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions + Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions().ifUnmodifiedSince(OffsetDateTime.now().minusDays(7)); + BlobAccessConditions blobAccessConditions = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); + + client.copyFromURL(url, metadata, modifiedAccessConditions, blobAccessConditions) + .subscribe(response -> System.out.printf("Copy identifier: %s%n", response.value())); + // END: com.azure.storage.blob.copyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions + } + + /** + * Code snippets for {@link BlobAsyncClient#download()} and + * {@link BlobAsyncClient#download(BlobRange, BlobAccessConditions, boolean, ReliableDownloadOptions)} + */ + public void download() { + // BEGIN: com.azure.storage.blob.download + client.download().subscribe(response -> { + ByteArrayOutputStream downloadData = new ByteArrayOutputStream(); + response.value().subscribe(piece -> { + try { + downloadData.write(piece.array()); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); + }); + // END: com.azure.storage.blob.download + + // BEGIN: com.azure.storage.blob.download#BlobRange-BlobAccessConditions-boolean-ReliableDownloadOptions + BlobRange range = new BlobRange(1024, 2048); + ReliableDownloadOptions options = new ReliableDownloadOptions().maxRetryRequests(5); + + client.download(range, null, false, options).subscribe(response -> { + ByteArrayOutputStream downloadData = new ByteArrayOutputStream(); + response.value().subscribe(piece -> { + try { + downloadData.write(piece.array()); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); + }); + // END: com.azure.storage.blob.download#BlobRange-BlobAccessConditions-boolean-ReliableDownloadOptions + } + + /** + * Code snippets for {@link BlobAsyncClient#downloadToFile(String)} and + * {@link BlobAsyncClient#downloadToFile(String, BlobRange, Integer, BlobAccessConditions, boolean, ReliableDownloadOptions)} + */ + public void downloadToFile() { + // BEGIN: com.azure.storage.blob.downloadToFile#String + client.downloadToFile(file).subscribe(response -> System.out.println("Completed download to file")); + // END: com.azure.storage.blob.downloadToFile#String + + // BEGIN: com.azure.storage.blob.downloadToFile#String-BlobRange-Integer-BlobAccessConditions-boolean-ReliableDownloadOptions + BlobRange range = new BlobRange(1024, 2048); + ReliableDownloadOptions options = new ReliableDownloadOptions().maxRetryRequests(5); + + client.downloadToFile(file, range, null, null, false, options) + .subscribe(response -> System.out.println("Completed download to file")); + // END: com.azure.storage.blob.downloadToFile#String-BlobRange-Integer-BlobAccessConditions-boolean-ReliableDownloadOptions + } + + /** + * Code snippets for {@link BlobAsyncClient#delete()} and + * {@link BlobAsyncClient#delete(DeleteSnapshotsOptionType, BlobAccessConditions)} + */ + public void delete() { + // BEGIN: com.azure.storage.blob.delete + client.delete().subscribe(response -> System.out.printf("Delete completed with status %d%n", response.statusCode())); + // END: com.azure.storage.blob.delete + + // BEGIN: com.azure.storage.blob.delete#DeleteSnapshotsOptionType-BlobAccessConditions + client.delete(DeleteSnapshotsOptionType.INCLUDE, null) + .subscribe(response -> System.out.printf("Delete completed with status %d%n", response.statusCode())); + // END: com.azure.storage.blob.delete#DeleteSnapshotsOptionType-BlobAccessConditions + } + + /** + * Code snippets for {@link BlobAsyncClient#getProperties()} and + * {@link BlobAsyncClient#getProperties(BlobAccessConditions)} + */ + public void getProperties() { + BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + } + + /** + * Code snippets for {@link BlobAsyncClient#setHTTPHeaders(BlobHTTPHeaders)} and + * {@link BlobAsyncClient#setHTTPHeaders(BlobHTTPHeaders, BlobAccessConditions)} + */ + public void setHTTPHeaders() { + BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + } + + /** + * Code snippets for {@link BlobAsyncClient#setMetadata(Metadata)} and + * {@link BlobAsyncClient#setMetadata(Metadata, BlobAccessConditions)} + */ + public void setMetadata() { + BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + } + + /** + * Code snippets for {@link BlobAsyncClient#createSnapshot()} and + * {@link BlobAsyncClient#createSnapshot(Metadata, BlobAccessConditions)} + */ + public void createSnapshot() { + BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + } + + /** + * Code snippets for {@link BlobAsyncClient#setTier(AccessTier)} and + * {@link BlobAsyncClient#setTier(AccessTier, LeaseAccessConditions)} + */ + public void setTier() { + BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + } + + /** + * Code snippet for {@link BlobAsyncClient#undelete()} + */ + public void undelete() { + BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + } + + /** + * Code snippets for {@link BlobAsyncClient#acquireLease(String, int)} and + * {@link BlobAsyncClient#acquireLease(String, int, ModifiedAccessConditions)} + */ + public void acquireLease() { + BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + } + + /** + * Code snippets for {@link BlobAsyncClient#renewLease(String)} and + * {@link BlobAsyncClient#renewLease(String, ModifiedAccessConditions)} + */ + public void renewLease() { + BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + } + + /** + * Code snippets for {@link BlobAsyncClient#releaseLease(String)} and + * {@link BlobAsyncClient#releaseLease(String, ModifiedAccessConditions)} + */ + public void releaseLease() { + BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + } + + /** + * Code snippets for {@link BlobAsyncClient#breakLease()} and + * {@link BlobAsyncClient#breakLease(Integer, ModifiedAccessConditions)} + */ + public void breakLease() { + BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + } + + /** + * Code snippets for {@link BlobAsyncClient#changeLease(String, String)} and + * {@link BlobAsyncClient#changeLease(String, String, ModifiedAccessConditions)} + */ + public void changeLease() { + BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + } + + /** + * Code snippet for {@link BlobAsyncClient#getAccountInfo()} + */ + public void getAccountInfo() { + BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + } +} diff --git a/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobClientJavaDocCodeSnippets.java b/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobClientJavaDocCodeSnippets.java new file mode 100644 index 0000000000000..ea779ce3e0558 --- /dev/null +++ b/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobClientJavaDocCodeSnippets.java @@ -0,0 +1,4 @@ +package com.azure.storage.blob; + +public class BlobClientJavaDocCodeSnippets { +} diff --git a/storage/client/blob/src/samples/java/FileTransferExample.java b/storage/client/blob/src/samples/java/com/azure/storage/blob/FileTransferExample.java similarity index 97% rename from storage/client/blob/src/samples/java/FileTransferExample.java rename to storage/client/blob/src/samples/java/com/azure/storage/blob/FileTransferExample.java index ff3b9376bfc50..befe616e10749 100644 --- a/storage/client/blob/src/samples/java/FileTransferExample.java +++ b/storage/client/blob/src/samples/java/com/azure/storage/blob/FileTransferExample.java @@ -1,10 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import com.azure.storage.blob.BlockBlobClient; -import com.azure.storage.blob.ContainerClient; -import com.azure.storage.blob.StorageClient; -import com.azure.storage.blob.StorageClientBuilder; +package com.azure.storage.blob; + import com.azure.storage.common.credentials.SharedKeyCredential; import java.io.File; diff --git a/storage/client/blob/src/samples/java/com/azure/storage/blob/JavaDocCodeSnippetsHelpers.java b/storage/client/blob/src/samples/java/com/azure/storage/blob/JavaDocCodeSnippetsHelpers.java new file mode 100644 index 0000000000000..aafc13dde6912 --- /dev/null +++ b/storage/client/blob/src/samples/java/com/azure/storage/blob/JavaDocCodeSnippetsHelpers.java @@ -0,0 +1,22 @@ +package com.azure.storage.blob; + +import java.net.MalformedURLException; +import java.net.URL; + +final class JavaDocCodeSnippetsHelpers { + static ContainerAsyncClient getContainerAsyncClient() { + return new ContainerClientBuilder().buildAsyncClient(); + } + + static BlobAsyncClient getBlobAsyncClient(String blobName) { + return getContainerAsyncClient().getBlobAsyncClient(blobName); + } + + static URL generateURL(String urlString) { + try { + return new URL(urlString); + } catch (MalformedURLException ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/storage/client/blob/src/samples/java/ListContainersExample.java b/storage/client/blob/src/samples/java/com/azure/storage/blob/ListContainersExample.java similarity index 95% rename from storage/client/blob/src/samples/java/ListContainersExample.java rename to storage/client/blob/src/samples/java/com/azure/storage/blob/ListContainersExample.java index ab8c9b3709bc7..f88d406ca5c58 100644 --- a/storage/client/blob/src/samples/java/ListContainersExample.java +++ b/storage/client/blob/src/samples/java/com/azure/storage/blob/ListContainersExample.java @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import com.azure.storage.blob.StorageClient; -import com.azure.storage.blob.StorageClientBuilder; +package com.azure.storage.blob; + import com.azure.storage.common.credentials.SharedKeyCredential; import java.util.Locale; diff --git a/storage/client/blob/src/samples/java/SampleHelper.java b/storage/client/blob/src/samples/java/com/azure/storage/blob/SampleHelper.java similarity index 94% rename from storage/client/blob/src/samples/java/SampleHelper.java rename to storage/client/blob/src/samples/java/com/azure/storage/blob/SampleHelper.java index d841413f06bc0..f72655d856bd7 100644 --- a/storage/client/blob/src/samples/java/SampleHelper.java +++ b/storage/client/blob/src/samples/java/com/azure/storage/blob/SampleHelper.java @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +package com.azure.storage.blob; + import com.azure.core.util.configuration.ConfigurationManager; /** diff --git a/storage/client/blob/src/samples/java/SetMetadataAndHTTPHeadersExample.java b/storage/client/blob/src/samples/java/com/azure/storage/blob/SetMetadataAndHTTPHeadersExample.java similarity index 94% rename from storage/client/blob/src/samples/java/SetMetadataAndHTTPHeadersExample.java rename to storage/client/blob/src/samples/java/com/azure/storage/blob/SetMetadataAndHTTPHeadersExample.java index 6b475499eab2c..b6c6bb40d090c 100644 --- a/storage/client/blob/src/samples/java/SetMetadataAndHTTPHeadersExample.java +++ b/storage/client/blob/src/samples/java/com/azure/storage/blob/SetMetadataAndHTTPHeadersExample.java @@ -1,10 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import com.azure.storage.blob.BlockBlobClient; -import com.azure.storage.blob.ContainerClient; -import com.azure.storage.blob.StorageClient; -import com.azure.storage.blob.StorageClientBuilder; +package com.azure.storage.blob; + import com.azure.storage.blob.models.BlobHTTPHeaders; import com.azure.storage.blob.models.Metadata; import com.azure.storage.common.credentials.SharedKeyCredential; diff --git a/storage/client/blob/src/samples/java/StorageErrorHandlingExample.java b/storage/client/blob/src/samples/java/com/azure/storage/blob/StorageErrorHandlingExample.java similarity index 94% rename from storage/client/blob/src/samples/java/StorageErrorHandlingExample.java rename to storage/client/blob/src/samples/java/com/azure/storage/blob/StorageErrorHandlingExample.java index 50d4e81d600c0..3a84d7026f7b5 100644 --- a/storage/client/blob/src/samples/java/StorageErrorHandlingExample.java +++ b/storage/client/blob/src/samples/java/com/azure/storage/blob/StorageErrorHandlingExample.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +package com.azure.storage.blob; + import com.azure.core.http.HttpResponse; -import com.azure.storage.blob.ContainerClient; -import com.azure.storage.blob.ContainerClientBuilder; -import com.azure.storage.blob.StorageException; import com.azure.storage.blob.models.StorageErrorCode; /** From 0b7eebc48b3af9d72b34ba8b78fda29c78b03b49 Mon Sep 17 00:00:00 2001 From: alzimmermsft <48699787+alzimmermsft@users.noreply.github.com> Date: Tue, 23 Jul 2019 11:05:31 -0700 Subject: [PATCH 6/8] JavaDoc snippets for BlobAsyncClient and BlobClient --- .../azure/storage/blob/BlobAsyncClient.java | 182 +++++++-- .../com/azure/storage/blob/BlobClient.java | 227 +++++++++-- .../BlobAsyncClientJavaDocCodeSnippets.java | 204 +++++++--- .../blob/BlobClientJavaDocCodeSnippets.java | 371 ++++++++++++++++++ .../blob/JavaDocCodeSnippetsHelpers.java | 4 + 5 files changed, 865 insertions(+), 123 deletions(-) diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java index 232b712c1b1d4..2aa05f99e6240 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java @@ -161,7 +161,7 @@ public URL getBlobUrl() { * *

Code Samples

* - * {@codesnippet com.azure.storage.blob.exists} + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.exists} * * @return true if the blob exists, false if it doesn't */ @@ -179,7 +179,7 @@ public Mono> exists() { * *

Code Samples

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

For more information, see the * Azure Docs

@@ -196,7 +196,7 @@ public Mono> startCopyFromURL(URL sourceURL) { * *

Code Samples

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

For more information, see the * Azure Docs

@@ -234,7 +234,7 @@ public Mono> startCopyFromURL(URL sourceURL, Metadata metadata, * *

Code Samples

* - * {@codesnippet com.azure.storage.blob.abortCopyFromURL#String} + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.abortCopyFromURL#String} * * @param copyId The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link * BlobStartCopyFromURLHeaders} object. @@ -249,7 +249,7 @@ public Mono abortCopyFromURL(String copyId) { * *

Code Samples

* - * {@codesnippet com.azure.storage.blob.abortCopyFromURL#String-LeaseAccessConditions} + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.abortCopyFromURL#String-LeaseAccessConditions} * * @param copyId The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link * BlobStartCopyFromURLHeaders} object. @@ -268,7 +268,7 @@ public Mono abortCopyFromURL(String copyId, LeaseAccessConditions * *

Code Samples

* - * {@codesnippet com.azure.storage.blob.copyFromURL#URL} + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.copyFromURL#URL} * * @param copySource The source URL to copy from. * @return A reactive response containing the copy ID for the long running operation. @@ -282,7 +282,7 @@ public Mono> copyFromURL(URL copySource) { * *

Code Samples

* - * {@codesnippet com.azure.storage.blob.copyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions} + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.copyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions} * * @param copySource The source URL to copy from. URLs outside of Azure may only be copied to block blobs. * @param metadata {@link Metadata} @@ -316,23 +316,31 @@ public Mono> copyFromURL(URL copySource, Metadata metadata, Mod * 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} + * * @return A reactive response containing the blob data. */ public Mono>> download() { - return this.download(null, null, false, null); + return this.download(null, null, null, false); } /** * 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.download#BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean} + * * @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 options {@link ReliableDownloadOptions} * @return A reactive response containing the blob data. */ - public Mono>> download(BlobRange range, BlobAccessConditions accessConditions, boolean rangeGetContentMD5, ReliableDownloadOptions options) { + public Mono>> download(BlobRange range, ReliableDownloadOptions options, BlobAccessConditions accessConditions, boolean rangeGetContentMD5) { return this.download(range, accessConditions, rangeGetContentMD5) .map(response -> new SimpleResponse<>( response.rawResponse(), @@ -390,11 +398,15 @@ Mono download(BlobRange range, BlobAccessConditions acces * This method makes an extra HTTP call to get the length of the blob in the beginning. To avoid this extra call, * use the other overload providing the {@link BlobRange} parameter. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.downloadToFile#String} + * * @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 this.downloadToFile(filePath, null, BLOB_DEFAULT_DOWNLOAD_BLOCK_SIZE, null, false, null); + return this.downloadToFile(filePath, null, BLOB_DEFAULT_DOWNLOAD_BLOCK_SIZE, null, null, false); } /** @@ -405,18 +417,22 @@ public Mono downloadToFile(String filePath) { * 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} + * * @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 options {@link ReliableDownloadOptions} * @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, BlobAccessConditions accessConditions, - boolean rangeGetContentMD5, ReliableDownloadOptions options) { + public Mono downloadToFile(String filePath, BlobRange range, Integer blockSize, ReliableDownloadOptions options, + BlobAccessConditions accessConditions, boolean rangeGetContentMD5) { if (blockSize < 0 || blockSize > BLOB_MAX_DOWNLOAD_BLOCK_SIZE) { throw new IllegalArgumentException("Block size should not exceed 100MB"); } @@ -471,6 +487,10 @@ private List sliceBlobRange(BlobRange blobRange, Integer blockSize) { /** * 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} + * * @return A reactive response signalling completion. */ public Mono delete() { @@ -480,6 +500,10 @@ public Mono delete() { /** * 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#DeleteSnapshotsOptionType-BlobAccessConditions} + * * @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. @@ -499,6 +523,10 @@ public Mono delete(DeleteSnapshotsOptionType deleteBlobSnapshotOpt /** * Returns the blob's metadata and properties. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.getProperties} + * * @return A reactive response containing the blob properties and metadata. */ public Mono> getProperties() { @@ -508,6 +536,10 @@ public Mono> getProperties() { /** * Returns the blob's metadata and properties. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.getProperties#BlobAccessConditions} + * * @param accessConditions {@link BlobAccessConditions} * @return A reactive response containing the blob properties and metadata. */ @@ -527,6 +559,10 @@ public Mono> getProperties(BlobAccessConditions accessC * see the * Azure Docs. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.setHTTPHeaders#BlobHTTPHeaders} + * * @param headers {@link BlobHTTPHeaders} * @return A reactive response signalling completion. */ @@ -540,6 +576,10 @@ public Mono setHTTPHeaders(BlobHTTPHeaders headers) { * see the * Azure Docs. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.setHTTPHeaders#BlobHTTPHeaders-BlobAccessConditions} + * * @param headers {@link BlobHTTPHeaders} * @param accessConditions {@link BlobAccessConditions} * @return A reactive response signalling completion. @@ -558,6 +598,10 @@ public Mono setHTTPHeaders(BlobHTTPHeaders headers, BlobAccessCond * must be preserved, they must be downloaded and included in the call to this method. For more information, see the * Azure Docs. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.setMetadata#Metadata} + * * @param metadata {@link Metadata} * @return A reactive response signalling completion. */ @@ -570,6 +614,10 @@ public Mono setMetadata(Metadata metadata) { * must be preserved, they must be downloaded and included in the call to this method. For more information, see the * Azure Docs. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.setMetadata#Metadata-BlobAccessConditions} + * * @param metadata {@link Metadata} * @param accessConditions {@link BlobAccessConditions} * @return A reactive response signalling completion. @@ -588,6 +636,10 @@ public Mono setMetadata(Metadata metadata, BlobAccessConditions ac /** * Creates a read-only snapshot of a blob. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.createSnapshot} + * * @return A reactive response containing the ID of the new snapshot. */ public Mono> createSnapshot() { @@ -597,6 +649,10 @@ public Mono> createSnapshot() { /** * Creates a read-only snapshot of a blob. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.createSnapshot#Metadata-BlobAccessConditions} + * * @param metadata {@link Metadata} * @param accessConditions {@link BlobAccessConditions} * @return A reactive response containing the ID of the new snapshot. @@ -618,6 +674,10 @@ public Mono> createSnapshot(Metadata metadata, BlobAccessCondit * 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} + * * @param tier The new tier for the blob. * @return A reactive response signalling completion. */ @@ -631,6 +691,10 @@ public Mono setTier(AccessTier tier) { * 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-LeaseAccessConditions} + * * @param tier The new tier for the blob. * @param leaseAccessConditions By setting lease access conditions, requests will fail if the provided lease does * not match the active lease on the blob. @@ -647,6 +711,10 @@ public Mono setTier(AccessTier tier, LeaseAccessConditions leaseAc /** * 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} + * * @return A reactive response signalling completion. */ public Mono undelete() { @@ -659,6 +727,10 @@ public Mono undelete() { * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 * seconds, or infinite (-1). * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.acquireLease#String-int} + * * @param proposedId A {@code String} in any valid GUID format. May be null. * @param duration The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A * non-infinite lease can be between 15 and 60 seconds. @@ -672,7 +744,11 @@ public Mono> acquireLease(String proposedId, int duration) { * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 * seconds, or infinite (-1). * - * @param proposedID A {@code String} in any valid GUID format. May be null. + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.acquireLease#String-int-ModifiedAccessConditions} + * + * @param proposedId A {@code String} in any valid GUID format. May be null. * @param duration The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A * non-infinite lease can be between 15 and 60 seconds. * @param modifiedAccessConditions Standard HTTP Access conditions related to the modification of data. ETag and @@ -681,7 +757,7 @@ public Mono> acquireLease(String proposedId, int duration) { * @return A reactive response containing the lease ID. * @throws IllegalArgumentException If {@code duration} is outside the bounds of 15 to 60 or isn't -1. */ - public Mono> acquireLease(String proposedID, int duration, ModifiedAccessConditions modifiedAccessConditions) { + public Mono> acquireLease(String proposedId, int duration, ModifiedAccessConditions modifiedAccessConditions) { if (!(duration == -1 || (duration >= 15 && duration <= 60))) { // Throwing is preferred to Mono.error because this will error out immediately instead of waiting until // subscription. @@ -689,7 +765,7 @@ public Mono> acquireLease(String proposedID, int duration, Modi } return postProcessResponse(this.azureBlobStorage.blobs().acquireLeaseWithRestResponseAsync( - null, null, null, duration, proposedID, null, + null, null, null, duration, proposedId, null, modifiedAccessConditions, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseId())); } @@ -697,50 +773,66 @@ public Mono> acquireLease(String proposedID, int duration, Modi /** * Renews the blob's previously-acquired lease. * - * @param leaseID The leaseId of the active lease on the blob. + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.renewLease#String} + * + * @param leaseId The leaseId of the active lease on the blob. * @return A reactive response containing the renewed lease ID. */ - public Mono> renewLease(String leaseID) { - return this.renewLease(leaseID, null); + public Mono> renewLease(String leaseId) { + return this.renewLease(leaseId, null); } /** * Renews the blob's previously-acquired lease. * - * @param leaseID The leaseId of the active lease on the blob. + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.renewLease#String-ModifiedAccessConditions} + * + * @param leaseId The leaseId of the active lease on the blob. * @param modifiedAccessConditions 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. * @return A reactive response containing the renewed lease ID. */ - public Mono> renewLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions) { + public Mono> renewLease(String leaseId, ModifiedAccessConditions modifiedAccessConditions) { return postProcessResponse(this.azureBlobStorage.blobs().renewLeaseWithRestResponseAsync(null, - null, leaseID, null, null, modifiedAccessConditions, Context.NONE)) + null, leaseId, null, null, modifiedAccessConditions, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseId())); } /** * Releases the blob's previously-acquired lease. * - * @param leaseID The leaseId of the active lease on the blob. + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.releaseLease#String} + * + * @param leaseId The leaseId of the active lease on the blob. * @return A reactive response signalling completion. */ - public Mono releaseLease(String leaseID) { - return this.releaseLease(leaseID, null); + public Mono releaseLease(String leaseId) { + return this.releaseLease(leaseId, null); } /** * Releases the blob's previously-acquired lease. * - * @param leaseID The leaseId of the active lease on the blob. + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.releaseLease#String-ModifiedAccessConditions} + * + * @param leaseId The leaseId of the active lease on the blob. * @param modifiedAccessConditions 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. * @return A reactive response signalling completion. */ - public Mono releaseLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions) { + public Mono releaseLease(String leaseId, ModifiedAccessConditions modifiedAccessConditions) { return postProcessResponse(this.azureBlobStorage.blobs().releaseLeaseWithRestResponseAsync(null, - null, leaseID, null, null, modifiedAccessConditions, Context.NONE)) + null, leaseId, null, null, modifiedAccessConditions, Context.NONE)) .map(VoidResponse::new); } @@ -748,6 +840,10 @@ public Mono releaseLease(String leaseID, ModifiedAccessConditions * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant * to break a fixed-duration lease when it expires or an infinite lease immediately. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.breakLease} + * * @return A reactive response containing the remaining time in the broken lease in seconds. */ public Mono> breakLease() { @@ -758,6 +854,10 @@ public Mono> breakLease() { * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant * to break a fixed-duration lease when it expires or an infinite lease immediately. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.breakLease#Integer-ModifiedAccessConditions} + * * @param breakPeriodInSeconds An optional {@code Integer} representing the proposed duration of seconds that the * lease should continue before it is broken, between 0 and 60 seconds. This break period is only used if it is * shorter than the time remaining on the lease. If longer, the time remaining on the lease is used. A new lease @@ -777,28 +877,36 @@ public Mono> breakLease(Integer breakPeriodInSeconds, Modified /** * ChangeLease changes the blob's lease ID. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.changeLease#String-String} + * * @param leaseId The leaseId of the active lease on the blob. - * @param proposedID A {@code String} in any valid GUID format. + * @param proposedId A {@code String} in any valid GUID format. * @return A reactive response containing the new lease ID. */ - public Mono> changeLease(String leaseId, String proposedID) { - return this.changeLease(leaseId, proposedID, null); + public Mono> changeLease(String leaseId, String proposedId) { + return this.changeLease(leaseId, proposedId, null); } /** * ChangeLease changes the blob's lease ID. For more information, see the Azure * Docs. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.changeLease#String-String-ModifiedAccessConditions} + * * @param leaseId The leaseId of the active lease on the blob. - * @param proposedID A {@code String} in any valid GUID format. + * @param proposedId A {@code String} in any valid GUID format. * @param modifiedAccessConditions 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. * @return A reactive response containing the new lease ID. */ - public Mono> changeLease(String leaseId, String proposedID, ModifiedAccessConditions modifiedAccessConditions) { + public Mono> changeLease(String leaseId, String proposedId, ModifiedAccessConditions modifiedAccessConditions) { return postProcessResponse(this.azureBlobStorage.blobs().changeLeaseWithRestResponseAsync(null, - null, leaseId, proposedID, null, null, modifiedAccessConditions, Context.NONE)) + null, leaseId, proposedId, null, null, modifiedAccessConditions, Context.NONE)) .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseId())); } @@ -806,6 +914,10 @@ public Mono> changeLease(String leaseId, String proposedID, Mod * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobAsyncClient.getAccountInfo} + * * @return a reactor response containing the sku name and account kind. */ // TODO (unknown): determine this return type diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java index a937b8ca47613..04c15df61a8dd 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java @@ -135,6 +135,10 @@ public final BlobInputStream openInputStream(BlobRange range, BlobAccessConditio /** * 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 Response exists() { @@ -144,6 +148,10 @@ public Response exists() { /** * Gets if the container this client represents exists in the cloud. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.exists#Duration} + * * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return true if the container exists, false if it doesn't */ @@ -157,6 +165,10 @@ public Response exists(Duration timeout) { * Copies the data at the source URL to a blob. For more information, see the * Azure Docs * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.startCopyFromURL#URL} + * * @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. */ @@ -168,6 +180,10 @@ public Response startCopyFromURL(URL sourceURL) { * Copies the data at the source URL to a blob. For more information, see the * Azure Docs * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.startCopyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions-Duration} + * * @param sourceURL The source URL to copy from. URLs outside of Azure may only be copied to block blobs. * @param metadata {@link Metadata} * @param sourceModifiedAccessConditions {@link ModifiedAccessConditions} against the source. Standard HTTP Access @@ -190,6 +206,10 @@ public Response startCopyFromURL(URL sourceURL, Metadata metadata, /** * 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} + * * @param copyId The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link * BlobStartCopyFromURLHeaders} object. * @return A response containing status code and HTTP headers. @@ -201,6 +221,10 @@ public VoidResponse abortCopyFromURL(String copyId) { /** * 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-LeaseAccessConditions-Duration} + * * @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 @@ -218,6 +242,10 @@ public VoidResponse abortCopyFromURL(String copyId, LeaseAccessConditions leaseA /** * 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} + * * @param copySource The source URL to copy from. * @return The copy ID for the long running operation. */ @@ -228,6 +256,10 @@ public Response copyFromURL(URL copySource) { /** * 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-Metadata-ModifiedAccessConditions-BlobAccessConditions-Duration} + * * @param copySource The source URL to copy from. URLs outside of Azure may only be copied to block blobs. * @param metadata {@link Metadata} * @param sourceModifiedAccessConditions {@link ModifiedAccessConditions} against the source. Standard HTTP Access @@ -251,6 +283,10 @@ public Response copyFromURL(URL copySource, Metadata metadata, * 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} + * * @param stream A non-null {@link OutputStream} instance where the downloaded data will be written. * @return A response containing status code and HTTP headers. * @throws UncheckedIOException If an I/O error occurs. @@ -263,19 +299,23 @@ public VoidResponse download(OutputStream stream) { * 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.download#OutputStream-BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration} + * * @param stream A non-null {@link OutputStream} instance where the downloaded data will be written. - * @param options {@link ReliableDownloadOptions} * @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. * @return A response containing status code and HTTP headers. * @throws UncheckedIOException If an I/O error occurs. */ - public VoidResponse download(OutputStream stream, ReliableDownloadOptions options, BlobRange range, + public VoidResponse download(OutputStream stream, BlobRange range, ReliableDownloadOptions options, BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Duration timeout) { Mono download = blobAsyncClient - .download(range, accessConditions, rangeGetContentMD5, options) + .download(range, options, accessConditions, rangeGetContentMD5) .flatMapMany(res -> res.value() .doOnNext(bf -> { try { @@ -295,10 +335,14 @@ public VoidResponse download(OutputStream stream, ReliableDownloadOptions option * Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link * AppendBlobClient}. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.downloadToFile#String} + * * @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written. - * @throws IOException If an I/O error occurs + * @throws UncheckedIOException If an I/O error occurs */ - public void downloadToFile(String filePath) throws IOException { + public void downloadToFile(String filePath) { blobAsyncClient.downloadToFile(filePath); } @@ -307,29 +351,33 @@ public void downloadToFile(String filePath) throws IOException { * Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link * AppendBlobClient}. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.downloadToFile#String-BlobRange-Integer-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration} + * * @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written. - * @param options {@link ReliableDownloadOptions} * @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. - * @throws IOException If an I/O error occurs + * @throws UncheckedIOException If an I/O error occurs */ - public void downloadToFile(String filePath, ReliableDownloadOptions options, BlobRange range, Integer blockSize, - BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Duration timeout) throws IOException { - Mono download = blobAsyncClient.downloadToFile(filePath, range, blockSize, accessConditions, rangeGetContentMD5, options); + public void downloadToFile(String filePath, BlobRange range, Integer blockSize, ReliableDownloadOptions options, + BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Duration timeout) { + Mono download = blobAsyncClient.downloadToFile(filePath, range, blockSize, options, accessConditions, rangeGetContentMD5); - try { - Utility.blockWithOptionalTimeout(download, timeout); - } catch (UncheckedIOException e) { - throw e.getCause(); - } + 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} + * * @return A response containing status code and HTTP headers. */ public VoidResponse delete() { @@ -339,6 +387,10 @@ public VoidResponse delete() { /** * 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#DeleteSnapshotsOptionType-BlobAccessConditions-Duration} + * * @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. @@ -357,6 +409,10 @@ public VoidResponse delete(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, /** * Returns the blob's metadata and properties. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.getProperties} + * * @return The blob properties and metadata. */ public Response getProperties() { @@ -366,6 +422,10 @@ public Response getProperties() { /** * Returns the blob's metadata and properties. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.getProperties#BlobAccessConditions-Duration} + * * @param accessConditions {@link BlobAccessConditions} * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return The blob properties and metadata. @@ -383,6 +443,10 @@ public Response getProperties(BlobAccessConditions accessConditi * see the * Azure Docs. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.setHTTPHeaders#BlobHTTPHeaders} + * * @param headers {@link BlobHTTPHeaders} * @return A response containing status code and HTTP headers. */ @@ -396,6 +460,10 @@ public VoidResponse setHTTPHeaders(BlobHTTPHeaders headers) { * see the * Azure Docs. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.setHTTPHeaders#BlobHTTPHeaders-BlobAccessConditions-Duration} + * * @param headers {@link BlobHTTPHeaders} * @param accessConditions {@link BlobAccessConditions} * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. @@ -414,6 +482,10 @@ public VoidResponse setHTTPHeaders(BlobHTTPHeaders headers, BlobAccessConditions * must be preserved, they must be downloaded and included in the call to this method. For more information, see the * Azure Docs. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.setMetadata#Metadata} + * * @param metadata {@link Metadata} * @return A response containing status code and HTTP headers. */ @@ -426,6 +498,10 @@ public VoidResponse setMetadata(Metadata metadata) { * must be preserved, they must be downloaded and included in the call to this method. For more information, see the * Azure Docs. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.setMetadata#Metadata-BlobAccessConditions-Duration} + * * @param metadata {@link Metadata} * @param accessConditions {@link BlobAccessConditions} * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. @@ -441,6 +517,10 @@ public VoidResponse setMetadata(Metadata metadata, BlobAccessConditions accessCo /** * Creates a read-only snapshot of a blob. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.createSnapshot} + * * @return The ID of the new snapshot. */ public Response createSnapshot() { @@ -450,6 +530,10 @@ public Response createSnapshot() { /** * Creates a read-only snapshot of a blob. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.createSnapshot#Metadata-BlobAccessConditions-Duration} + * * @param metadata {@link Metadata} * @param accessConditions {@link BlobAccessConditions} * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. @@ -468,6 +552,10 @@ public Response createSnapshot(Metadata metadata, BlobAccessConditions a * 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} + * * @param tier The new tier for the blob. * @return A response containing status code and HTTP headers. */ @@ -481,6 +569,10 @@ public VoidResponse setTier(AccessTier tier) { * 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-LeaseAccessConditions-Duration} + * * @param tier The new tier for the blob. * @param leaseAccessConditions By setting lease access conditions, requests will fail if the provided lease does * not match the active lease on the blob. @@ -497,6 +589,10 @@ public VoidResponse setTier(AccessTier tier, LeaseAccessConditions leaseAccessCo /** * 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} + * * @return A response containing status code and HTTP headers. */ public VoidResponse undelete() { @@ -506,6 +602,10 @@ public VoidResponse undelete() { /** * 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#Duration} + * * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return A response containing status code and HTTP headers. */ @@ -520,6 +620,10 @@ public VoidResponse undelete(Duration timeout) { * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 * seconds, or infinite (-1). * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.acquireLease#String-int} + * * @param proposedId A {@code String} in any valid GUID format. May be null. * @param duration The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A * non-infinite lease can be between 15 and 60 seconds. @@ -533,7 +637,11 @@ public Response acquireLease(String proposedId, int duration) { * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 * seconds, or infinite (-1). * - * @param proposedID A {@code String} in any valid GUID format. May be null. + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.acquireLease#String-int-ModifiedAccessConditions-Duration} + * + * @param proposedId A {@code String} in any valid GUID format. May be null. * @param duration The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A * non-infinite lease can be between 15 and 60 seconds. * @param modifiedAccessConditions Standard HTTP Access conditions related to the modification of data. ETag and @@ -542,10 +650,10 @@ public Response acquireLease(String proposedId, int duration) { * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return The lease ID. */ - public Response acquireLease(String proposedID, int duration, + public Response acquireLease(String proposedId, int duration, ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { Mono> response = blobAsyncClient - .acquireLease(proposedID, duration, modifiedAccessConditions); + .acquireLease(proposedId, duration, modifiedAccessConditions); return Utility.blockWithOptionalTimeout(response, timeout); } @@ -553,27 +661,35 @@ public Response acquireLease(String proposedID, int duration, /** * Renews the blob's previously-acquired lease. * - * @param leaseID The leaseId of the active lease on the blob. + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.renewLease#String} + * + * @param leaseId The leaseId of the active lease on the blob. * @return The renewed lease ID. */ - public Response renewLease(String leaseID) { - return this.renewLease(leaseID, null, null); + public Response renewLease(String leaseId) { + return this.renewLease(leaseId, null, null); } /** * Renews the blob's previously-acquired lease. * - * @param leaseID The leaseId of the active lease on the blob. + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.renewLease#String-ModifiedAccessConditions-Duration} + * + * @param leaseId The leaseId of the active lease on the blob. * @param modifiedAccessConditions 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 timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return The renewed lease ID. */ - public Response renewLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions, + public Response renewLease(String leaseId, ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { Mono> response = blobAsyncClient - .renewLease(leaseID, modifiedAccessConditions); + .renewLease(leaseId, modifiedAccessConditions); return Utility.blockWithOptionalTimeout(response, timeout); } @@ -581,27 +697,33 @@ public Response renewLease(String leaseID, ModifiedAccessConditions modi /** * Releases the blob's previously-acquired lease. * - * @param leaseID The leaseId of the active lease on the blob. + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.releaseLease#String} + * + * @param leaseId The leaseId of the active lease on the blob. * @return A response containing status code and HTTP headers. */ - public VoidResponse releaseLease(String leaseID) { - return this.releaseLease(leaseID, null, null); + public VoidResponse releaseLease(String leaseId) { + return this.releaseLease(leaseId, null, null); } /** * Releases the blob's previously-acquired lease. * - * @param leaseID The leaseId of the active lease on the blob. + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.releaseLease#String-ModifiedAccessConditions-Duration} + * + * @param leaseId The leaseId of the active lease on the blob. * @param modifiedAccessConditions 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 timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return A response containing status code and HTTP headers. */ - public VoidResponse releaseLease(String leaseID, - ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { - Mono response = blobAsyncClient - .releaseLease(leaseID, modifiedAccessConditions); + public VoidResponse releaseLease(String leaseId, ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + Mono response = blobAsyncClient.releaseLease(leaseId, modifiedAccessConditions); return Utility.blockWithOptionalTimeout(response, timeout); } @@ -610,6 +732,10 @@ public VoidResponse releaseLease(String leaseID, * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant * to break a fixed-duration lease when it expires or an infinite lease immediately. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.breakLease} + * * @return The remaining time in the broken lease in seconds. */ public Response breakLease() { @@ -620,6 +746,10 @@ public Response breakLease() { * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant * to break a fixed-duration lease when it expires or an infinite lease immediately. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.breakLease#Integer-ModifiedAccessConditions-Duration} + * * @param breakPeriodInSeconds An optional {@code Integer} representing the proposed duration of seconds that the * lease should continue before it is broken, between 0 and 60 seconds. This break period is only used if it is * shorter than the time remaining on the lease. If longer, the time remaining on the lease is used. A new lease @@ -631,8 +761,7 @@ public Response breakLease() { * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return The remaining time in the broken lease in seconds. */ - public Response breakLease(Integer breakPeriodInSeconds, - ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + public Response breakLease(Integer breakPeriodInSeconds, ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { Mono> response = blobAsyncClient .breakLease(breakPeriodInSeconds, modifiedAccessConditions); @@ -642,30 +771,36 @@ public Response breakLease(Integer breakPeriodInSeconds, /** * ChangeLease changes the blob's lease ID. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.changeLease#String-String} + * * @param leaseId The leaseId of the active lease on the blob. - * @param proposedID A {@code String} in any valid GUID format. + * @param proposedId A {@code String} in any valid GUID format. * @return The new lease ID. */ - public Response changeLease(String leaseId, String proposedID) { - return this.changeLease(leaseId, proposedID, null, null); + public Response changeLease(String leaseId, String proposedId) { + return this.changeLease(leaseId, proposedId, null, null); } /** * ChangeLease changes the blob's lease ID. For more information, see the Azure * Docs. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.changeLease#String-String-ModifiedAccessConditions-Duration} + * * @param leaseId The leaseId of the active lease on the blob. - * @param proposedID A {@code String} in any valid GUID format. + * @param proposedId A {@code String} in any valid GUID format. * @param modifiedAccessConditions 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 timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return The new lease ID. */ - public Response changeLease(String leaseId, String proposedID, - ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { - Mono> response = blobAsyncClient - .changeLease(leaseId, proposedID, modifiedAccessConditions); + public Response changeLease(String leaseId, String proposedId, ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + Mono> response = blobAsyncClient.changeLease(leaseId, proposedId, modifiedAccessConditions); return Utility.blockWithOptionalTimeout(response, timeout); } @@ -674,6 +809,10 @@ public Response changeLease(String leaseId, String proposedID, * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.getAccountInfo} + * * @return The sku name and account kind. */ public Response getAccountInfo() { @@ -684,6 +823,10 @@ public Response getAccountInfo() { * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. * + *

Code Samples

+ * + * {@codesnippet com.azure.storage.blob.BlobClient.getAccountInfo#Duration} + * * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return The sku name and account kind. */ diff --git a/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobAsyncClientJavaDocCodeSnippets.java b/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobAsyncClientJavaDocCodeSnippets.java index a516e22b8ed07..78efe3d743fa6 100644 --- a/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobAsyncClientJavaDocCodeSnippets.java +++ b/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobAsyncClientJavaDocCodeSnippets.java @@ -23,11 +23,10 @@ /** * Code snippets for {@link BlobAsyncClient} */ +@SuppressWarnings("unused") public class BlobAsyncClientJavaDocCodeSnippets { - - private String blobName = "blob"; - private BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); - private String leaseId = "lease"; + private BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient("blobName"); + private String leaseId = "leaseId"; private String copyId = "copyId"; private URL url = JavaDocCodeSnippetsHelpers.generateURL("https://sample.com"); private String file = "file"; @@ -36,9 +35,9 @@ public class BlobAsyncClientJavaDocCodeSnippets { * Code snippet for {@link BlobAsyncClient#exists()} */ public void existsCodeSnippet() { - // BEGIN: com.azure.storage.blob.exists + // BEGIN: com.azure.storage.blob.BlobAsyncClient.exists client.exists().subscribe(response -> System.out.printf("Exists? %b%n", response.value())); - // END: com.azure.storage.blob.exists + // END: com.azure.storage.blob.BlobAsyncClient.exists } /** @@ -46,12 +45,12 @@ public void existsCodeSnippet() { * {@link BlobAsyncClient#startCopyFromURL(URL, Metadata, ModifiedAccessConditions, BlobAccessConditions)} */ public void startCopyFromURL() { - // BEGIN: com.azure.storage.blob.startCopyFromURL#URL + // BEGIN: com.azure.storage.blob.BlobAsyncClient.startCopyFromURL#URL client.startCopyFromURL(url) .subscribe(response -> System.out.printf("Copy identifier: %s%n", response.value())); - // END: com.azure.storage.blob.startCopyFromURL#URL + // END: com.azure.storage.blob.BlobAsyncClient.startCopyFromURL#URL - // BEGIN: com.azure.storage.blob.startCopyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions + // BEGIN: com.azure.storage.blob.BlobAsyncClient.startCopyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions().ifUnmodifiedSince(OffsetDateTime.now().minusDays(7)); BlobAccessConditions blobAccessConditions = new BlobAccessConditions() @@ -59,7 +58,7 @@ public void startCopyFromURL() { client.startCopyFromURL(url, metadata, modifiedAccessConditions, blobAccessConditions) .subscribe(response -> System.out.printf("Copy identifier: %s%n", response.value())); - // END: com.azure.storage.blob.startCopyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions + // END: com.azure.storage.blob.BlobAsyncClient.startCopyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions } /** @@ -67,16 +66,16 @@ public void startCopyFromURL() { * {@link BlobAsyncClient#abortCopyFromURL(String, LeaseAccessConditions)} */ public void abortCopyFromURL() { - // BEGIN: com.azure.storage.blob.abortCopyFromURL#String + // BEGIN: com.azure.storage.blob.BlobAsyncClient.abortCopyFromURL#String client.abortCopyFromURL(copyId) .subscribe(response -> System.out.printf("Aborted copy completed with status %d%n", response.statusCode())); - // END: com.azure.storage.blob.abortCopyFromURL#String + // END: com.azure.storage.blob.BlobAsyncClient.abortCopyFromURL#String - // BEGIN: com.azure.storage.blob.abortCopyFromURL#String-LeaseAccessConditions + // BEGIN: com.azure.storage.blob.BlobAsyncClient.abortCopyFromURL#String-LeaseAccessConditions LeaseAccessConditions leaseAccessConditions = new LeaseAccessConditions().leaseId(leaseId); client.abortCopyFromURL(copyId, leaseAccessConditions) .subscribe(response -> System.out.printf("Aborted copy completed with status %d%n", response.statusCode())); - // END: com.azure.storage.blob.abortCopyFromURL#String-LeaseAccessConditions + // END: com.azure.storage.blob.BlobAsyncClient.abortCopyFromURL#String-LeaseAccessConditions } /** @@ -84,11 +83,11 @@ public void abortCopyFromURL() { * {@link BlobAsyncClient#copyFromURL(URL, Metadata, ModifiedAccessConditions, BlobAccessConditions)} */ public void copyFromURL() { - // BEGIN: com.azure.storage.blob.copyFromURL#URL + // BEGIN: com.azure.storage.blob.BlobAsyncClient.copyFromURL#URL client.copyFromURL(url).subscribe(response -> System.out.printf("Copy identifier: %s%n", response.value())); - // END: com.azure.storage.blob.copyFromURL#URL + // END: com.azure.storage.blob.BlobAsyncClient.copyFromURL#URL - // BEGIN: com.azure.storage.blob.copyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions + // BEGIN: com.azure.storage.blob.BlobAsyncClient.copyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions().ifUnmodifiedSince(OffsetDateTime.now().minusDays(7)); BlobAccessConditions blobAccessConditions = new BlobAccessConditions() @@ -96,15 +95,15 @@ public void copyFromURL() { client.copyFromURL(url, metadata, modifiedAccessConditions, blobAccessConditions) .subscribe(response -> System.out.printf("Copy identifier: %s%n", response.value())); - // END: com.azure.storage.blob.copyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions + // END: com.azure.storage.blob.BlobAsyncClient.copyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions } /** * Code snippets for {@link BlobAsyncClient#download()} and - * {@link BlobAsyncClient#download(BlobRange, BlobAccessConditions, boolean, ReliableDownloadOptions)} + * {@link BlobAsyncClient#download(BlobRange, ReliableDownloadOptions, BlobAccessConditions, boolean)} */ public void download() { - // BEGIN: com.azure.storage.blob.download + // BEGIN: com.azure.storage.blob.BlobAsyncClient.download client.download().subscribe(response -> { ByteArrayOutputStream downloadData = new ByteArrayOutputStream(); response.value().subscribe(piece -> { @@ -115,13 +114,13 @@ public void download() { } }); }); - // END: com.azure.storage.blob.download + // END: com.azure.storage.blob.BlobAsyncClient.download - // BEGIN: com.azure.storage.blob.download#BlobRange-BlobAccessConditions-boolean-ReliableDownloadOptions + // BEGIN: com.azure.storage.blob.BlobAsyncClient.download#BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean BlobRange range = new BlobRange(1024, 2048); ReliableDownloadOptions options = new ReliableDownloadOptions().maxRetryRequests(5); - client.download(range, null, false, options).subscribe(response -> { + client.download(range, options, null, false).subscribe(response -> { ByteArrayOutputStream downloadData = new ByteArrayOutputStream(); response.value().subscribe(piece -> { try { @@ -131,25 +130,25 @@ public void download() { } }); }); - // END: com.azure.storage.blob.download#BlobRange-BlobAccessConditions-boolean-ReliableDownloadOptions + // END: com.azure.storage.blob.BlobAsyncClient.download#BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean } /** * Code snippets for {@link BlobAsyncClient#downloadToFile(String)} and - * {@link BlobAsyncClient#downloadToFile(String, BlobRange, Integer, BlobAccessConditions, boolean, ReliableDownloadOptions)} + * {@link BlobAsyncClient#downloadToFile(String, BlobRange, Integer, ReliableDownloadOptions, BlobAccessConditions, boolean)} */ public void downloadToFile() { - // BEGIN: com.azure.storage.blob.downloadToFile#String + // BEGIN: com.azure.storage.blob.BlobAsyncClient.downloadToFile#String client.downloadToFile(file).subscribe(response -> System.out.println("Completed download to file")); - // END: com.azure.storage.blob.downloadToFile#String + // END: com.azure.storage.blob.BlobAsyncClient.downloadToFile#String - // BEGIN: com.azure.storage.blob.downloadToFile#String-BlobRange-Integer-BlobAccessConditions-boolean-ReliableDownloadOptions + // BEGIN: com.azure.storage.blob.BlobAsyncClient.downloadToFile#String-BlobRange-Integer-ReliableDownloadOptions-BlobAccessConditions-boolean BlobRange range = new BlobRange(1024, 2048); ReliableDownloadOptions options = new ReliableDownloadOptions().maxRetryRequests(5); - client.downloadToFile(file, range, null, null, false, options) + client.downloadToFile(file, range, null, options, null, false) .subscribe(response -> System.out.println("Completed download to file")); - // END: com.azure.storage.blob.downloadToFile#String-BlobRange-Integer-BlobAccessConditions-boolean-ReliableDownloadOptions + // END: com.azure.storage.blob.BlobAsyncClient.downloadToFile#String-BlobRange-Integer-ReliableDownloadOptions-BlobAccessConditions-boolean } /** @@ -157,14 +156,14 @@ public void downloadToFile() { * {@link BlobAsyncClient#delete(DeleteSnapshotsOptionType, BlobAccessConditions)} */ public void delete() { - // BEGIN: com.azure.storage.blob.delete + // BEGIN: com.azure.storage.blob.BlobAsyncClient.delete client.delete().subscribe(response -> System.out.printf("Delete completed with status %d%n", response.statusCode())); - // END: com.azure.storage.blob.delete + // END: com.azure.storage.blob.BlobAsyncClient.delete - // BEGIN: com.azure.storage.blob.delete#DeleteSnapshotsOptionType-BlobAccessConditions + // BEGIN: com.azure.storage.blob.BlobAsyncClient.delete#DeleteSnapshotsOptionType-BlobAccessConditions client.delete(DeleteSnapshotsOptionType.INCLUDE, null) .subscribe(response -> System.out.printf("Delete completed with status %d%n", response.statusCode())); - // END: com.azure.storage.blob.delete#DeleteSnapshotsOptionType-BlobAccessConditions + // END: com.azure.storage.blob.BlobAsyncClient.delete#DeleteSnapshotsOptionType-BlobAccessConditions } /** @@ -172,7 +171,18 @@ public void delete() { * {@link BlobAsyncClient#getProperties(BlobAccessConditions)} */ public void getProperties() { - BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + // BEGIN: com.azure.storage.blob.BlobAsyncClient.getProperties + client.getProperties().subscribe(response -> + System.out.printf("Type: %s, Size: %d%n", response.value().blobType(), response.value().blobSize())); + // END: com.azure.storage.blob.BlobAsyncClient.getProperties + + // BEGIN: com.azure.storage.blob.BlobAsyncClient.getProperties#BlobAccessConditions + BlobAccessConditions accessConditions = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); + + client.getProperties(accessConditions).subscribe(response -> + System.out.printf("Type: %s, Size: %d%n", response.value().blobType(), response.value().blobSize())); + // END: com.azure.storage.blob.BlobAsyncClient.getProperties#BlobAccessConditions } /** @@ -180,7 +190,22 @@ public void getProperties() { * {@link BlobAsyncClient#setHTTPHeaders(BlobHTTPHeaders, BlobAccessConditions)} */ public void setHTTPHeaders() { - BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + // BEGIN: com.azure.storage.blob.BlobAsyncClient.setHTTPHeaders#BlobHTTPHeaders + client.setHTTPHeaders(new BlobHTTPHeaders() + .blobContentLanguage("en-US") + .blobContentType("binary")).subscribe(response -> + System.out.printf("Set HTTP headers completed with status %d%n", response.statusCode())); + // END: com.azure.storage.blob.BlobAsyncClient.setHTTPHeaders#BlobHTTPHeaders + + // BEGIN: com.azure.storage.blob.BlobAsyncClient.setHTTPHeaders#BlobHTTPHeaders-BlobAccessConditions + BlobAccessConditions accessConditions = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); + + client.setHTTPHeaders(new BlobHTTPHeaders() + .blobContentLanguage("en-US") + .blobContentType("binary"), accessConditions).subscribe(response -> + System.out.printf("Set HTTP headers completed with status %d%n", response.statusCode())); + // END: com.azure.storage.blob.BlobAsyncClient.setHTTPHeaders#BlobHTTPHeaders-BlobAccessConditions } /** @@ -188,7 +213,18 @@ public void setHTTPHeaders() { * {@link BlobAsyncClient#setMetadata(Metadata, BlobAccessConditions)} */ public void setMetadata() { - BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + // BEGIN: com.azure.storage.blob.BlobAsyncClient.setMetadata#Metadata + client.setMetadata(new Metadata(Collections.singletonMap("metadata", "value"))) + .subscribe(response -> System.out.printf("Set metadata completed with status %d%n", response.statusCode())); + // END: com.azure.storage.blob.BlobAsyncClient.setMetadata#Metadata + + // BEGIN: com.azure.storage.blob.BlobAsyncClient.setMetadata#Metadata-BlobAccessConditions + BlobAccessConditions accessConditions = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); + + client.setMetadata(new Metadata(Collections.singletonMap("metadata", "value")), accessConditions) + .subscribe(response -> System.out.printf("Set metadata completed with status %d%n", response.statusCode())); + // END: com.azure.storage.blob.BlobAsyncClient.setMetadata#Metadata-BlobAccessConditions } /** @@ -196,7 +232,18 @@ public void setMetadata() { * {@link BlobAsyncClient#createSnapshot(Metadata, BlobAccessConditions)} */ public void createSnapshot() { - BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + // BEGIN: com.azure.storage.blob.BlobAsyncClient.createSnapshot + client.createSnapshot().subscribe(response -> System.out.printf("Identifier for the snapshot is %s%n", response.value())); + // END: com.azure.storage.blob.BlobAsyncClient.createSnapshot + + // BEGIN: com.azure.storage.blob.BlobAsyncClient.createSnapshot#Metadata-BlobAccessConditions + Metadata snapshotMetadata = new Metadata(Collections.singletonMap("metadata", "value")); + BlobAccessConditions accessConditions = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); + + client.createSnapshot(snapshotMetadata, accessConditions) + .subscribe(response -> System.out.printf("Identifier for the snapshot is %s%n", response.value())); + // END: com.azure.storage.blob.BlobAsyncClient.createSnapshot#Metadata-BlobAccessConditions } /** @@ -204,14 +251,25 @@ public void createSnapshot() { * {@link BlobAsyncClient#setTier(AccessTier, LeaseAccessConditions)} */ public void setTier() { - BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + // BEGIN: com.azure.storage.blob.BlobAsyncClient.setTier#AccessTier + client.setTier(AccessTier.HOT).subscribe(response -> System.out.printf("Set tier completed with status code %d%n", response.statusCode())); + // END: com.azure.storage.blob.BlobAsyncClient.setTier#AccessTier + + // BEGIN: com.azure.storage.blob.BlobAsyncClient.setTier#AccessTier-LeaseAccessConditions + LeaseAccessConditions accessConditions = new LeaseAccessConditions().leaseId(leaseId); + + client.setTier(AccessTier.HOT, accessConditions) + .subscribe(response -> System.out.printf("Set tier completed with status code %d%n", response.statusCode())); + // END: com.azure.storage.blob.BlobAsyncClient.setTier#AccessTier-LeaseAccessConditions } /** * Code snippet for {@link BlobAsyncClient#undelete()} */ public void undelete() { - BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + // BEGIN: com.azure.storage.blob.BlobAsyncClient.undelete + client.undelete().subscribe(response -> System.out.printf("Undelete completed with status %d%n", response.statusCode())); + // END: com.azure.storage.blob.BlobAsyncClient.undelete } /** @@ -219,7 +277,17 @@ public void undelete() { * {@link BlobAsyncClient#acquireLease(String, int, ModifiedAccessConditions)} */ public void acquireLease() { - BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + // BEGIN: com.azure.storage.blob.BlobAsyncClient.acquireLease#String-int + client.acquireLease("proposedId", 60).subscribe(response -> System.out.printf("Lease ID is %s%n", response.value())); + // END: com.azure.storage.blob.BlobAsyncClient.acquireLease#String-int + + // BEGIN: com.azure.storage.blob.BlobAsyncClient.acquireLease#String-int-ModifiedAccessConditions + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .ifModifiedSince(OffsetDateTime.now().minusDays(3)); + + client.acquireLease("proposedId", 60, modifiedAccessConditions) + .subscribe(response -> System.out.printf("Lease ID is %s%n", response.value())); + // END: com.azure.storage.blob.BlobAsyncClient.acquireLease#String-int-ModifiedAccessConditions } /** @@ -227,7 +295,17 @@ public void acquireLease() { * {@link BlobAsyncClient#renewLease(String, ModifiedAccessConditions)} */ public void renewLease() { - BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + // BEGIN: com.azure.storage.blob.BlobAsyncClient.renewLease#String + client.renewLease(leaseId).subscribe(response -> System.out.printf("Renewed lease ID is %s%n", response.value())); + // END: com.azure.storage.blob.BlobAsyncClient.renewLease#String + + // BEGIN: com.azure.storage.blob.BlobAsyncClient.renewLease#String-ModifiedAccessConditions + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .ifUnmodifiedSince(OffsetDateTime.now().minusDays(3)); + + client.renewLease(leaseId, modifiedAccessConditions) + .subscribe(response -> System.out.printf("Renewed lease ID is %s%n", response.value())); + // END: com.azure.storage.blob.BlobAsyncClient.renewLease#String-ModifiedAccessConditions } /** @@ -235,7 +313,17 @@ public void renewLease() { * {@link BlobAsyncClient#releaseLease(String, ModifiedAccessConditions)} */ public void releaseLease() { - BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + // BEGIN: com.azure.storage.blob.BlobAsyncClient.releaseLease#String + client.releaseLease(leaseId).subscribe(response -> System.out.printf("Release lease completed with status %d%n", response.statusCode())); + // END: com.azure.storage.blob.BlobAsyncClient.releaseLease#String + + // BEGIN: com.azure.storage.blob.BlobAsyncClient.releaseLease#String-ModifiedAccessConditions + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .ifUnmodifiedSince(OffsetDateTime.now().minusDays(3)); + + client.releaseLease(leaseId, modifiedAccessConditions) + .subscribe(response -> System.out.printf("Release lease completed with status %d%n", response.statusCode())); + // END: com.azure.storage.blob.BlobAsyncClient.releaseLease#String-ModifiedAccessConditions } /** @@ -243,7 +331,18 @@ public void releaseLease() { * {@link BlobAsyncClient#breakLease(Integer, ModifiedAccessConditions)} */ public void breakLease() { - BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + // BEGIN: com.azure.storage.blob.BlobAsyncClient.breakLease + client.breakLease().subscribe(response -> System.out.printf("The broken lease has %d seconds remaining on the lease", response.value())); + // END: com.azure.storage.blob.BlobAsyncClient.breakLease + + // BEGIN: com.azure.storage.blob.BlobAsyncClient.breakLease#Integer-ModifiedAccessConditions + Integer retainLeaseInSeconds = 5; + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .ifUnmodifiedSince(OffsetDateTime.now().minusDays(3)); + + client.breakLease(retainLeaseInSeconds, modifiedAccessConditions) + .subscribe(response -> System.out.printf("The broken lease has %d seconds remaining on the lease", response.value())); + // END: com.azure.storage.blob.BlobAsyncClient.breakLease#Integer-ModifiedAccessConditions } /** @@ -251,13 +350,26 @@ public void breakLease() { * {@link BlobAsyncClient#changeLease(String, String, ModifiedAccessConditions)} */ public void changeLease() { - BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + // BEGIN: com.azure.storage.blob.BlobAsyncClient.changeLease#String-String + client.changeLease(leaseId, "proposedId").subscribe(response -> System.out.printf("Changed lease ID is %s%n", response.value())); + // END: com.azure.storage.blob.BlobAsyncClient.changeLease#String-String + + // BEGIN: com.azure.storage.blob.BlobAsyncClient.changeLease#String-String-ModifiedAccessConditions + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .ifUnmodifiedSince(OffsetDateTime.now().minusDays(3)); + + client.changeLease(leaseId, "proposedId", modifiedAccessConditions) + .subscribe(response -> System.out.printf("Changed lease ID is %s%n", response.value())); + // END: com.azure.storage.blob.BlobAsyncClient.changeLease#String-String-ModifiedAccessConditions } /** * Code snippet for {@link BlobAsyncClient#getAccountInfo()} */ public void getAccountInfo() { - BlobAsyncClient client = JavaDocCodeSnippetsHelpers.getBlobAsyncClient(blobName); + // BEGIN: com.azure.storage.blob.BlobAsyncClient.getAccountInfo + client.getAccountInfo().subscribe(response -> System.out.printf("Account Kind: %s, SKU: %s%n", + response.value().accountKind(), response.value().skuName())); + // END: com.azure.storage.blob.BlobAsyncClient.getAccountInfo } } diff --git a/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobClientJavaDocCodeSnippets.java b/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobClientJavaDocCodeSnippets.java index ea779ce3e0558..33e9d4ac46e40 100644 --- a/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobClientJavaDocCodeSnippets.java +++ b/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobClientJavaDocCodeSnippets.java @@ -1,4 +1,375 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + package com.azure.storage.blob; +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.ReliableDownloadOptions; +import com.azure.storage.blob.models.StorageAccountInfo; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.net.URL; +import java.time.Duration; +import java.time.OffsetDateTime; +import java.util.Collections; + +/** + * Code snippets for {@link BlobClient} + */ +@SuppressWarnings("unused") public class BlobClientJavaDocCodeSnippets { + private BlobClient client = JavaDocCodeSnippetsHelpers.getBlobClient("blobName"); + private String leaseId = "leaseId"; + private String copyId = "copyId"; + private URL url = JavaDocCodeSnippetsHelpers.generateURL("https://sample.com"); + private String file = "file"; + private Duration timeout = Duration.ofSeconds(30); + + /** + * Code snippets for {@link BlobClient#exists()} and {@link BlobClient#exists(Duration)} + */ + public void existsCodeSnippet() { + // BEGIN: com.azure.storage.blob.BlobClient.exists + System.out.printf("Exists? %b%n", client.exists().value()); + // END: com.azure.storage.blob.BlobClient.exists + + // BEGIN: com.azure.storage.blob.BlobClient.exists#Duration + System.out.printf("Exists? %b%n", client.exists(timeout).value()); + // END: com.azure.storage.blob.BlobClient.exists#Duration + } + + /** + * Code snippets for {@link BlobClient#startCopyFromURL(URL)} and + * {@link BlobClient#startCopyFromURL(URL, Metadata, ModifiedAccessConditions, BlobAccessConditions, Duration)} + */ + public void startCopyFromURL() { + // BEGIN: com.azure.storage.blob.BlobClient.startCopyFromURL#URL + System.out.printf("Copy identifier: %s%n", client.startCopyFromURL(url).value()); + // END: com.azure.storage.blob.BlobClient.startCopyFromURL#URL + + // BEGIN: com.azure.storage.blob.BlobClient.startCopyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions-Duration + Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions().ifUnmodifiedSince(OffsetDateTime.now().minusDays(7)); + BlobAccessConditions blobAccessConditions = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); + + System.out.printf("Copy identifier: %s%n", + client.startCopyFromURL(url, metadata, modifiedAccessConditions, blobAccessConditions, timeout)); + // END: com.azure.storage.blob.BlobClient.startCopyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions-Duration + } + + /** + * Code snippets for {@link BlobClient#abortCopyFromURL(String)} and + * {@link BlobClient#abortCopyFromURL(String, LeaseAccessConditions, Duration)} + */ + public void abortCopyFromURL() { + // BEGIN: com.azure.storage.blob.BlobClient.abortCopyFromURL#String + System.out.printf("Aborted copy completed with status %d%n", client.abortCopyFromURL(copyId).statusCode()); + // END: com.azure.storage.blob.BlobClient.abortCopyFromURL#String + + // BEGIN: com.azure.storage.blob.BlobClient.abortCopyFromURL#String-LeaseAccessConditions-Duration + LeaseAccessConditions leaseAccessConditions = new LeaseAccessConditions().leaseId(leaseId); + System.out.printf("Aborted copy completed with status %d%n", client.abortCopyFromURL(copyId, leaseAccessConditions, timeout).statusCode()); + // END: com.azure.storage.blob.BlobClient.abortCopyFromURL#String-LeaseAccessConditions-Duration + } + + /** + * Code snippets for {@link BlobClient#copyFromURL(URL)} and + * {@link BlobClient#copyFromURL(URL, Metadata, ModifiedAccessConditions, BlobAccessConditions, Duration)} + */ + public void copyFromURL() { + // BEGIN: com.azure.storage.blob.BlobClient.copyFromURL#URL + System.out.printf("Copy identifier: %s%n", client.copyFromURL(url).value()); + // END: com.azure.storage.blob.BlobClient.copyFromURL#URL + + // BEGIN: com.azure.storage.blob.BlobClient.copyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions-Duration + Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions().ifUnmodifiedSince(OffsetDateTime.now().minusDays(7)); + BlobAccessConditions blobAccessConditions = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); + + System.out.printf("Copy identifier: %s%n", client.copyFromURL(url, metadata, modifiedAccessConditions, blobAccessConditions, timeout).value()); + // END: com.azure.storage.blob.BlobClient.copyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions-Duration + } + + /** + * Code snippets for {@link BlobClient#download(OutputStream)} and + * {@link BlobClient#download(OutputStream, BlobRange, ReliableDownloadOptions, BlobAccessConditions, boolean, Duration)} + */ + public void download() { + // BEGIN: com.azure.storage.blob.BlobClient.download#OutputSteam + System.out.printf("Download completed with status %d%n", client.download(new ByteArrayOutputStream()).statusCode()); + // END: com.azure.storage.blob.BlobClient.download#OutputSteam + + // BEGIN: com.azure.storage.blob.BlobClient.download#OutputStream-BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration + BlobRange range = new BlobRange(1024, 2048); + ReliableDownloadOptions options = new ReliableDownloadOptions().maxRetryRequests(5); + + System.out.printf("Download completed with status %d%n", + client.download(new ByteArrayOutputStream(), range, options, null, false, timeout).statusCode()); + // END: com.azure.storage.blob.BlobClient.download#OutputStream-BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration + } + + /** + * Code snippets for {@link BlobClient#downloadToFile(String)} and + * {@link BlobClient#downloadToFile(String, BlobRange, Integer, ReliableDownloadOptions, BlobAccessConditions, boolean, Duration)} + */ + public void downloadToFile() { + // BEGIN: com.azure.storage.blob.BlobClient.downloadToFile#String + client.downloadToFile(file); + System.out.println("Completed download to file"); + // END: com.azure.storage.blob.BlobClient.downloadToFile#String + + // BEGIN: com.azure.storage.blob.BlobClient.downloadToFile#String-BlobRange-Integer-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration + BlobRange range = new BlobRange(1024, 2048); + ReliableDownloadOptions options = new ReliableDownloadOptions().maxRetryRequests(5); + + client.downloadToFile(file, range, null, options, null, false, timeout); + System.out.println("Completed download to file"); + // END: com.azure.storage.blob.BlobClient.downloadToFile#String-BlobRange-Integer-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration + } + + /** + * Code snippets for {@link BlobClient#delete()} and + * {@link BlobClient#delete(DeleteSnapshotsOptionType, BlobAccessConditions, Duration)} + */ + public void delete() { + // BEGIN: com.azure.storage.blob.BlobClient.delete + System.out.printf("Delete completed with status %d%n", client.delete().statusCode()); + // END: com.azure.storage.blob.BlobClient.delete + + // BEGIN: com.azure.storage.blob.BlobClient.delete#DeleteSnapshotsOptionType-BlobAccessConditions-Duration + System.out.printf("Delete completed with status %d%n", client.delete(DeleteSnapshotsOptionType.INCLUDE, null, timeout).statusCode()); + // END: com.azure.storage.blob.BlobClient.delete#DeleteSnapshotsOptionType-BlobAccessConditions-Duration + } + + /** + * Code snippets for {@link BlobClient#getProperties()} + */ + public void getProperties() { + // BEGIN: com.azure.storage.blob.BlobClient.getProperties + BlobProperties properties = client.getProperties().value(); + System.out.printf("Type: %s, Size: %d%n", properties.blobType(), properties.blobSize()); + // END: com.azure.storage.blob.BlobClient.getProperties + } + + /** + * Code snippet for {@link BlobClient#getProperties(BlobAccessConditions, Duration)} + */ + public void getPropertiesWithTimeout() { + // BEGIN: com.azure.storage.blob.BlobClient.getProperties#BlobAccessConditions-Duration + BlobAccessConditions accessConditions = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); + + BlobProperties properties = client.getProperties(accessConditions, timeout).value(); + System.out.printf("Type: %s, Size: %d%n", properties.blobType(), properties.blobSize()); + // END: com.azure.storage.blob.BlobClient.getProperties#BlobAccessConditions-Duration + } + + /** + * Code snippets for {@link BlobClient#setHTTPHeaders(BlobHTTPHeaders)} and + * {@link BlobClient#setHTTPHeaders(BlobHTTPHeaders, BlobAccessConditions, Duration)} + */ + public void setHTTPHeaders() { + // BEGIN: com.azure.storage.blob.BlobClient.setHTTPHeaders#BlobHTTPHeaders + System.out.printf("Set HTTP headers completed with status %d%n", + client.setHTTPHeaders(new BlobHTTPHeaders() + .blobContentLanguage("en-US") + .blobContentType("binary")) + .statusCode()); + // END: com.azure.storage.blob.BlobClient.setHTTPHeaders#BlobHTTPHeaders + + // BEGIN: com.azure.storage.blob.BlobClient.setHTTPHeaders#BlobHTTPHeaders-BlobAccessConditions-Duration + BlobAccessConditions accessConditions = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); + + System.out.printf("Set HTTP headers completed with status %d%n", + client.setHTTPHeaders(new BlobHTTPHeaders() + .blobContentLanguage("en-US") + .blobContentType("binary"), accessConditions, timeout) + .statusCode()); + // END: com.azure.storage.blob.BlobClient.setHTTPHeaders#BlobHTTPHeaders-BlobAccessConditions-Duration + } + + /** + * Code snippets for {@link BlobClient#setMetadata(Metadata)} and + * {@link BlobClient#setMetadata(Metadata, BlobAccessConditions, Duration)} + */ + public void setMetadata() { + // BEGIN: com.azure.storage.blob.BlobClient.setMetadata#Metadata + System.out.printf("Set metadata completed with status %d%n", + client.setMetadata(new Metadata(Collections.singletonMap("metadata", "value"))).statusCode()); + // END: com.azure.storage.blob.BlobClient.setMetadata#Metadata + + // BEGIN: com.azure.storage.blob.BlobClient.setMetadata#Metadata-BlobAccessConditions-Duration + BlobAccessConditions accessConditions = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); + + System.out.printf("Set metadata completed with status %d%n", + client.setMetadata(new Metadata(Collections.singletonMap("metadata", "value")), accessConditions, timeout).statusCode()); + // END: com.azure.storage.blob.BlobClient.setMetadata#Metadata-BlobAccessConditions-Duration + } + + /** + * Code snippets for {@link BlobClient#createSnapshot()} and + * {@link BlobClient#createSnapshot(Metadata, BlobAccessConditions, Duration)} + */ + public void createSnapshot() { + // BEGIN: com.azure.storage.blob.BlobClient.createSnapshot + System.out.printf("Identifier for the snapshot is %s%n", client.createSnapshot().value()); + // END: com.azure.storage.blob.BlobClient.createSnapshot + + // BEGIN: com.azure.storage.blob.BlobClient.createSnapshot#Metadata-BlobAccessConditions-Duration + Metadata snapshotMetadata = new Metadata(Collections.singletonMap("metadata", "value")); + BlobAccessConditions accessConditions = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); + + System.out.printf("Identifier for the snapshot is %s%n", client.createSnapshot(snapshotMetadata, accessConditions, timeout).value()); + // END: com.azure.storage.blob.BlobClient.createSnapshot#Metadata-BlobAccessConditions-Duration + } + + /** + * Code snippets for {@link BlobClient#setTier(AccessTier)} and + * {@link BlobClient#setTier(AccessTier, LeaseAccessConditions, Duration)} + */ + public void setTier() { + // BEGIN: com.azure.storage.blob.BlobClient.setTier#AccessTier + System.out.printf("Set tier completed with status code %d%n", client.setTier(AccessTier.HOT).statusCode()); + // END: com.azure.storage.blob.BlobClient.setTier#AccessTier + + // BEGIN: com.azure.storage.blob.BlobClient.setTier#AccessTier-LeaseAccessConditions-Duration + LeaseAccessConditions accessConditions = new LeaseAccessConditions().leaseId(leaseId); + + System.out.printf("Set tier completed with status code %d%n", client.setTier(AccessTier.HOT, accessConditions, timeout).statusCode()); + // END: com.azure.storage.blob.BlobClient.setTier#AccessTier-LeaseAccessConditions-Duration + } + + /** + * Code snippets for {@link BlobClient#undelete()} and {@link BlobClient#undelete(Duration)} + */ + public void undelete() { + // BEGIN: com.azure.storage.blob.BlobClient.undelete + System.out.printf("Undelete completed with status %d%n", client.undelete().statusCode()); + // END: com.azure.storage.blob.BlobClient.undelete + + // BEGIN: com.azure.storage.blob.BlobClient.undelete#Duration + System.out.printf("Undelete completed with status %d%n", client.undelete(timeout).statusCode()); + // END: com.azure.storage.blob.BlobClient.undelete#Duration + } + + /** + * Code snippets for {@link BlobClient#acquireLease(String, int)} and + * {@link BlobClient#acquireLease(String, int, ModifiedAccessConditions, Duration)} + */ + public void acquireLease() { + // BEGIN: com.azure.storage.blob.BlobClient.acquireLease#String-int + System.out.printf("Lease ID is %s%n", client.acquireLease("proposedId", 60).value()); + // END: com.azure.storage.blob.BlobClient.acquireLease#String-int + + // BEGIN: com.azure.storage.blob.BlobClient.acquireLease#String-int-ModifiedAccessConditions-Duration + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .ifModifiedSince(OffsetDateTime.now().minusDays(3)); + + System.out.printf("Lease ID is %s%n", client.acquireLease("proposedId", 60, modifiedAccessConditions, timeout).value()); + // END: com.azure.storage.blob.BlobClient.acquireLease#String-int-ModifiedAccessConditions-Duration + } + + /** + * Code snippets for {@link BlobClient#renewLease(String)} and + * {@link BlobClient#renewLease(String, ModifiedAccessConditions, Duration)} + */ + public void renewLease() { + // BEGIN: com.azure.storage.blob.BlobClient.renewLease#String + System.out.printf("Renewed lease ID is %s%n", client.renewLease(leaseId).value()); + // END: com.azure.storage.blob.BlobClient.renewLease#String + + // BEGIN: com.azure.storage.blob.BlobClient.renewLease#String-ModifiedAccessConditions-Duration + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .ifUnmodifiedSince(OffsetDateTime.now().minusDays(3)); + + System.out.printf("Renewed lease ID is %s%n", client.renewLease(leaseId, modifiedAccessConditions, timeout).value()); + // END: com.azure.storage.blob.BlobClient.renewLease#String-ModifiedAccessConditions-Duration + } + + /** + * Code snippets for {@link BlobClient#releaseLease(String)} and + * {@link BlobClient#releaseLease(String, ModifiedAccessConditions, Duration)} + */ + public void releaseLease() { + // BEGIN: com.azure.storage.blob.BlobClient.releaseLease#String + System.out.printf("Release lease completed with status %d%n", client.releaseLease(leaseId).statusCode()); + // END: com.azure.storage.blob.BlobClient.releaseLease#String + + // BEGIN: com.azure.storage.blob.BlobClient.releaseLease#String-ModifiedAccessConditions-Duration + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .ifUnmodifiedSince(OffsetDateTime.now().minusDays(3)); + + System.out.printf("Release lease completed with status %d%n", client.releaseLease(leaseId, modifiedAccessConditions, timeout).statusCode()); + // END: com.azure.storage.blob.BlobClient.releaseLease#String-ModifiedAccessConditions-Duration + } + + /** + * Code snippets for {@link BlobClient#breakLease()} and + * {@link BlobClient#breakLease(Integer, ModifiedAccessConditions, Duration)} + */ + public void breakLease() { + // BEGIN: com.azure.storage.blob.BlobClient.breakLease + System.out.printf("The broken lease has %d seconds remaining on the lease", client.breakLease().value()); + // END: com.azure.storage.blob.BlobClient.breakLease + + // BEGIN: com.azure.storage.blob.BlobClient.breakLease#Integer-ModifiedAccessConditions-Duration + Integer retainLeaseInSeconds = 5; + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .ifUnmodifiedSince(OffsetDateTime.now().minusDays(3)); + + System.out.printf("The broken lease has %d seconds remaining on the lease", + client.breakLease(retainLeaseInSeconds, modifiedAccessConditions, timeout).value()); + // END: com.azure.storage.blob.BlobClient.breakLease#Integer-ModifiedAccessConditions-Duration + } + + /** + * Code snippets for {@link BlobClient#changeLease(String, String)} and + * {@link BlobClient#changeLease(String, String, ModifiedAccessConditions, Duration)} + */ + public void changeLease() { + // BEGIN: com.azure.storage.blob.BlobClient.changeLease#String-String + System.out.printf("Changed lease ID is %s%n", client.changeLease(leaseId, "proposedId").value()); + // END: com.azure.storage.blob.BlobClient.changeLease#String-String + + // BEGIN: com.azure.storage.blob.BlobClient.changeLease#String-String-ModifiedAccessConditions-Duration + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .ifUnmodifiedSince(OffsetDateTime.now().minusDays(3)); + + System.out.printf("Changed lease ID is %s%n", + client.changeLease(leaseId, "proposedId", modifiedAccessConditions, timeout).value()); + // END: com.azure.storage.blob.BlobClient.changeLease#String-String-ModifiedAccessConditions-Duration + } + + /** + * Code snippet for {@link BlobClient#getAccountInfo()} + */ + public void getAccountInfo() { + // BEGIN: com.azure.storage.blob.BlobClient.getAccountInfo + StorageAccountInfo accountInfo = client.getAccountInfo().value(); + System.out.printf("Account Kind: %s, SKU: %s%n", accountInfo.accountKind(), accountInfo.skuName()); + // END: com.azure.storage.blob.BlobClient.getAccountInfo + } + + /** + * Code snippet for {@link BlobClient#getAccountInfo(Duration)} + */ + public void getAccountInfoWithTimeout() { + // BEGIN: com.azure.storage.blob.BlobClient.getAccountInfo#Duration + StorageAccountInfo accountInfo = client.getAccountInfo(timeout).value(); + System.out.printf("Account Kind: %s, SKU: %s%n", accountInfo.accountKind(), accountInfo.skuName()); + // END: com.azure.storage.blob.BlobClient.getAccountInfo#Duration + } } diff --git a/storage/client/blob/src/samples/java/com/azure/storage/blob/JavaDocCodeSnippetsHelpers.java b/storage/client/blob/src/samples/java/com/azure/storage/blob/JavaDocCodeSnippetsHelpers.java index aafc13dde6912..20436f696b5c6 100644 --- a/storage/client/blob/src/samples/java/com/azure/storage/blob/JavaDocCodeSnippetsHelpers.java +++ b/storage/client/blob/src/samples/java/com/azure/storage/blob/JavaDocCodeSnippetsHelpers.java @@ -12,6 +12,10 @@ static BlobAsyncClient getBlobAsyncClient(String blobName) { return getContainerAsyncClient().getBlobAsyncClient(blobName); } + static BlobClient getBlobClient(String blobName) { + return new BlobClient(getBlobAsyncClient(blobName)); + } + static URL generateURL(String urlString) { try { return new URL(urlString); From c2165f6fc02fa3d1f403c56aadd3fc0fa54bbf72 Mon Sep 17 00:00:00 2001 From: alzimmermsft <48699787+alzimmermsft@users.noreply.github.com> Date: Tue, 23 Jul 2019 12:02:25 -0700 Subject: [PATCH 7/8] Added links to REST API docs for BlobAsyncClient and BlobClient, fixed JavaDoc issues, fix unit test issues --- .../azure/storage/blob/BlobAsyncClient.java | 121 ++++++++++++-- .../com/azure/storage/blob/BlobClient.java | 147 ++++++++++++++---- .../storage/blob/DownloadAsyncResponse.java | 2 +- .../BlobAsyncClientJavaDocCodeSnippets.java | 39 +++-- .../blob/BlobClientJavaDocCodeSnippets.java | 40 +++-- .../blob/JavaDocCodeSnippetsHelpers.java | 3 + .../com/azure/storage/blob/BlobAPITest.groovy | 4 +- 7 files changed, 284 insertions(+), 72 deletions(-) diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java index 2aa05f99e6240..cdb12d4736806 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java @@ -126,7 +126,7 @@ public PageBlobAsyncClient asPageBlobAsyncClient() { /** * Initializes a {@link ContainerAsyncClient} 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 + * 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 @@ -179,7 +179,7 @@ public Mono> exists() { * *

Code Samples

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

For more information, see the * Azure Docs

@@ -236,6 +236,9 @@ public Mono> startCopyFromURL(URL sourceURL, Metadata metadata, * * {@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. @@ -251,6 +254,9 @@ public Mono abortCopyFromURL(String copyId) { * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.abortCopyFromURL#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 @@ -270,6 +276,9 @@ public Mono abortCopyFromURL(String copyId, LeaseAccessConditions * * {@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. */ @@ -284,6 +293,9 @@ public Mono> copyFromURL(URL copySource) { * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.copyFromURL#URL-Metadata-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 sourceModifiedAccessConditions {@link ModifiedAccessConditions} against the source. Standard HTTP Access @@ -320,6 +332,9 @@ public Mono> copyFromURL(URL copySource, Metadata metadata, Mod * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.download} * + *

For more information, see the + * Azure Docs

+ * * @return A reactive response containing the blob data. */ public Mono>> download() { @@ -334,6 +349,9 @@ public Mono>> download() { * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.download#BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean} * + *

For more information, see the + * Azure Docs

+ * * @param range {@link BlobRange} * @param options {@link ReliableDownloadOptions} * @param accessConditions {@link BlobAccessConditions} @@ -402,6 +420,9 @@ Mono download(BlobRange range, BlobAccessConditions acces * * {@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 */ @@ -421,6 +442,9 @@ public Mono downloadToFile(String filePath) { * * {@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 @@ -491,6 +515,9 @@ private List sliceBlobRange(BlobRange blobRange, Integer blockSize) { * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.delete} * + *

For more information, see the + * Azure Docs

+ * * @return A reactive response signalling completion. */ public Mono delete() { @@ -504,6 +531,9 @@ public Mono delete() { * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.delete#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. @@ -527,6 +557,9 @@ public Mono delete(DeleteSnapshotsOptionType deleteBlobSnapshotOpt * * {@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() { @@ -540,6 +573,9 @@ public Mono> getProperties() { * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.getProperties#BlobAccessConditions} * + *

For more information, see the + * Azure Docs

+ * * @param accessConditions {@link BlobAccessConditions} * @return A reactive response containing the blob properties and metadata. */ @@ -555,14 +591,15 @@ public Mono> getProperties(BlobAccessConditions accessC /** * 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. For more information, - * see the - * Azure Docs. + * 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. */ @@ -572,14 +609,15 @@ public Mono setHTTPHeaders(BlobHTTPHeaders headers) { /** * 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. For more information, - * see the - * Azure Docs. + * order to preserve existing values, they must be passed alongside the header being changed. * *

Code Samples

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

For more information, see the + * Azure Docs

+ * * @param headers {@link BlobHTTPHeaders} * @param accessConditions {@link BlobAccessConditions} * @return A reactive response signalling completion. @@ -595,13 +633,15 @@ public Mono setHTTPHeaders(BlobHTTPHeaders headers, BlobAccessCond /** * 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. For more information, see the - * Azure Docs. + * 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. */ @@ -611,13 +651,15 @@ public Mono setMetadata(Metadata metadata) { /** * 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. For more information, see the - * Azure Docs. + * 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-BlobAccessConditions} * + *

For more information, see the + * Azure Docs

+ * * @param metadata {@link Metadata} * @param accessConditions {@link BlobAccessConditions} * @return A reactive response signalling completion. @@ -640,6 +682,9 @@ public Mono setMetadata(Metadata metadata, BlobAccessConditions ac * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.createSnapshot} * + *

For more information, see the + * Azure Docs

+ * * @return A reactive response containing the ID of the new snapshot. */ public Mono> createSnapshot() { @@ -653,6 +698,9 @@ public Mono> createSnapshot() { * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.createSnapshot#Metadata-BlobAccessConditions} * + *

For more information, see the + * Azure Docs

+ * * @param metadata {@link Metadata} * @param accessConditions {@link BlobAccessConditions} * @return A reactive response containing the ID of the new snapshot. @@ -678,6 +726,9 @@ public Mono> createSnapshot(Metadata metadata, BlobAccessCondit * * {@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. */ @@ -695,6 +746,9 @@ public Mono setTier(AccessTier tier) { * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.setTier#AccessTier-LeaseAccessConditions} * + *

For more information, see the + * Azure Docs

+ * * @param tier The new tier for the blob. * @param leaseAccessConditions By setting lease access conditions, requests will fail if the provided lease does * not match the active lease on the blob. @@ -715,6 +769,9 @@ public Mono setTier(AccessTier tier, LeaseAccessConditions leaseAc * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.undelete} * + *

For more information, see the + * Azure Docs

+ * * @return A reactive response signalling completion. */ public Mono undelete() { @@ -731,6 +788,9 @@ public Mono undelete() { * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.acquireLease#String-int} * + *

For more information, see the + * Azure Docs

+ * * @param proposedId A {@code String} in any valid GUID format. May be null. * @param duration The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A * non-infinite lease can be between 15 and 60 seconds. @@ -748,6 +808,9 @@ public Mono> acquireLease(String proposedId, int duration) { * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.acquireLease#String-int-ModifiedAccessConditions} * + *

For more information, see the + * Azure Docs

+ * * @param proposedId A {@code String} in any valid GUID format. May be null. * @param duration The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A * non-infinite lease can be between 15 and 60 seconds. @@ -777,6 +840,9 @@ public Mono> acquireLease(String proposedId, int duration, Modi * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.renewLease#String} * + *

For more information, see the + * Azure Docs

+ * * @param leaseId The leaseId of the active lease on the blob. * @return A reactive response containing the renewed lease ID. */ @@ -791,6 +857,9 @@ public Mono> renewLease(String leaseId) { * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.renewLease#String-ModifiedAccessConditions} * + *

For more information, see the + * Azure Docs

+ * * @param leaseId The leaseId of the active lease on the blob. * @param modifiedAccessConditions 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 @@ -810,6 +879,9 @@ public Mono> renewLease(String leaseId, ModifiedAccessCondition * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.releaseLease#String} * + *

For more information, see the + * Azure Docs

+ * * @param leaseId The leaseId of the active lease on the blob. * @return A reactive response signalling completion. */ @@ -824,6 +896,9 @@ public Mono releaseLease(String leaseId) { * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.releaseLease#String-ModifiedAccessConditions} * + *

For more information, see the + * Azure Docs

+ * * @param leaseId The leaseId of the active lease on the blob. * @param modifiedAccessConditions 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 @@ -844,6 +919,9 @@ public Mono releaseLease(String leaseId, ModifiedAccessConditions * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.breakLease} * + *

For more information, see the + * Azure Docs

+ * * @return A reactive response containing the remaining time in the broken lease in seconds. */ public Mono> breakLease() { @@ -858,6 +936,9 @@ public Mono> breakLease() { * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.breakLease#Integer-ModifiedAccessConditions} * + *

For more information, see the + * Azure Docs

+ * * @param breakPeriodInSeconds An optional {@code Integer} representing the proposed duration of seconds that the * lease should continue before it is broken, between 0 and 60 seconds. This break period is only used if it is * shorter than the time remaining on the lease. If longer, the time remaining on the lease is used. A new lease @@ -881,6 +962,9 @@ public Mono> breakLease(Integer breakPeriodInSeconds, Modified * * {@codesnippet com.azure.storage.blob.BlobAsyncClient.changeLease#String-String} * + *

For more information, see the + * Azure Docs

+ * * @param leaseId The leaseId of the active lease on the blob. * @param proposedId A {@code String} in any valid GUID format. * @return A reactive response containing the new lease ID. @@ -890,13 +974,15 @@ public Mono> changeLease(String leaseId, String proposedId) { } /** - * ChangeLease changes the blob's lease ID. For more information, see the Azure - * Docs. + * ChangeLease changes the blob's lease ID. * *

Code Samples

* * {@codesnippet com.azure.storage.blob.BlobAsyncClient.changeLease#String-String-ModifiedAccessConditions} * + *

For more information, see the + * Azure Docs

+ * * @param leaseId The leaseId of the active lease on the blob. * @param proposedId A {@code String} in any valid GUID format. * @param modifiedAccessConditions Standard HTTP Access conditions related to the modification of data. ETag and @@ -911,16 +997,17 @@ public Mono> changeLease(String leaseId, String proposedId, Mod } /** - * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. + * 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. */ - // TODO (unknown): determine this return type public Mono> getAccountInfo() { return postProcessResponse( this.azureBlobStorage.blobs().getAccountInfoWithRestResponseAsync(null, null, Context.NONE)) diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java index 04c15df61a8dd..8c90be15409b6 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java @@ -162,13 +162,15 @@ public Response exists(Duration timeout) { } /** - * Copies the data at the source URL to a blob. For more information, see the - * Azure Docs + * 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. */ @@ -177,13 +179,15 @@ public Response startCopyFromURL(URL sourceURL) { } /** - * Copies the data at the source URL to a blob. For more information, see the - * Azure Docs + * Copies the data at the source URL to a blob. * *

Code Samples

* * {@codesnippet com.azure.storage.blob.BlobClient.startCopyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions-Duration} * + *

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 sourceModifiedAccessConditions {@link ModifiedAccessConditions} against the source. Standard HTTP Access @@ -194,9 +198,8 @@ public Response startCopyFromURL(URL sourceURL) { * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return The copy ID for the long running operation. */ - public Response startCopyFromURL(URL sourceURL, Metadata metadata, - ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions, - Duration timeout) { + public Response startCopyFromURL(URL sourceURL, Metadata metadata, ModifiedAccessConditions sourceModifiedAccessConditions, + BlobAccessConditions destAccessConditions, Duration timeout) { Mono> response = blobAsyncClient .startCopyFromURL(sourceURL, metadata, sourceModifiedAccessConditions, destAccessConditions); @@ -210,6 +213,9 @@ public Response startCopyFromURL(URL sourceURL, Metadata metadata, * * {@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. * @return A response containing status code and HTTP headers. @@ -225,6 +231,9 @@ public VoidResponse abortCopyFromURL(String copyId) { * * {@codesnippet com.azure.storage.blob.BlobClient.abortCopyFromURL#String-LeaseAccessConditions-Duration} * + *

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 @@ -246,6 +255,9 @@ public VoidResponse abortCopyFromURL(String copyId, LeaseAccessConditions leaseA * * {@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. */ @@ -260,6 +272,9 @@ public Response copyFromURL(URL copySource) { * * {@codesnippet com.azure.storage.blob.BlobClient.copyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions-Duration} * + *

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 sourceModifiedAccessConditions {@link ModifiedAccessConditions} against the source. Standard HTTP Access @@ -270,9 +285,8 @@ public Response copyFromURL(URL copySource) { * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return The copy ID for the long running operation. */ - public Response copyFromURL(URL copySource, Metadata metadata, - ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions, - Duration timeout) { + public Response copyFromURL(URL copySource, Metadata metadata, ModifiedAccessConditions sourceModifiedAccessConditions, + BlobAccessConditions destAccessConditions, Duration timeout) { Mono> response = blobAsyncClient .copyFromURL(copySource, metadata, sourceModifiedAccessConditions, destAccessConditions); @@ -287,6 +301,9 @@ public Response copyFromURL(URL copySource, Metadata metadata, * * {@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. * @return A response containing status code and HTTP headers. * @throws UncheckedIOException If an I/O error occurs. @@ -303,6 +320,9 @@ public VoidResponse download(OutputStream stream) { * * {@codesnippet com.azure.storage.blob.BlobClient.download#OutputStream-BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration} * + *

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} @@ -339,6 +359,9 @@ public VoidResponse download(OutputStream stream, BlobRange range, ReliableDownl * * {@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 */ @@ -355,6 +378,9 @@ public void downloadToFile(String filePath) { * * {@codesnippet com.azure.storage.blob.BlobClient.downloadToFile#String-BlobRange-Integer-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration} * + *

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 @@ -378,6 +404,9 @@ public void downloadToFile(String filePath, BlobRange range, Integer blockSize, * * {@codesnippet com.azure.storage.blob.BlobClient.delete} * + *

For more information, see the + * Azure Docs

+ * * @return A response containing status code and HTTP headers. */ public VoidResponse delete() { @@ -391,6 +420,9 @@ public VoidResponse delete() { * * {@codesnippet com.azure.storage.blob.BlobClient.delete#DeleteSnapshotsOptionType-BlobAccessConditions-Duration} * + *

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. @@ -413,6 +445,9 @@ public VoidResponse delete(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, * * {@codesnippet com.azure.storage.blob.BlobClient.getProperties} * + *

For more information, see the + * Azure Docs

+ * * @return The blob properties and metadata. */ public Response getProperties() { @@ -426,6 +461,9 @@ public Response getProperties() { * * {@codesnippet com.azure.storage.blob.BlobClient.getProperties#BlobAccessConditions-Duration} * + *

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. * @return The blob properties and metadata. @@ -439,14 +477,15 @@ public Response getProperties(BlobAccessConditions accessConditi /** * 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. For more information, - * see the - * Azure Docs. + * 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} * @return A response containing status code and HTTP headers. */ @@ -456,14 +495,15 @@ public VoidResponse setHTTPHeaders(BlobHTTPHeaders headers) { /** * 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. For more information, - * see the - * Azure Docs. + * order to preserve existing values, they must be passed alongside the header being changed. * *

Code Samples

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

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. @@ -479,13 +519,15 @@ public VoidResponse setHTTPHeaders(BlobHTTPHeaders headers, BlobAccessConditions /** * 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. For more information, see the - * Azure Docs. + * 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} * @return A response containing status code and HTTP headers. */ @@ -495,13 +537,15 @@ public VoidResponse setMetadata(Metadata metadata) { /** * 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. For more information, see the - * Azure Docs. + * 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-BlobAccessConditions-Duration} * + *

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. @@ -521,6 +565,9 @@ public VoidResponse setMetadata(Metadata metadata, BlobAccessConditions accessCo * * {@codesnippet com.azure.storage.blob.BlobClient.createSnapshot} * + *

For more information, see the + * Azure Docs

+ * * @return The ID of the new snapshot. */ public Response createSnapshot() { @@ -534,6 +581,9 @@ public Response createSnapshot() { * * {@codesnippet com.azure.storage.blob.BlobClient.createSnapshot#Metadata-BlobAccessConditions-Duration} * + *

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. @@ -556,6 +606,9 @@ public Response createSnapshot(Metadata metadata, BlobAccessConditions a * * {@codesnippet com.azure.storage.blob.BlobClient.setTier#AccessTier} * + *

For more information, see the + * Azure Docs

+ * * @param tier The new tier for the blob. * @return A response containing status code and HTTP headers. */ @@ -573,6 +626,9 @@ public VoidResponse setTier(AccessTier tier) { * * {@codesnippet com.azure.storage.blob.BlobClient.setTier#AccessTier-LeaseAccessConditions-Duration} * + *

For more information, see the + * Azure Docs

+ * * @param tier The new tier for the blob. * @param leaseAccessConditions By setting lease access conditions, requests will fail if the provided lease does * not match the active lease on the blob. @@ -593,6 +649,9 @@ public VoidResponse setTier(AccessTier tier, LeaseAccessConditions leaseAccessCo * * {@codesnippet com.azure.storage.blob.BlobClient.undelete} * + *

For more information, see the + * Azure Docs

+ * * @return A response containing status code and HTTP headers. */ public VoidResponse undelete() { @@ -606,6 +665,9 @@ public VoidResponse undelete() { * * {@codesnippet com.azure.storage.blob.BlobClient.undelete#Duration} * + *

For more information, see the + * Azure Docs

+ * * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return A response containing status code and HTTP headers. */ @@ -624,6 +686,9 @@ public VoidResponse undelete(Duration timeout) { * * {@codesnippet com.azure.storage.blob.BlobClient.acquireLease#String-int} * + *

For more information, see the + * Azure Docs

+ * * @param proposedId A {@code String} in any valid GUID format. May be null. * @param duration The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A * non-infinite lease can be between 15 and 60 seconds. @@ -641,6 +706,9 @@ public Response acquireLease(String proposedId, int duration) { * * {@codesnippet com.azure.storage.blob.BlobClient.acquireLease#String-int-ModifiedAccessConditions-Duration} * + *

For more information, see the + * Azure Docs

+ * * @param proposedId A {@code String} in any valid GUID format. May be null. * @param duration The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A * non-infinite lease can be between 15 and 60 seconds. @@ -665,6 +733,9 @@ public Response acquireLease(String proposedId, int duration, * * {@codesnippet com.azure.storage.blob.BlobClient.renewLease#String} * + *

For more information, see the + * Azure Docs

+ * * @param leaseId The leaseId of the active lease on the blob. * @return The renewed lease ID. */ @@ -679,6 +750,9 @@ public Response renewLease(String leaseId) { * * {@codesnippet com.azure.storage.blob.BlobClient.renewLease#String-ModifiedAccessConditions-Duration} * + *

For more information, see the + * Azure Docs

+ * * @param leaseId The leaseId of the active lease on the blob. * @param modifiedAccessConditions 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 @@ -701,6 +775,9 @@ public Response renewLease(String leaseId, ModifiedAccessConditions modi * * {@codesnippet com.azure.storage.blob.BlobClient.releaseLease#String} * + *

For more information, see the + * Azure Docs

+ * * @param leaseId The leaseId of the active lease on the blob. * @return A response containing status code and HTTP headers. */ @@ -715,6 +792,9 @@ public VoidResponse releaseLease(String leaseId) { * * {@codesnippet com.azure.storage.blob.BlobClient.releaseLease#String-ModifiedAccessConditions-Duration} * + *

For more information, see the + * Azure Docs

+ * * @param leaseId The leaseId of the active lease on the blob. * @param modifiedAccessConditions 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 @@ -736,6 +816,9 @@ public VoidResponse releaseLease(String leaseId, ModifiedAccessConditions modifi * * {@codesnippet com.azure.storage.blob.BlobClient.breakLease} * + *

For more information, see the + * Azure Docs

+ * * @return The remaining time in the broken lease in seconds. */ public Response breakLease() { @@ -750,6 +833,9 @@ public Response breakLease() { * * {@codesnippet com.azure.storage.blob.BlobClient.breakLease#Integer-ModifiedAccessConditions-Duration} * + *

For more information, see the + * Azure Docs

+ * * @param breakPeriodInSeconds An optional {@code Integer} representing the proposed duration of seconds that the * lease should continue before it is broken, between 0 and 60 seconds. This break period is only used if it is * shorter than the time remaining on the lease. If longer, the time remaining on the lease is used. A new lease @@ -775,6 +861,9 @@ public Response breakLease(Integer breakPeriodInSeconds, ModifiedAccess * * {@codesnippet com.azure.storage.blob.BlobClient.changeLease#String-String} * + *

For more information, see the + * Azure Docs

+ * * @param leaseId The leaseId of the active lease on the blob. * @param proposedId A {@code String} in any valid GUID format. * @return The new lease ID. @@ -784,13 +873,15 @@ public Response changeLease(String leaseId, String proposedId) { } /** - * ChangeLease changes the blob's lease ID. For more information, see the Azure - * Docs. + * ChangeLease changes the blob's lease ID. * *

Code Samples

* * {@codesnippet com.azure.storage.blob.BlobClient.changeLease#String-String-ModifiedAccessConditions-Duration} * + *

For more information, see the + * Azure Docs

+ * * @param leaseId The leaseId of the active lease on the blob. * @param proposedId A {@code String} in any valid GUID format. * @param modifiedAccessConditions Standard HTTP Access conditions related to the modification of data. ETag and @@ -806,13 +897,15 @@ public Response changeLease(String leaseId, String proposedId, ModifiedA } /** - * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. + * 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 Response getAccountInfo() { @@ -820,13 +913,15 @@ public Response getAccountInfo() { } /** - * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. + * Returns the sku name and account kind for the account. * *

Code Samples

* * {@codesnippet com.azure.storage.blob.BlobClient.getAccountInfo#Duration} * + *

For more information, see the + * Azure Docs

+ * * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. * @return The sku name and account kind. */ diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/DownloadAsyncResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/DownloadAsyncResponse.java index e22a3fa72a16c..c27ad3645d207 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/DownloadAsyncResponse.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/DownloadAsyncResponse.java @@ -18,7 +18,7 @@ /** * {@code DownloadAsyncResponse} wraps the protocol-layer response from {@link BlobAsyncClient#download(BlobRange, - * BlobAccessConditions, boolean, ReliableDownloadOptions)} to automatically retry failed reads from the body as + * ReliableDownloadOptions, BlobAccessConditions, boolean)} to automatically retry failed reads from the body as * appropriate. If the download is interrupted, the {@code DownloadAsyncResponse} will make a request to resume the download * from where it left off, allowing the user to consume the data as one continuous stream, for any interruptions are * hidden. The retry behavior is defined by the options passed to the {@link #body(ReliableDownloadOptions)}. The diff --git a/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobAsyncClientJavaDocCodeSnippets.java b/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobAsyncClientJavaDocCodeSnippets.java index 78efe3d743fa6..3b82eabc7bcfc 100644 --- a/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobAsyncClientJavaDocCodeSnippets.java +++ b/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobAsyncClientJavaDocCodeSnippets.java @@ -52,7 +52,8 @@ public void startCopyFromURL() { // BEGIN: com.azure.storage.blob.BlobAsyncClient.startCopyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); - ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions().ifUnmodifiedSince(OffsetDateTime.now().minusDays(7)); + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .ifUnmodifiedSince(OffsetDateTime.now().minusDays(7)); BlobAccessConditions blobAccessConditions = new BlobAccessConditions() .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); @@ -89,7 +90,8 @@ public void copyFromURL() { // BEGIN: com.azure.storage.blob.BlobAsyncClient.copyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); - ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions().ifUnmodifiedSince(OffsetDateTime.now().minusDays(7)); + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .ifUnmodifiedSince(OffsetDateTime.now().minusDays(7)); BlobAccessConditions blobAccessConditions = new BlobAccessConditions() .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); @@ -101,6 +103,8 @@ public void copyFromURL() { /** * Code snippets for {@link BlobAsyncClient#download()} and * {@link BlobAsyncClient#download(BlobRange, ReliableDownloadOptions, BlobAccessConditions, boolean)} + * + * @throws UncheckedIOException If an I/O error occurs */ public void download() { // BEGIN: com.azure.storage.blob.BlobAsyncClient.download @@ -157,7 +161,8 @@ public void downloadToFile() { */ public void delete() { // BEGIN: com.azure.storage.blob.BlobAsyncClient.delete - client.delete().subscribe(response -> System.out.printf("Delete completed with status %d%n", response.statusCode())); + client.delete() + .subscribe(response -> System.out.printf("Delete completed with status %d%n", response.statusCode())); // END: com.azure.storage.blob.BlobAsyncClient.delete // BEGIN: com.azure.storage.blob.BlobAsyncClient.delete#DeleteSnapshotsOptionType-BlobAccessConditions @@ -233,7 +238,8 @@ public void setMetadata() { */ public void createSnapshot() { // BEGIN: com.azure.storage.blob.BlobAsyncClient.createSnapshot - client.createSnapshot().subscribe(response -> System.out.printf("Identifier for the snapshot is %s%n", response.value())); + client.createSnapshot() + .subscribe(response -> System.out.printf("Identifier for the snapshot is %s%n", response.value())); // END: com.azure.storage.blob.BlobAsyncClient.createSnapshot // BEGIN: com.azure.storage.blob.BlobAsyncClient.createSnapshot#Metadata-BlobAccessConditions @@ -252,7 +258,8 @@ public void createSnapshot() { */ public void setTier() { // BEGIN: com.azure.storage.blob.BlobAsyncClient.setTier#AccessTier - client.setTier(AccessTier.HOT).subscribe(response -> System.out.printf("Set tier completed with status code %d%n", response.statusCode())); + client.setTier(AccessTier.HOT) + .subscribe(response -> System.out.printf("Set tier completed with status code %d%n", response.statusCode())); // END: com.azure.storage.blob.BlobAsyncClient.setTier#AccessTier // BEGIN: com.azure.storage.blob.BlobAsyncClient.setTier#AccessTier-LeaseAccessConditions @@ -268,7 +275,8 @@ public void setTier() { */ public void undelete() { // BEGIN: com.azure.storage.blob.BlobAsyncClient.undelete - client.undelete().subscribe(response -> System.out.printf("Undelete completed with status %d%n", response.statusCode())); + client.undelete() + .subscribe(response -> System.out.printf("Undelete completed with status %d%n", response.statusCode())); // END: com.azure.storage.blob.BlobAsyncClient.undelete } @@ -278,7 +286,8 @@ public void undelete() { */ public void acquireLease() { // BEGIN: com.azure.storage.blob.BlobAsyncClient.acquireLease#String-int - client.acquireLease("proposedId", 60).subscribe(response -> System.out.printf("Lease ID is %s%n", response.value())); + client.acquireLease("proposedId", 60) + .subscribe(response -> System.out.printf("Lease ID is %s%n", response.value())); // END: com.azure.storage.blob.BlobAsyncClient.acquireLease#String-int // BEGIN: com.azure.storage.blob.BlobAsyncClient.acquireLease#String-int-ModifiedAccessConditions @@ -296,7 +305,8 @@ public void acquireLease() { */ public void renewLease() { // BEGIN: com.azure.storage.blob.BlobAsyncClient.renewLease#String - client.renewLease(leaseId).subscribe(response -> System.out.printf("Renewed lease ID is %s%n", response.value())); + client.renewLease(leaseId) + .subscribe(response -> System.out.printf("Renewed lease ID is %s%n", response.value())); // END: com.azure.storage.blob.BlobAsyncClient.renewLease#String // BEGIN: com.azure.storage.blob.BlobAsyncClient.renewLease#String-ModifiedAccessConditions @@ -314,7 +324,8 @@ public void renewLease() { */ public void releaseLease() { // BEGIN: com.azure.storage.blob.BlobAsyncClient.releaseLease#String - client.releaseLease(leaseId).subscribe(response -> System.out.printf("Release lease completed with status %d%n", response.statusCode())); + client.releaseLease(leaseId) + .subscribe(response -> System.out.printf("Release lease completed with status %d%n", response.statusCode())); // END: com.azure.storage.blob.BlobAsyncClient.releaseLease#String // BEGIN: com.azure.storage.blob.BlobAsyncClient.releaseLease#String-ModifiedAccessConditions @@ -332,7 +343,9 @@ public void releaseLease() { */ public void breakLease() { // BEGIN: com.azure.storage.blob.BlobAsyncClient.breakLease - client.breakLease().subscribe(response -> System.out.printf("The broken lease has %d seconds remaining on the lease", response.value())); + client.breakLease() + .subscribe(response -> + System.out.printf("The broken lease has %d seconds remaining on the lease", response.value())); // END: com.azure.storage.blob.BlobAsyncClient.breakLease // BEGIN: com.azure.storage.blob.BlobAsyncClient.breakLease#Integer-ModifiedAccessConditions @@ -341,7 +354,8 @@ public void breakLease() { .ifUnmodifiedSince(OffsetDateTime.now().minusDays(3)); client.breakLease(retainLeaseInSeconds, modifiedAccessConditions) - .subscribe(response -> System.out.printf("The broken lease has %d seconds remaining on the lease", response.value())); + .subscribe(response -> + System.out.printf("The broken lease has %d seconds remaining on the lease", response.value())); // END: com.azure.storage.blob.BlobAsyncClient.breakLease#Integer-ModifiedAccessConditions } @@ -351,7 +365,8 @@ public void breakLease() { */ public void changeLease() { // BEGIN: com.azure.storage.blob.BlobAsyncClient.changeLease#String-String - client.changeLease(leaseId, "proposedId").subscribe(response -> System.out.printf("Changed lease ID is %s%n", response.value())); + client.changeLease(leaseId, "proposedId") + .subscribe(response -> System.out.printf("Changed lease ID is %s%n", response.value())); // END: com.azure.storage.blob.BlobAsyncClient.changeLease#String-String // BEGIN: com.azure.storage.blob.BlobAsyncClient.changeLease#String-String-ModifiedAccessConditions diff --git a/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobClientJavaDocCodeSnippets.java b/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobClientJavaDocCodeSnippets.java index 33e9d4ac46e40..d99b83f910ad2 100644 --- a/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobClientJavaDocCodeSnippets.java +++ b/storage/client/blob/src/samples/java/com/azure/storage/blob/BlobClientJavaDocCodeSnippets.java @@ -57,7 +57,8 @@ public void startCopyFromURL() { // BEGIN: com.azure.storage.blob.BlobClient.startCopyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions-Duration Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); - ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions().ifUnmodifiedSince(OffsetDateTime.now().minusDays(7)); + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .ifUnmodifiedSince(OffsetDateTime.now().minusDays(7)); BlobAccessConditions blobAccessConditions = new BlobAccessConditions() .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); @@ -77,7 +78,8 @@ public void abortCopyFromURL() { // BEGIN: com.azure.storage.blob.BlobClient.abortCopyFromURL#String-LeaseAccessConditions-Duration LeaseAccessConditions leaseAccessConditions = new LeaseAccessConditions().leaseId(leaseId); - System.out.printf("Aborted copy completed with status %d%n", client.abortCopyFromURL(copyId, leaseAccessConditions, timeout).statusCode()); + System.out.printf("Aborted copy completed with status %d%n", + client.abortCopyFromURL(copyId, leaseAccessConditions, timeout).statusCode()); // END: com.azure.storage.blob.BlobClient.abortCopyFromURL#String-LeaseAccessConditions-Duration } @@ -92,11 +94,13 @@ public void copyFromURL() { // BEGIN: com.azure.storage.blob.BlobClient.copyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions-Duration Metadata metadata = new Metadata(Collections.singletonMap("metadata", "value")); - ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions().ifUnmodifiedSince(OffsetDateTime.now().minusDays(7)); + ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() + .ifUnmodifiedSince(OffsetDateTime.now().minusDays(7)); BlobAccessConditions blobAccessConditions = new BlobAccessConditions() .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); - System.out.printf("Copy identifier: %s%n", client.copyFromURL(url, metadata, modifiedAccessConditions, blobAccessConditions, timeout).value()); + System.out.printf("Copy identifier: %s%n", + client.copyFromURL(url, metadata, modifiedAccessConditions, blobAccessConditions, timeout).value()); // END: com.azure.storage.blob.BlobClient.copyFromURL#URL-Metadata-ModifiedAccessConditions-BlobAccessConditions-Duration } @@ -105,9 +109,10 @@ public void copyFromURL() { * {@link BlobClient#download(OutputStream, BlobRange, ReliableDownloadOptions, BlobAccessConditions, boolean, Duration)} */ public void download() { - // BEGIN: com.azure.storage.blob.BlobClient.download#OutputSteam - System.out.printf("Download completed with status %d%n", client.download(new ByteArrayOutputStream()).statusCode()); - // END: com.azure.storage.blob.BlobClient.download#OutputSteam + // BEGIN: com.azure.storage.blob.BlobClient.download#OutputStream + System.out.printf("Download completed with status %d%n", + client.download(new ByteArrayOutputStream()).statusCode()); + // END: com.azure.storage.blob.BlobClient.download#OutputStream // BEGIN: com.azure.storage.blob.BlobClient.download#OutputStream-BlobRange-ReliableDownloadOptions-BlobAccessConditions-boolean-Duration BlobRange range = new BlobRange(1024, 2048); @@ -147,7 +152,8 @@ public void delete() { // END: com.azure.storage.blob.BlobClient.delete // BEGIN: com.azure.storage.blob.BlobClient.delete#DeleteSnapshotsOptionType-BlobAccessConditions-Duration - System.out.printf("Delete completed with status %d%n", client.delete(DeleteSnapshotsOptionType.INCLUDE, null, timeout).statusCode()); + System.out.printf("Delete completed with status %d%n", + client.delete(DeleteSnapshotsOptionType.INCLUDE, null, timeout).statusCode()); // END: com.azure.storage.blob.BlobClient.delete#DeleteSnapshotsOptionType-BlobAccessConditions-Duration } @@ -214,7 +220,8 @@ public void setMetadata() { .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); System.out.printf("Set metadata completed with status %d%n", - client.setMetadata(new Metadata(Collections.singletonMap("metadata", "value")), accessConditions, timeout).statusCode()); + client.setMetadata( + new Metadata(Collections.singletonMap("metadata", "value")), accessConditions, timeout).statusCode()); // END: com.azure.storage.blob.BlobClient.setMetadata#Metadata-BlobAccessConditions-Duration } @@ -232,7 +239,8 @@ public void createSnapshot() { BlobAccessConditions accessConditions = new BlobAccessConditions() .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseId)); - System.out.printf("Identifier for the snapshot is %s%n", client.createSnapshot(snapshotMetadata, accessConditions, timeout).value()); + System.out.printf("Identifier for the snapshot is %s%n", + client.createSnapshot(snapshotMetadata, accessConditions, timeout).value()); // END: com.azure.storage.blob.BlobClient.createSnapshot#Metadata-BlobAccessConditions-Duration } @@ -248,7 +256,8 @@ public void setTier() { // BEGIN: com.azure.storage.blob.BlobClient.setTier#AccessTier-LeaseAccessConditions-Duration LeaseAccessConditions accessConditions = new LeaseAccessConditions().leaseId(leaseId); - System.out.printf("Set tier completed with status code %d%n", client.setTier(AccessTier.HOT, accessConditions, timeout).statusCode()); + System.out.printf("Set tier completed with status code %d%n", + client.setTier(AccessTier.HOT, accessConditions, timeout).statusCode()); // END: com.azure.storage.blob.BlobClient.setTier#AccessTier-LeaseAccessConditions-Duration } @@ -278,7 +287,8 @@ public void acquireLease() { ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() .ifModifiedSince(OffsetDateTime.now().minusDays(3)); - System.out.printf("Lease ID is %s%n", client.acquireLease("proposedId", 60, modifiedAccessConditions, timeout).value()); + System.out.printf("Lease ID is %s%n", + client.acquireLease("proposedId", 60, modifiedAccessConditions, timeout).value()); // END: com.azure.storage.blob.BlobClient.acquireLease#String-int-ModifiedAccessConditions-Duration } @@ -295,7 +305,8 @@ public void renewLease() { ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() .ifUnmodifiedSince(OffsetDateTime.now().minusDays(3)); - System.out.printf("Renewed lease ID is %s%n", client.renewLease(leaseId, modifiedAccessConditions, timeout).value()); + System.out.printf("Renewed lease ID is %s%n", + client.renewLease(leaseId, modifiedAccessConditions, timeout).value()); // END: com.azure.storage.blob.BlobClient.renewLease#String-ModifiedAccessConditions-Duration } @@ -312,7 +323,8 @@ public void releaseLease() { ModifiedAccessConditions modifiedAccessConditions = new ModifiedAccessConditions() .ifUnmodifiedSince(OffsetDateTime.now().minusDays(3)); - System.out.printf("Release lease completed with status %d%n", client.releaseLease(leaseId, modifiedAccessConditions, timeout).statusCode()); + System.out.printf("Release lease completed with status %d%n", + client.releaseLease(leaseId, modifiedAccessConditions, timeout).statusCode()); // END: com.azure.storage.blob.BlobClient.releaseLease#String-ModifiedAccessConditions-Duration } diff --git a/storage/client/blob/src/samples/java/com/azure/storage/blob/JavaDocCodeSnippetsHelpers.java b/storage/client/blob/src/samples/java/com/azure/storage/blob/JavaDocCodeSnippetsHelpers.java index 20436f696b5c6..febf2861cad9a 100644 --- a/storage/client/blob/src/samples/java/com/azure/storage/blob/JavaDocCodeSnippetsHelpers.java +++ b/storage/client/blob/src/samples/java/com/azure/storage/blob/JavaDocCodeSnippetsHelpers.java @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + package com.azure.storage.blob; import java.net.MalformedURLException; diff --git a/storage/client/blob/src/test/java/com/azure/storage/blob/BlobAPITest.groovy b/storage/client/blob/src/test/java/com/azure/storage/blob/BlobAPITest.groovy index 0cf250d85d174..4f5a6947c9af1 100644 --- a/storage/client/blob/src/test/java/com/azure/storage/blob/BlobAPITest.groovy +++ b/storage/client/blob/src/test/java/com/azure/storage/blob/BlobAPITest.groovy @@ -139,7 +139,7 @@ class BlobAPITest extends APISpec { when: def outStream = new ByteArrayOutputStream() - bu.download(outStream, null, range, null, false, null) + bu.download(outStream, range, null, null, false, null) String bodyStr = outStream.toString() then: @@ -209,7 +209,7 @@ class BlobAPITest extends APISpec { def "Download md5"() { when: - VoidResponse response = bu.download(new ByteArrayOutputStream(), null, new BlobRange(0 ,3), null, true, null) + VoidResponse response = bu.download(new ByteArrayOutputStream(), new BlobRange(0 ,3), null, null, true, null) byte[] contentMD5 = response.headers().value("content-md5").getBytes() then: From 9bf21cf1582cb8ba23312df45d6438d26b4d9702 Mon Sep 17 00:00:00 2001 From: alzimmermsft <48699787+alzimmermsft@users.noreply.github.com> Date: Tue, 30 Jul 2019 16:17:14 -0700 Subject: [PATCH 8/8] Removed invalid import --- .../src/main/java/com/azure/storage/blob/BlobAsyncClient.java | 1 - 1 file changed, 1 deletion(-) diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java index 430f74dc2b0bf..ad598f8a8983b 100644 --- a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java @@ -3,7 +3,6 @@ package com.azure.storage.blob; -import com.azure.core.annotations.HEAD; import com.azure.core.http.HttpResponse; import com.azure.core.http.rest.Response; import com.azure.core.http.rest.SimpleResponse;