org.apache.maven.plugins
maven-javadoc-plugin
diff --git a/storage/client/src/main/java/com/azure/storage/blob/AccountSASPermission.java b/storage/client/src/main/java/com/azure/storage/blob/AccountSASPermission.java
new file mode 100644
index 0000000000000..2e909098792d6
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/AccountSASPermission.java
@@ -0,0 +1,252 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import java.util.Locale;
+
+/**
+ * This is a helper class to construct a string representing the permissions granted by an AccountSAS. Setting a value
+ * to true means that any SAS which uses these permissions will grant permissions for that operation. Once all the
+ * values are set, this should be serialized with toString and set as the permissions field on an
+ * {@link AccountSASSignatureValues} object. It is possible to construct the permissions string without this class, but
+ * the order of the permissions is particular and this class guarantees correctness.
+ */
+final class AccountSASPermission {
+
+ private boolean read;
+
+ private boolean add;
+
+ private boolean create;
+
+ private boolean write;
+
+ private boolean delete;
+
+ private boolean list;
+
+ private boolean update;
+
+ private boolean processMessages;
+
+ /**
+ * Initializes an {@code AccountSASPermission} object with all fields set to false.
+ */
+ public AccountSASPermission() {
+ }
+
+ /**
+ * Creates an {@code AccountSASPermission} from the specified permissions string. This method will throw an
+ * {@code IllegalArgumentException} if it encounters a character that does not correspond to a valid permission.
+ *
+ * @param permString
+ * A {@code String} which represents the {@code SharedAccessAccountPermissions}.
+ *
+ * @return An {@code AccountSASPermission} object generated from the given {@code String}.
+ */
+ public static AccountSASPermission parse(String permString) {
+ AccountSASPermission permissions = new AccountSASPermission();
+
+ for (int i = 0; i < permString.length(); i++) {
+ char c = permString.charAt(i);
+ switch (c) {
+ case 'r':
+ permissions.read = true;
+ break;
+ case 'w':
+ permissions.write = true;
+ break;
+ case 'd':
+ permissions.delete = true;
+ break;
+ case 'l':
+ permissions.list = true;
+ break;
+ case 'a':
+ permissions.add = true;
+ break;
+ case 'c':
+ permissions.create = true;
+ break;
+ case 'u':
+ permissions.update = true;
+ break;
+ case 'p':
+ permissions.processMessages = true;
+ break;
+ default:
+ throw new IllegalArgumentException(
+ String.format(Locale.ROOT, SR.ENUM_COULD_NOT_BE_PARSED_INVALID_VALUE, "Permissions", permString, c));
+ }
+ }
+ return permissions;
+ }
+
+ /**
+ * Permission to read resources and list queues and tables granted.
+ */
+ public boolean read() {
+ return read;
+ }
+
+ /**
+ * Permission to read resources and list queues and tables granted.
+ */
+ public AccountSASPermission withRead(boolean read) {
+ this.read = read;
+ return this;
+ }
+
+ /**
+ * Permission to add messages, table entities, and append to blobs granted.
+ */
+ public boolean add() {
+ return add;
+ }
+
+ /**
+ * Permission to add messages, table entities, and append to blobs granted.
+ */
+ public AccountSASPermission withAdd(boolean add) {
+ this.add = add;
+ return this;
+ }
+
+ /**
+ * Permission to create blobs and files granted.
+ */
+ public boolean create() {
+ return create;
+ }
+
+ /**
+ * Permission to create blobs and files granted.
+ */
+ public AccountSASPermission withCreate(boolean create) {
+ this.create = create;
+ return this;
+ }
+
+ /**
+ * Permission to write resources granted.
+ */
+ public boolean write() {
+ return write;
+ }
+
+ /**
+ * Permission to write resources granted.
+ */
+ public AccountSASPermission withWrite(boolean write) {
+ this.write = write;
+ return this;
+ }
+
+ /**
+ * Permission to delete resources granted.
+ */
+ public boolean delete() {
+ return delete;
+ }
+
+ /**
+ * Permission to delete resources granted.
+ */
+ public AccountSASPermission withDelete(boolean delete) {
+ this.delete = delete;
+ return this;
+ }
+
+ /**
+ * Permission to list blob containers, blobs, shares, directories, and files granted.
+ */
+ public boolean list() {
+ return list;
+ }
+
+ /**
+ * Permission to list blob containers, blobs, shares, directories, and files granted.
+ */
+ public AccountSASPermission withList(boolean list) {
+ this.list = list;
+ return this;
+ }
+
+ /**
+ * Permissions to update messages and table entities granted.
+ */
+ public boolean update() {
+ return update;
+ }
+
+ /**
+ * Permissions to update messages and table entities granted.
+ */
+ public AccountSASPermission withUpdate(boolean update) {
+ this.update = update;
+ return this;
+ }
+
+ /**
+ * Permission to get and delete messages granted.
+ */
+ public boolean processMessages() {
+ return processMessages;
+ }
+
+ /**
+ * Permission to get and delete messages granted.
+ */
+ public AccountSASPermission withProcessMessages(boolean processMessages) {
+ this.processMessages = processMessages;
+ return this;
+ }
+
+ /**
+ * Converts the given permissions to a {@code String}. Using this method will guarantee the permissions are in an
+ * order accepted by the service.
+ *
+ * @return A {@code String} which represents the {@code AccountSASPermissions}.
+ */
+ @Override
+ public String toString() {
+ // The order of the characters should be as specified here to ensure correctness:
+ // https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas
+ final StringBuilder builder = new StringBuilder();
+
+ if (this.read) {
+ builder.append('r');
+ }
+
+ if (this.write) {
+ builder.append('w');
+ }
+
+ if (this.delete) {
+ builder.append('d');
+ }
+
+ if (this.list) {
+ builder.append('l');
+ }
+
+ if (this.add) {
+ builder.append('a');
+ }
+
+ if (this.create) {
+ builder.append('c');
+ }
+
+ if (this.update) {
+ builder.append('u');
+ }
+
+ if (this.processMessages) {
+ builder.append('p');
+ }
+
+ return builder.toString();
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/AccountSASResourceType.java b/storage/client/src/main/java/com/azure/storage/blob/AccountSASResourceType.java
new file mode 100644
index 0000000000000..a7d6c477e22c8
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/AccountSASResourceType.java
@@ -0,0 +1,133 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import java.util.Locale;
+
+/**
+ * This is a helper class to construct a string representing the resources accessible by an AccountSAS. Setting a value
+ * to true means that any SAS which uses these permissions will grant access to that resource type. Once all the
+ * values are set, this should be serialized with toString and set as the resources field on an
+ * {@link AccountSASSignatureValues} object. It is possible to construct the resources string without this class, but
+ * the order of the resources is particular and this class guarantees correctness.
+ */
+final class AccountSASResourceType {
+
+ private boolean service;
+
+ private boolean container;
+
+ private boolean object;
+
+ /**
+ * Initializes an {@code AccountSASResourceType} object with all fields set to false.
+ */
+ public AccountSASResourceType() {
+ }
+
+ /**
+ * Creates an {@code AccountSASResourceType} from the specified resource types string. This method will throw an
+ * {@code IllegalArgumentException} if it encounters a character that does not correspond to a valid resource type.
+ *
+ * @param resourceTypesString
+ * A {@code String} which represents the {@code AccountSASResourceTypes}.
+ *
+ * @return A {@code AccountSASResourceType} generated from the given {@code String}.
+ */
+ public static AccountSASResourceType parse(String resourceTypesString) {
+ AccountSASResourceType resourceType = new AccountSASResourceType();
+
+ for (int i = 0; i < resourceTypesString.length(); i++) {
+ char c = resourceTypesString.charAt(i);
+ switch (c) {
+ case 's':
+ resourceType.service = true;
+ break;
+ case 'c':
+ resourceType.container = true;
+ break;
+ case 'o':
+ resourceType.object = true;
+ break;
+ default:
+ throw new IllegalArgumentException(
+ String.format(Locale.ROOT, SR.ENUM_COULD_NOT_BE_PARSED_INVALID_VALUE,
+ "Resource Types", resourceTypesString, c));
+ }
+ }
+ return resourceType;
+ }
+
+ /**
+ * Permission to access service level APIs granted.
+ */
+ public boolean service() {
+ return service;
+ }
+
+ /**
+ * Permission to access service level APIs granted.
+ */
+ public AccountSASResourceType withService(boolean service) {
+ this.service = service;
+ return this;
+ }
+
+ /**
+ * Permission to access container level APIs (Blob Containers, Tables, Queues, File Shares) granted.
+ */
+ public boolean container() {
+ return container;
+ }
+
+ /**
+ * Permission to access container level APIs (Blob Containers, Tables, Queues, File Shares) granted.
+ */
+ public AccountSASResourceType withContainer(boolean container) {
+ this.container = container;
+ return this;
+ }
+
+ /**
+ * Permission to access object level APIs (Blobs, Table Entities, Queue Messages, Files) granted.
+ */
+ public boolean object() {
+ return object;
+ }
+
+ /**
+ * Permission to access object level APIs (Blobs, Table Entities, Queue Messages, Files) granted.
+ */
+ public AccountSASResourceType withObject(boolean object) {
+ this.object = object;
+ return this;
+ }
+
+ /**
+ * Converts the given resource types to a {@code String}. Using this method will guarantee the resource types are in
+ * an order accepted by the service.
+ *
+ * @return A {@code String} which represents the {@code AccountSASResourceTypes}.
+ */
+ @Override
+ public String toString() {
+ // The order of the characters should be as specified here to ensure correctness:
+ // https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas
+ StringBuilder builder = new StringBuilder();
+
+ if (this.service) {
+ builder.append('s');
+ }
+
+ if (this.container) {
+ builder.append('c');
+ }
+
+ if (this.object) {
+ builder.append('o');
+ }
+
+ return builder.toString();
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/AccountSASService.java b/storage/client/src/main/java/com/azure/storage/blob/AccountSASService.java
new file mode 100644
index 0000000000000..1ba5564c542ce
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/AccountSASService.java
@@ -0,0 +1,154 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import java.util.Locale;
+
+/**
+ * This is a helper class to construct a string representing the services accessible by an AccountSAS. Setting a value
+ * to true means that any SAS which uses these permissions will grant access to that service. Once all the
+ * values are set, this should be serialized with toString and set as the services field on an
+ * {@link AccountSASSignatureValues} object. It is possible to construct the services string without this class, but
+ * the order of the services is particular and this class guarantees correctness.
+ */
+final class AccountSASService {
+
+ private boolean blob;
+
+ private boolean file;
+
+ private boolean queue;
+
+ private boolean table;
+
+ /**
+ * Initializes an {@code AccountSASService} object with all fields set to false.
+ */
+ public AccountSASService() {
+ }
+
+ /**
+ * Creates an {@code AccountSASService} from the specified services string. This method will throw an
+ * {@code IllegalArgumentException} if it encounters a character that does not correspond to a valid service.
+ *
+ * @param servicesString
+ * A {@code String} which represents the {@code SharedAccessAccountServices}.
+ *
+ * @return A {@code AccountSASService} generated from the given {@code String}.
+ */
+ public static AccountSASService parse(String servicesString) {
+ AccountSASService services = new AccountSASService();
+
+ for (int i = 0; i < servicesString.length(); i++) {
+ char c = servicesString.charAt(i);
+ switch (c) {
+ case 'b':
+ services.blob = true;
+ break;
+ case 'f':
+ services.file = true;
+ break;
+ case 'q':
+ services.queue = true;
+ break;
+ case 't':
+ services.table = true;
+ break;
+ default:
+ throw new IllegalArgumentException(
+ String.format(Locale.ROOT, SR.ENUM_COULD_NOT_BE_PARSED_INVALID_VALUE, "Services",
+ servicesString, c));
+ }
+ }
+ return services;
+ }
+
+ /**
+ * Permission to access blob resources granted.
+ */
+ public boolean blob() {
+ return blob;
+ }
+
+ /**
+ * Permission to access blob resources granted.
+ */
+ public AccountSASService withBlob(boolean blob) {
+ this.blob = blob;
+ return this;
+ }
+
+ /**
+ * Permission to access file resources granted.
+ */
+ public boolean file() {
+ return file;
+ }
+
+ /**
+ * Permission to access file resources granted.
+ */
+ public AccountSASService withFile(boolean file) {
+ this.file = file;
+ return this;
+ }
+
+ /**
+ * Permission to access queue resources granted.
+ */
+ public boolean queue() {
+ return queue;
+ }
+
+ /**
+ * Permission to access queue resources granted.
+ */
+ public AccountSASService withQueue(boolean queue) {
+ this.queue = queue;
+ return this;
+ }
+
+ /**
+ * Permission to access table resources granted.
+ */
+ public boolean table() {
+ return table;
+ }
+
+ /**
+ * Permission to access table resources granted.
+ */
+ public AccountSASService withTable(boolean table) {
+ this.table = table;
+ return this;
+ }
+
+ /**
+ * Converts the given services to a {@code String}. Using this method will guarantee the services are in an order
+ * accepted by the service.
+ *
+ * @return A {@code String} which represents the {@code AccountSASServices}.
+ */
+ @Override
+ public String toString() {
+ // The order of the characters should be as specified here to ensure correctness:
+ // https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas
+ StringBuilder value = new StringBuilder();
+
+ if (this.blob) {
+ value.append('b');
+ }
+ if (this.queue) {
+ value.append('q');
+ }
+ if (this.table) {
+ value.append('t');
+ }
+ if (this.file) {
+ value.append('f');
+ }
+
+ return value.toString();
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/AccountSASSignatureValues.java b/storage/client/src/main/java/com/azure/storage/blob/AccountSASSignatureValues.java
new file mode 100644
index 0000000000000..c14d218574a01
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/AccountSASSignatureValues.java
@@ -0,0 +1,226 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import java.security.InvalidKeyException;
+import java.time.OffsetDateTime;
+
+/**
+ * AccountSASSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage account. 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
+ * for more conceptual information on SAS:
+ *
+ *
+ * Please see
+ * here for further
+ * descriptions of the parameters, 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=account_sas "Sample code for AccountSASSignatureValues")] \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 AccountSASSignatureValues {
+
+ private String version = Constants.HeaderConstants.TARGET_STORAGE_VERSION;
+
+ private SASProtocol protocol;
+
+ private OffsetDateTime startTime;
+
+ private OffsetDateTime expiryTime;
+
+ private String permissions;
+
+ private IPRange ipRange;
+
+ private String services;
+
+ private String resourceTypes;
+
+ /**
+ * Initializes an {@code AccountSASSignatureValues} object with the version number set to the default and all
+ * other values empty.
+ */
+ public AccountSASSignatureValues() {
+ }
+
+ /**
+ * If null or empty, this defaults to the service version targeted by this version of the library.
+ */
+ public String version() {
+ return version;
+ }
+
+ /**
+ * If null or empty, this defaults to the service version targeted by this version of the library.
+ */
+ public AccountSASSignatureValues withVersion(String version) {
+ this.version = version;
+ return this;
+ }
+
+ /**
+ * {@link SASProtocol}
+ */
+ public SASProtocol protocol() {
+ return protocol;
+ }
+
+ /**
+ * {@link SASProtocol}
+ */
+ public AccountSASSignatureValues withProtocol(SASProtocol protocol) {
+ this.protocol = protocol;
+ return this;
+ }
+
+ /**
+ * When the SAS will take effect.
+ */
+ public OffsetDateTime startTime() {
+ return startTime;
+ }
+
+ /**
+ * When the SAS will take effect.
+ */
+ public AccountSASSignatureValues withStartTime(OffsetDateTime startTime) {
+ this.startTime = startTime;
+ return this;
+ }
+
+ /**
+ * The time after which the SAS will no longer work.
+ */
+ public OffsetDateTime expiryTime() {
+ return expiryTime;
+ }
+
+ /**
+ * The time after which the SAS will no longer work.
+ */
+ public AccountSASSignatureValues withExpiryTime(OffsetDateTime expiryTime) {
+ this.expiryTime = expiryTime;
+ return this;
+ }
+
+ /**
+ * Specifies which operations the SAS user may perform. Please refer to {@link AccountSASPermission} for help
+ * constructing the permissions string.
+ */
+ public String permissions() {
+ return permissions;
+ }
+
+ /**
+ * Specifies which operations the SAS user may perform. Please refer to {@link AccountSASPermission} for help
+ * constructing the permissions string.
+ */
+ public AccountSASSignatureValues withPermissions(String permissions) {
+ this.permissions = permissions;
+ return this;
+ }
+
+ /**
+ * {@link IPRange}
+ */
+ public IPRange ipRange() {
+ return ipRange;
+ }
+
+ /**
+ * {@link IPRange}
+ */
+ public AccountSASSignatureValues withIpRange(IPRange ipRange) {
+ this.ipRange = ipRange;
+ return this;
+ }
+
+ /**
+ * The values that indicate the services accessible with this SAS. Please refer to {@link AccountSASService} to
+ * construct this value.
+ */
+ public String services() {
+ return services;
+ }
+
+ /**
+ * The values that indicate the services accessible with this SAS. Please refer to {@link AccountSASService} to
+ * construct this value.
+ */
+ public AccountSASSignatureValues withServices(String services) {
+ this.services = services;
+ return this;
+ }
+
+ /**
+ * The values that indicate the resource types accessible with this SAS. Please refer
+ * to {@link AccountSASResourceType} to construct this value.
+ */
+ public String resourceTypes() {
+ return resourceTypes;
+ }
+
+ /**
+ * The values that indicate the resource types accessible with this SAS. Please refer
+ * to {@link AccountSASResourceType} to construct this value.
+ */
+ public AccountSASSignatureValues withResourceTypes(String resourceTypes) {
+ this.resourceTypes = resourceTypes;
+ return this;
+ }
+
+ /**
+ * Generates a {@link SASQueryParameters} object which contains all SAS query parameters needed to make an actual
+ * REST request.
+ *
+ * @param sharedKeyCredentials
+ * Credentials for the storage account and corresponding primary or secondary key.
+ *
+ * @return {@link SASQueryParameters}
+ */
+ public SASQueryParameters generateSASQueryParameters(SharedKeyCredentials sharedKeyCredentials) {
+ Utility.assertNotNull("SharedKeyCredentials", sharedKeyCredentials);
+ Utility.assertNotNull("services", this.services);
+ Utility.assertNotNull("resourceTypes", this.resourceTypes);
+ Utility.assertNotNull("expiryTime", this.expiryTime);
+ Utility.assertNotNull("permissions", this.permissions);
+ Utility.assertNotNull("version", this.version);
+
+ // Signature is generated on the un-url-encoded values.
+ final String stringToSign = stringToSign(sharedKeyCredentials);
+
+ String signature;
+ try {
+ signature = sharedKeyCredentials.computeHmac256(stringToSign);
+ } catch (InvalidKeyException e) {
+ throw new Error(e); // The key should have been validated by now. If it is no longer valid here, we fail.
+ }
+
+ return new SASQueryParameters(this.version, this.services, resourceTypes,
+ this.protocol, this.startTime, this.expiryTime, this.ipRange, null,
+ null, this.permissions, signature, null, null, null, null, null, null);
+ }
+
+ private String stringToSign(final SharedKeyCredentials sharedKeyCredentials) {
+ return String.join("\n",
+ sharedKeyCredentials.getAccountName(),
+ AccountSASPermission.parse(this.permissions).toString(), // guarantees ordering
+ this.services,
+ resourceTypes,
+ this.startTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.startTime),
+ Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.expiryTime),
+ this.ipRange == null ? (new IPRange()).toString() : this.ipRange.toString(),
+ this.protocol == null ? "" : this.protocol.toString(),
+ this.version,
+ Constants.EMPTY_STRING // Account SAS requires an additional newline character
+ );
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/AnonymousCredentials.java b/storage/client/src/main/java/com/azure/storage/blob/AnonymousCredentials.java
new file mode 100644
index 0000000000000..923b1c941dd9f
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/AnonymousCredentials.java
@@ -0,0 +1,31 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import com.azure.core.http.HttpPipelineCallContext;
+import com.azure.core.http.HttpPipelineNextPolicy;
+import com.azure.core.http.HttpResponse;
+import reactor.core.publisher.Mono;
+
+/**
+ * Anonymous credentials are to be used with with HTTP(S) requests that read blobs from public containers or requests
+ * that use a Shared Access Signature (SAS). This is because Anonymous credentials will not set an Authorization header.
+ * Pass an instance of this class as the credentials parameter when creating a new pipeline (typically with
+ * {@link StorageURL}).
+ */
+public final class AnonymousCredentials implements ICredentials {
+
+ /**
+ * Returns an empty instance of {@code AnonymousCredentials}.
+ */
+ public AnonymousCredentials() {
+ }
+
+
+
+ @Override
+ public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) {
+ return next.process();
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/AppendBlobAccessConditions.java b/storage/client/src/main/java/com/azure/storage/blob/AppendBlobAccessConditions.java
new file mode 100644
index 0000000000000..2d137418118e6
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/AppendBlobAccessConditions.java
@@ -0,0 +1,88 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import com.azure.storage.blob.models.AppendPositionAccessConditions;
+import com.azure.storage.blob.models.LeaseAccessConditions;
+import com.azure.storage.blob.models.ModifiedAccessConditions;
+
+/**
+ * This class contains values that restrict the successful completion of AppendBlock operations to certain conditions.
+ * Any field may be set to null if no access conditions are desired.
+ *
+ * Please refer to the request header section
+ * here for more conceptual
+ * information.
+ */
+public final class AppendBlobAccessConditions {
+
+ private AppendPositionAccessConditions appendPositionAccessConditions;
+
+ private ModifiedAccessConditions modifiedAccessConditions;
+
+ private LeaseAccessConditions leaseAccessConditions;
+
+ /**
+ * Creates an instance which has fields set to non-null, empty values.
+ */
+ public AppendBlobAccessConditions() {
+ appendPositionAccessConditions = new AppendPositionAccessConditions();
+ modifiedAccessConditions = new ModifiedAccessConditions();
+ leaseAccessConditions = new LeaseAccessConditions();
+ }
+
+ /**
+ * Access conditions used for appending data only if the operation meets the provided conditions related to the
+ * size of the append blob.
+ */
+ public AppendPositionAccessConditions appendPositionAccessConditions() {
+ return appendPositionAccessConditions;
+ }
+
+ /**
+ * Access conditions used for appending data only if the operation meets the provided conditions related to the
+ * size of the append blob.
+ */
+ public AppendBlobAccessConditions withAppendPositionAccessConditions(
+ AppendPositionAccessConditions appendPositionAccessConditions) {
+ this.appendPositionAccessConditions = appendPositionAccessConditions;
+ return this;
+ }
+
+ /**
+ * 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.
+ */
+ public ModifiedAccessConditions modifiedAccessConditions() {
+ return 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.
+ */
+ public AppendBlobAccessConditions withModifiedAccessConditions(ModifiedAccessConditions modifiedAccessConditions) {
+ this.modifiedAccessConditions = modifiedAccessConditions;
+ return this;
+ }
+
+ /**
+ * By setting lease access conditions, requests will fail if the provided lease does not match the active lease on
+ * the blob.
+ */
+ public LeaseAccessConditions leaseAccessConditions() {
+ return leaseAccessConditions;
+ }
+
+ /**
+ * By setting lease access conditions, requests will fail if the provided lease does not match the active lease on
+ * the blob.
+ */
+ public AppendBlobAccessConditions withLeaseAccessConditions(LeaseAccessConditions leaseAccessConditions) {
+ this.leaseAccessConditions = leaseAccessConditions;
+ return this;
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/AppendBlobAsyncClient.java b/storage/client/src/main/java/com/azure/storage/blob/AppendBlobAsyncClient.java
new file mode 100644
index 0000000000000..73607c2ed3f26
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/AppendBlobAsyncClient.java
@@ -0,0 +1,216 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import com.azure.core.http.rest.ResponseBase;
+import com.azure.core.util.Context;
+import com.azure.storage.blob.implementation.AzureBlobStorageImpl;
+import com.azure.storage.blob.models.AppendBlobAppendBlockFromUrlHeaders;
+import com.azure.storage.blob.models.AppendBlobAppendBlockHeaders;
+import com.azure.storage.blob.models.AppendBlobCreateHeaders;
+import com.azure.storage.blob.models.BlobHTTPHeaders;
+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;
+
+
+/**
+ * Client to an append blob. It may only be instantiated through a {@link AppendBlobClientBuilder}, via
+ * the method {@link BlobAsyncClient#asAppendBlobAsyncClient()}, or via the method
+ * {@link ContainerAsyncClient#getAppendBlobAsyncClient(String)}. This class does not hold
+ * any state about a particular blob, but is instead a convenient way of sending appropriate
+ * requests to the resource on the service.
+ *
+ *
+ * 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.
+ *
+ *
+ * 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 AppendBlobAsyncClient extends BlobAsyncClient {
+ AppendBlobAsyncRawClient appendBlobAsyncRawClient;
+
+ /**
+ * 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;
+
+ /**
+ * Package-private constructor for use by {@link AppendBlobClientBuilder}.
+ * @param azureBlobStorage the API client for blob storage API
+ */
+ AppendBlobAsyncClient(AzureBlobStorageImpl azureBlobStorage) {
+ super(azureBlobStorage);
+ appendBlobAsyncRawClient = new AppendBlobAsyncRawClient(azureBlobStorage);
+ }
+
+ /**
+ * Static method for getting a new builder for this class.
+ *
+ * @return
+ * A new {@link AppendBlobClientBuilder} instance.
+ */
+ public static AppendBlobClientBuilder appendBlobClientBuilder() {
+ return new AppendBlobClientBuilder();
+ }
+
+ /**
+ * Creates a 0-length append blob. Call appendBlock to append data to an append blob.
+ *
+ * @return
+ * A reactive response containing the information of the created appended blob.
+ */
+ public Mono create() {
+ return this.create(null, null, null, null);
+ }
+
+ /**
+ * Creates a 0-length append blob. Call appendBlock to append data to an append blob.
+ *
+ * @param headers
+ * {@link BlobHTTPHeaders}
+ * @param metadata
+ * {@link Metadata}
+ * @param accessConditions
+ * {@link BlobAccessConditions}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response containing the information of the created appended blob.
+ */
+ public Mono create(BlobHTTPHeaders headers, Metadata metadata,
+ BlobAccessConditions accessConditions, Context context) {
+ return appendBlobAsyncRawClient
+ .create(headers, metadata, accessConditions, context)
+ .map(ResponseBase::deserializedHeaders);
+ }
+
+ /**
+ * Commits a new block of data to the end of the existing append blob.
+ *
+ * Note that the data passed must be replayable if retries are enabled (the default). In other words, the
+ * {@code Flux} must produce the same data each time it is subscribed to.
+ *
+ * @param data
+ * The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled
+ * (the default). In other words, the Flux must produce the same data each time it is subscribed to.
+ * @param length
+ * The exact length of the data. It is important that this value match precisely the length of the data
+ * emitted by the {@code Flux}.
+ *
+ * @return
+ * A reactive response containing the information of the append blob operation.
+ */
+ public Mono appendBlock(Flux data, long length) {
+ return this.appendBlock(data, length, null, null);
+ }
+
+ /**
+ * Commits a new block of data to the end of the existing append blob.
+ *
+ * Note that the data passed must be replayable if retries are enabled (the default). In other words, the
+ * {@code Flux} must produce the same data each time it is subscribed to.
+ *
+ * @param data
+ * The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled
+ * (the default). In other words, the Flux must produce the same data each time it is subscribed to.
+ * @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}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response containing the information of the append blob operation.
+ */
+ public Mono appendBlock(Flux data, long length,
+ AppendBlobAccessConditions appendBlobAccessConditions, Context context) {
+ return appendBlobAsyncRawClient
+ .appendBlock(data, length, appendBlobAccessConditions, context)
+ .map(ResponseBase::deserializedHeaders);
+ }
+
+ /**
+ * Commits a new block of data from another blob to the end of this append blob.
+ *
+ * @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
+ * A reactive response containing the information of the append blob operation.
+ */
+ public Mono appendBlockFromUrl(URL sourceURL, BlobRange sourceRange) {
+ return this.appendBlockFromUrl(sourceURL, sourceRange, null, null,
+ null, null);
+ }
+
+ /**
+ * Commits a new block of data from another blob to the end of this append blob.
+ *
+ * @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}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response containing the information of the append blob operation.
+ */
+ public Mono appendBlockFromUrl(URL sourceURL, BlobRange sourceRange,
+ byte[] sourceContentMD5, AppendBlobAccessConditions destAccessConditions,
+ SourceModifiedAccessConditions sourceAccessConditions, Context context) {
+ return appendBlobAsyncRawClient
+ .appendBlockFromUrl(sourceURL, sourceRange, sourceContentMD5, destAccessConditions, sourceAccessConditions, context)
+ .map(ResponseBase::deserializedHeaders);
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/AppendBlobAsyncRawClient.java b/storage/client/src/main/java/com/azure/storage/blob/AppendBlobAsyncRawClient.java
new file mode 100644
index 0000000000000..17fc536b9873f
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/AppendBlobAsyncRawClient.java
@@ -0,0 +1,207 @@
+// 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.AzureBlobStorageBuilder;
+import com.azure.storage.blob.implementation.AzureBlobStorageImpl;
+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.BlobHTTPHeaders;
+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);
+ }
+
+ /**
+ * 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, 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}
+ * @param context {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ * @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, Context context) {
+ metadata = metadata == null ? new Metadata() : metadata;
+ accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions;
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.appendBlobs().createWithRestResponseAsync(null,
+ null, 0, null, metadata, null, null,
+ null, null, headers, accessConditions.leaseAccessConditions(),
+ accessConditions.modifiedAccessConditions(), context));
+ }
+
+ /**
+ * 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, 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}
+ * @param context {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ * @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, Context context) {
+ appendBlobAccessConditions = appendBlobAccessConditions == null ? new AppendBlobAccessConditions()
+ : appendBlobAccessConditions;
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.appendBlobs().appendBlockWithRestResponseAsync(
+ null, null, data, length, null, null,
+ null, null, null, null,
+ appendBlobAccessConditions.leaseAccessConditions(),
+ appendBlobAccessConditions.appendPositionAccessConditions(),
+ appendBlobAccessConditions.modifiedAccessConditions(), context));
+ }
+
+ /**
+ * 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, 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}
+ * @param context {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ * @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, Context context) {
+
+ sourceRange = sourceRange == null ? new BlobRange(0) : sourceRange;
+ destAccessConditions = destAccessConditions == null
+ ? new AppendBlobAccessConditions() : destAccessConditions;
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(
+ this.azureBlobStorage.appendBlobs().appendBlockFromUrlWithRestResponseAsync(null, null,
+ sourceURL, 0, sourceRange.toString(), sourceContentMD5, null, null,
+ destAccessConditions.leaseAccessConditions(),
+ destAccessConditions.appendPositionAccessConditions(),
+ destAccessConditions.modifiedAccessConditions(), sourceAccessConditions, context));
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/AppendBlobClient.java b/storage/client/src/main/java/com/azure/storage/blob/AppendBlobClient.java
new file mode 100644
index 0000000000000..97bc08151b3b1
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/AppendBlobClient.java
@@ -0,0 +1,218 @@
+// 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.AppendBlobAppendBlockFromUrlHeaders;
+import com.azure.storage.blob.models.AppendBlobAppendBlockHeaders;
+import com.azure.storage.blob.models.AppendBlobCreateHeaders;
+import com.azure.storage.blob.models.BlobHTTPHeaders;
+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.time.Duration;
+
+
+/**
+ * Client to an append blob. It may only be instantiated through a {@link AppendBlobClientBuilder}, via
+ * the method {@link BlobClient#asAppendBlobClient()}, or via the method
+ * {@link ContainerClient#getAppendBlobClient(String)}. This class does not hold
+ * any state about a particular blob, but is instead a convenient way of sending appropriate
+ * requests to the resource on the service.
+ *
+ *
+ * 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.
+ */
+public final class AppendBlobClient extends BlobClient {
+
+ 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;
+
+ /**
+ * Indicates the maximum number of blocks allowed in an append blob.
+ */
+ public static final int MAX_BLOCKS = 50000;
+
+ /**
+ * Package-private constructor for use by {@link AppendBlobClientBuilder}.
+ * @param azureBlobStorage the API client for blob storage API
+ */
+ AppendBlobClient(AzureBlobStorageImpl azureBlobStorage) {
+ super(azureBlobStorage);
+ this.appendBlobAsyncClient = new AppendBlobAsyncClient(azureBlobStorage);
+ }
+
+ /**
+ * Static method for getting a new builder for this class.
+ *
+ * @return
+ * A new {@link AppendBlobClientBuilder} instance.
+ */
+ public static AppendBlobClientBuilder appendBlobClientBuilder() {
+ return new AppendBlobClientBuilder();
+ }
+
+ /**
+ * Creates a 0-length append blob. Call appendBlock to append data to an append blob.
+ *
+ * @return
+ * The information of the created appended blob.
+ */
+ public AppendBlobCreateHeaders create() {
+ return this.create(null, null, null, null, null);
+ }
+
+ /**
+ * Creates a 0-length append blob. Call appendBlock to append data to an append blob.
+ *
+ * @param headers
+ * {@link BlobHTTPHeaders}
+ * @param metadata
+ * {@link Metadata}
+ * @param accessConditions
+ * {@link BlobAccessConditions}
+ * @param timeout
+ * An optional timeout value beyond which a {@link RuntimeException} will be raised.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * The information of the created appended blob.
+ */
+ public AppendBlobCreateHeaders create(BlobHTTPHeaders headers, Metadata metadata,
+ BlobAccessConditions accessConditions, Duration timeout, Context context) {
+ Mono response = appendBlobAsyncClient.create(headers, metadata, accessConditions, context);
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * Commits a new block of data to the end of the existing append blob.
+ *
+ * Note that the data passed must be replayable if retries are enabled (the default). In other words, the
+ * {@code Flux} must produce the same data each time it is subscribed to.
+ *
+ * @param data
+ * The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled
+ * (the default). In other words, the Flux must produce the same data each time it is subscribed to.
+ * @param length
+ * The exact length of the data. It is important that this value match precisely the length of the data
+ * emitted by the {@code Flux}.
+ *
+ * @return
+ * The information of the append blob operation.
+ */
+ public AppendBlobAppendBlockHeaders appendBlock(Flux data, long length) {
+ return this.appendBlock(data, length, null, null, null);
+ }
+
+ /**
+ * Commits a new block of data to the end of the existing append blob.
+ *
+ * Note that the data passed must be replayable if retries are enabled (the default). In other words, the
+ * {@code Flux} must produce the same data each time it is subscribed to.
+ *
+ * @param data
+ * The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled
+ * (the default). In other words, the Flux must produce the same data each time it is subscribed to.
+ * @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}
+ * @param timeout
+ * An optional timeout value beyond which a {@link RuntimeException} will be raised.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * The information of the append blob operation.
+ */
+ public AppendBlobAppendBlockHeaders appendBlock(Flux data, long length,
+ AppendBlobAccessConditions appendBlobAccessConditions, Duration timeout, Context context) {
+ Mono response = appendBlobAsyncClient.appendBlock(data, length, appendBlobAccessConditions, context);
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * Commits a new block of data from another blob to the end of this append blob.
+ *
+ * @param sourceURL
+ * The url to the blob that will be the source of the copy. A source blob in the same storage account can
+ * be authenticated via Shared Key. However, if the source is a blob in another account, the source blob
+ * must either be public or must be authenticated via a shared access signature. If the source blob is
+ * public, no authentication is required to perform the operation.
+ * @param sourceRange
+ * The source {@link BlobRange} to copy.
+ *
+ * @return
+ * The information of the append blob operation.
+ */
+ public AppendBlobAppendBlockFromUrlHeaders appendBlockFromUrl(URL sourceURL, BlobRange sourceRange) {
+ return this.appendBlockFromUrl(sourceURL, sourceRange, null, null,
+ null, null, null);
+ }
+
+ /**
+ * Commits a new block of data from another blob to the end of this append blob.
+ *
+ * @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}
+ * @param timeout
+ * An optional timeout value beyond which a {@link RuntimeException} will be raised.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * The information of the append blob operation.
+ */
+ public AppendBlobAppendBlockFromUrlHeaders appendBlockFromUrl(URL sourceURL, BlobRange sourceRange,
+ byte[] sourceContentMD5, AppendBlobAccessConditions destAccessConditions,
+ SourceModifiedAccessConditions sourceAccessConditions, Duration timeout, Context context) {
+ Mono response = appendBlobAsyncClient.appendBlockFromUrl(sourceURL, sourceRange, sourceContentMD5, destAccessConditions, sourceAccessConditions, context);
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/AppendBlobClientBuilder.java b/storage/client/src/main/java/com/azure/storage/blob/AppendBlobClientBuilder.java
new file mode 100644
index 0000000000000..9e511263f96c0
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/AppendBlobClientBuilder.java
@@ -0,0 +1,220 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import com.azure.core.configuration.Configuration;
+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.util.ImplUtils;
+import com.azure.storage.blob.implementation.AzureBlobStorageBuilder;
+import com.azure.storage.blob.implementation.AzureBlobStorageImpl;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Fluent AppendBlobClientBuilder for instantiating a {@link AppendBlobClient} or {@link AppendBlobAsyncClient}.
+ *
+ *
+ * An instance of this builder may only be created from static method {@link AppendBlobClient#appendBlobClientBuilder()}.
+ * The following information must be provided on this builder:
+ *
+ *
+ * - the endpoint through {@code .endpoint()}, including the container name and blob name, in the format of {@code https://{accountName}.blob.core.windows.net/{containerName}/{blobName}}.
+ *
- the credential through {@code .credentials()} or {@code .connectionString()} if the container is not publicly accessible.
+ *
+ *
+ *
+ * Once all the configurations are set on this builder, call {@code .buildClient()} to create a
+ * {@link AppendBlobClient} or {@code .buildAsyncClient()} to create a {@link AppendBlobAsyncClient}.
+ */
+public final class AppendBlobClientBuilder {
+ private static final String ACCOUNT_NAME = "AccountName".toLowerCase();
+ private static final String ACCOUNT_KEY = "AccountKey".toLowerCase();
+
+ private final List policies;
+
+ private URL endpoint;
+ private ICredentials credentials = new AnonymousCredentials();
+ private HttpClient httpClient;
+ private HttpLogDetailLevel logLevel;
+ private RetryPolicy retryPolicy;
+ private Configuration configuration;
+
+ public AppendBlobClientBuilder() {
+ retryPolicy = new RetryPolicy();
+ logLevel = HttpLogDetailLevel.NONE;
+ policies = new ArrayList<>();
+ }
+
+ /**
+ * Constructs an instance of AppendBlobAsyncClient based on the configurations stored in the appendBlobClientBuilder.
+ * @return a new client instance
+ */
+ private AzureBlobStorageImpl buildImpl() {
+ Objects.requireNonNull(endpoint);
+
+ // Closest to API goes first, closest to wire goes last.
+ final List policies = new ArrayList<>();
+
+ policies.add(new UserAgentPolicy(BlobConfiguration.NAME, BlobConfiguration.VERSION));
+ policies.add(new RequestIdPolicy());
+ policies.add(new AddDatePolicy());
+ policies.add(credentials); // This needs to be a different credential type.
+
+ policies.add(retryPolicy);
+
+ policies.addAll(this.policies);
+ policies.add(new HttpLoggingPolicy(logLevel));
+
+ HttpPipeline pipeline = HttpPipeline.builder()
+ .policies(policies.toArray(new HttpPipelinePolicy[0]))
+ .httpClient(httpClient)
+ .build();
+
+ return new AzureBlobStorageBuilder()
+ .url(endpoint.toString())
+ .pipeline(pipeline)
+ .build();
+ }
+
+ /**
+ * @return a {@link AppendBlobClient} created from the configurations in this builder.
+ */
+ public AppendBlobClient buildClient() {
+ return new AppendBlobClient(buildImpl());
+ }
+
+ /**
+ * @return a {@link AppendBlobAsyncClient} created from the configurations in this builder.
+ */
+ public AppendBlobAsyncClient buildAsyncClient() {
+ return new AppendBlobAsyncClient(buildImpl());
+ }
+
+ /**
+ * Sets the service endpoint, additionally parses it for information (SAS token, container name)
+ * @param endpoint URL of the service
+ * @return the updated AppendBlobClientBuilder object
+ */
+ public AppendBlobClientBuilder endpoint(String endpoint) {
+ Objects.requireNonNull(endpoint);
+ try {
+ this.endpoint = new URL(endpoint);
+ } catch (MalformedURLException ex) {
+ throw new IllegalArgumentException("The Azure Storage Queue endpoint url is malformed.");
+ }
+
+ return this;
+ }
+
+ /**
+ * Sets the credentials used to authorize requests sent to the service
+ * @param credentials authorization credentials
+ * @return the updated AppendBlobClientBuilder object
+ */
+ public AppendBlobClientBuilder credentials(SharedKeyCredentials credentials) {
+ this.credentials = credentials;
+ return this;
+ }
+
+ /**
+ * Sets the credentials used to authorize requests sent to the service
+ * @param credentials authorization credentials
+ * @return the updated AppendBlobClientBuilder object
+ */
+ public AppendBlobClientBuilder credentials(TokenCredentials credentials) {
+ this.credentials = credentials;
+ return this;
+ }
+
+ /**
+ * Clears the credentials used to authorize requests sent to the service
+ * @return the updated AppendBlobClientBuilder object
+ */
+ public AppendBlobClientBuilder anonymousCredentials() {
+ this.credentials = new AnonymousCredentials();
+ return this;
+ }
+
+ /**
+ * Sets the connection string for the service, parses it for authentication information (account name, account key)
+ * @param connectionString connection string from access keys section
+ * @return the updated AppendBlobClientBuilder object
+ */
+ public AppendBlobClientBuilder connectionString(String connectionString) {
+ Objects.requireNonNull(connectionString);
+
+ Map connectionKVPs = new HashMap<>();
+ for (String s : connectionString.split(";")) {
+ String[] kvp = s.split("=", 2);
+ connectionKVPs.put(kvp[0].toLowerCase(), kvp[1]);
+ }
+
+ String accountName = connectionKVPs.get(ACCOUNT_NAME);
+ String accountKey = connectionKVPs.get(ACCOUNT_KEY);
+
+ if (ImplUtils.isNullOrEmpty(accountName) || ImplUtils.isNullOrEmpty(accountKey)) {
+ throw new IllegalArgumentException("Connection string must contain 'AccountName' and 'AccountKey'.");
+ }
+
+ // Use accountName and accountKey to get the SAS token using the credential class.
+ credentials = new SharedKeyCredentials(accountName, accountKey);
+
+ return this;
+ }
+
+ /**
+ * Sets the http client used to send service requests
+ * @param httpClient http client to send requests
+ * @return the updated AppendBlobClientBuilder object
+ */
+ public AppendBlobClientBuilder httpClient(HttpClient httpClient) {
+ this.httpClient = httpClient;
+ return this;
+ }
+
+ /**
+ * Adds a pipeline policy to apply on each request sent
+ * @param pipelinePolicy a pipeline policy
+ * @return the updated AppendBlobClientBuilder object
+ */
+ public AppendBlobClientBuilder addPolicy(HttpPipelinePolicy pipelinePolicy) {
+ this.policies.add(pipelinePolicy);
+ return this;
+ }
+
+ /**
+ * Sets the logging level for service requests
+ * @param logLevel logging level
+ * @return the updated AppendBlobClientBuilder object
+ */
+ public AppendBlobClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) {
+ this.logLevel = logLevel;
+ return this;
+ }
+
+ /**
+ * Sets the configuration object used to retrieve environment configuration values used to buildClient the client with
+ * when they are not set in the appendBlobClientBuilder, defaults to Configuration.NONE
+ * @param configuration configuration store
+ * @return the updated AppendBlobClientBuilder object
+ */
+ public AppendBlobClientBuilder configuration(Configuration configuration) {
+ this.configuration = configuration;
+ return this;
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/AppendBlobRawClient.java b/storage/client/src/main/java/com/azure/storage/blob/AppendBlobRawClient.java
new file mode 100644
index 0000000000000..22abc039755b6
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/AppendBlobRawClient.java
@@ -0,0 +1,220 @@
+// 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.core.util.Context;
+import com.azure.storage.blob.implementation.AzureBlobStorageBuilder;
+import com.azure.storage.blob.implementation.AzureBlobStorageImpl;
+import com.azure.storage.blob.models.*;
+import io.netty.buffer.ByteBuf;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.time.Duration;
+
+
+/**
+ * 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 AppendBlobRawClient extends BlobRawClient {
+
+ AppendBlobAsyncRawClient appendBlobAsyncRawClient;
+
+ /**
+ * 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.
+ * {@link StorageURL#createPipeline(ICredentials, PipelineOptions)} for more information.
+ */
+ AppendBlobRawClient(AzureBlobStorageImpl azureBlobStorage) {
+ super(azureBlobStorage);
+ this.appendBlobAsyncRawClient = new AppendBlobAsyncRawClient(azureBlobStorage);
+ }
+
+
+ /**
+ * 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 AppendBlobsCreateResponse create() {
+ return this.create(null, null, 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}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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 AppendBlobsCreateResponse create(BlobHTTPHeaders headers, Metadata metadata,
+ BlobAccessConditions accessConditions, Duration timeout, Context context) {
+ Mono response = appendBlobAsyncRawClient.create(headers, metadata, accessConditions, context);
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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 AppendBlobsAppendBlockResponse appendBlock(Flux data, long length) {
+ return this.appendBlock(data, length, null, null, 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}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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 AppendBlobsAppendBlockResponse appendBlock(Flux data, long length,
+ AppendBlobAccessConditions appendBlobAccessConditions, Duration timeout, Context context) {
+ Mono response = appendBlobAsyncRawClient.appendBlock(data, length, appendBlobAccessConditions, context);
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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 AppendBlobsAppendBlockFromUrlResponse appendBlockFromUrl(URL sourceURL, BlobRange sourceRange) {
+ return this.appendBlockFromUrl(sourceURL, sourceRange, null, null,
+ 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}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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 AppendBlobsAppendBlockFromUrlResponse appendBlockFromUrl(URL sourceURL, BlobRange sourceRange,
+ byte[] sourceContentMD5, AppendBlobAccessConditions destAccessConditions,
+ SourceModifiedAccessConditions sourceAccessConditions, Duration timeout, Context context) {
+ Mono response = appendBlobAsyncRawClient.appendBlockFromUrl(sourceURL, sourceRange, sourceContentMD5, destAccessConditions, sourceAccessConditions, context);
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlobAccessConditions.java b/storage/client/src/main/java/com/azure/storage/blob/BlobAccessConditions.java
new file mode 100644
index 0000000000000..ec115a7513fc3
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlobAccessConditions.java
@@ -0,0 +1,64 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import com.azure.storage.blob.models.LeaseAccessConditions;
+import com.azure.storage.blob.models.ModifiedAccessConditions;
+
+/**
+ * This class contains values which will restrict the successful operation of a variety of requests to the conditions
+ * present. These conditions are entirely optional. The entire object or any of its properties may be set to null when
+ * passed to a method to indicate that those conditions are not desired. Please refer to the type of each field for more
+ * information on those particular access conditions.
+ */
+public final class BlobAccessConditions {
+
+ private ModifiedAccessConditions modifiedAccessConditions;
+
+ private LeaseAccessConditions leaseAccessConditions;
+
+ /**
+ * Creates an instance which has fields set to non-null, empty values.
+ */
+ public BlobAccessConditions() {
+ modifiedAccessConditions = new ModifiedAccessConditions();
+ leaseAccessConditions = new LeaseAccessConditions();
+ }
+
+ /**
+ * 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.
+ */
+ public ModifiedAccessConditions modifiedAccessConditions() {
+ return 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.
+ */
+ public BlobAccessConditions withModifiedAccessConditions(ModifiedAccessConditions modifiedAccessConditions) {
+ this.modifiedAccessConditions = modifiedAccessConditions;
+ return this;
+ }
+
+ /**
+ * By setting lease access conditions, requests will fail if the provided lease does not match the active lease on
+ * the blob.
+ */
+ public LeaseAccessConditions leaseAccessConditions() {
+ return leaseAccessConditions;
+ }
+
+ /**
+ * By setting lease access conditions, requests will fail if the provided lease does not match the active lease on
+ * the blob.
+ */
+ public BlobAccessConditions withLeaseAccessConditions(LeaseAccessConditions leaseAccessConditions) {
+ this.leaseAccessConditions = leaseAccessConditions;
+ return this;
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlobAsyncClient.java b/storage/client/src/main/java/com/azure/storage/blob/BlobAsyncClient.java
new file mode 100644
index 0000000000000..964caa7d90ad4
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlobAsyncClient.java
@@ -0,0 +1,818 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import com.azure.core.http.rest.ResponseBase;
+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.BlobHTTPHeaders;
+import com.azure.storage.blob.models.BlobStartCopyFromURLHeaders;
+import com.azure.storage.blob.models.DeleteSnapshotsOptionType;
+import com.azure.storage.blob.models.LeaseAccessConditions;
+import com.azure.storage.blob.models.ModifiedAccessConditions;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.netty.ByteBufFlux;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UncheckedIOException;
+import java.net.URL;
+import java.nio.ByteBuffer;
+
+/**
+ * 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()}.
+ *
+ *
+ * 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.
+ *
+ *
+ * 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 {
+
+ protected BlobAsyncRawClient blobAsyncRawClient;
+
+ /**
+ * Package-private constructor for use by {@link BlobClientBuilder}.
+ * @param azureBlobStorage the API client for blob storage API
+ */
+ BlobAsyncClient(AzureBlobStorageImpl azureBlobStorage) {
+ blobAsyncRawClient = new BlobAsyncRawClient(azureBlobStorage);
+ }
+
+ /**
+ * Static method for getting a new builder for this class.
+ *
+ * @return
+ * A new {@link BlobClientBuilder} instance.
+ */
+ public static BlobClientBuilder blobClientBuilder() {
+ return new BlobClientBuilder();
+ }
+
+ /**
+ * Creates a new {@link BlockBlobAsyncClient} to this resource, maintaining configurations. Only do this for blobs
+ * that are known to be block blobs.
+ *
+ * @return
+ * A {@link BlockBlobAsyncClient} to this resource.
+ */
+ public BlockBlobAsyncClient asBlockBlobAsyncClient() {
+ return new BlockBlobAsyncClient(this.blobAsyncRawClient.azureBlobStorage);
+ }
+
+ /**
+ * Creates a new {@link AppendBlobAsyncClient} to this resource, maintaining configurations. Only do this for blobs
+ * that are known to be append blobs.
+ *
+ * @return
+ * A {@link AppendBlobAsyncClient} to this resource.
+ */
+ public AppendBlobAsyncClient asAppendBlobAsyncClient() {
+ return new AppendBlobAsyncClient(this.blobAsyncRawClient.azureBlobStorage);
+ }
+
+ /**
+ * Creates a new {@link PageBlobAsyncClient} to this resource, maintaining configurations. Only do this for blobs
+ * that are known to be page blobs.
+ *
+ * @return
+ * A {@link PageBlobAsyncClient} to this resource.
+ */
+ public PageBlobAsyncClient asPageBlobAsyncClient() {
+ return new PageBlobAsyncClient(this.blobAsyncRawClient.azureBlobStorage);
+ }
+
+
+ /**
+ * 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.
+ */
+ public Mono startCopyFromURL(URL sourceURL) {
+ return this.startCopyFromURL(sourceURL, null, 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response containing the copy ID for the long running operation.
+ */
+ public Mono startCopyFromURL(URL sourceURL, Metadata metadata,
+ ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions,
+ Context context) {
+ return blobAsyncRawClient
+ .startCopyFromURL(sourceURL, metadata, sourceModifiedAccessConditions, destAccessConditions, context)
+ .map(response -> response.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.
+ */
+ public Mono abortCopyFromURL(String copyId) {
+ return this.abortCopyFromURL(copyId, null, null);
+ }
+
+ /**
+ * 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 context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response signalling completion.
+ */
+ public Mono abortCopyFromURL(String copyId, LeaseAccessConditions leaseAccessConditions, Context context) {
+ return blobAsyncRawClient
+ .abortCopyFromURL(copyId, leaseAccessConditions, context)
+ .then();
+ }
+
+ /**
+ * 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.
+ */
+ public Mono copyFromURL(URL copySource) {
+ return this.copyFromURL(copySource, null, null, null, null);
+ }
+
+ /**
+ * 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 context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response containing the copy ID for the long running operation.
+ */
+ public Mono copyFromURL(URL copySource, Metadata metadata,
+ ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions,
+ Context context) {
+ return blobAsyncRawClient
+ .syncCopyFromURL(copySource, metadata, sourceModifiedAccessConditions, destAccessConditions, context)
+ .map(response -> response.deserializedHeaders().copyId());
+ }
+
+ /**
+ * 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.
+ */
+ public Flux download() {
+ return this.download(null, null, false, null, null);
+ }
+
+ /**
+ * 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 context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response containing the blob data.
+ */
+ public Flux download(BlobRange range, BlobAccessConditions accessConditions,
+ boolean rangeGetContentMD5, ReliableDownloadOptions options, Context context) {
+ return blobAsyncRawClient
+ .download(range, accessConditions, rangeGetContentMD5, context)
+ .flatMapMany(response -> ByteBufFlux.fromInbound(response.body(options)).asByteBuffer());
+ }
+
+ /**
+ * 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}.
+ *
+ * @param filePath
+ * A non-null {@link OutputStream} instance where the downloaded data will be written.
+ */
+ public Mono downloadToFile(String filePath) {
+ return this.downloadToFile(filePath, null, null, false, null, null);
+ }
+
+ /**
+ * 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}.
+ *
+ * @param filePath
+ * A non-null {@link OutputStream} instance where the downloaded data will be written.
+ * @param range
+ * {@link BlobRange}
+ * @param accessConditions
+ * {@link BlobAccessConditions}
+ * @param rangeGetContentMD5
+ * Whether the contentMD5 for the specified blob range should be returned.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ */
+ public Mono downloadToFile(String filePath, BlobRange range, BlobAccessConditions accessConditions,
+ boolean rangeGetContentMD5, ReliableDownloadOptions options, Context context) {
+ //todo make this method smart
+ return Mono.using(
+ () -> new FileOutputStream(new File(filePath)),
+ fstream -> this.download(range, accessConditions, rangeGetContentMD5, options, context)
+ .doOnNext(byteBuffer -> {
+ try {
+ fstream.write(byteBuffer.array());
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ })
+ .then(),
+ fstream -> {
+ try {
+ fstream.close();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+ );
+ }
+
+ /**
+ * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots.
+ *
+ * @return
+ * A reactive response signalling completion.
+ */
+ public Mono delete() {
+ return this.delete(null, null, null);
+ }
+
+ /**
+ * 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 context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response signalling completion.
+ */
+ public Mono delete(DeleteSnapshotsOptionType deleteBlobSnapshotOptions,
+ BlobAccessConditions accessConditions, Context context) {
+ return blobAsyncRawClient
+ .delete(deleteBlobSnapshotOptions, accessConditions, context)
+ .then();
+ }
+
+ /**
+ * Returns the blob's metadata and properties.
+ *
+ * @return
+ * A reactive response containing the blob properties and metadata.
+ */
+ public Mono getProperties() {
+ return this.getProperties(null, null);
+ }
+
+ /**
+ * Returns the blob's metadata and properties.
+ *
+ * @param accessConditions
+ * {@link BlobAccessConditions}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response containing the blob properties and metadata.
+ */
+ public Mono getProperties(BlobAccessConditions accessConditions, Context context) {
+ return blobAsyncRawClient
+ .getProperties(accessConditions, context)
+ .map(ResponseBase::deserializedHeaders)
+ .map(BlobProperties::new);
+ }
+
+ /**
+ * 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.
+ */
+ public Mono setHTTPHeaders(BlobHTTPHeaders headers) {
+ return this.setHTTPHeaders(headers, null, 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
+ * Azure Docs.
+ *
+ * @param headers
+ * {@link BlobHTTPHeaders}
+ * @param accessConditions
+ * {@link BlobAccessConditions}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response signalling completion.
+ */
+ public Mono setHTTPHeaders(BlobHTTPHeaders headers, BlobAccessConditions accessConditions, Context context) {
+ return blobAsyncRawClient
+ .setHTTPHeaders(headers, accessConditions, context)
+ .then();
+ }
+
+ /**
+ * 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}
+ *
+ * @return
+ * A reactive response signalling completion.
+ */
+ public Mono setMetadata(Metadata metadata) {
+ return this.setMetadata(metadata, null, 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}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response signalling completion.
+ */
+ public Mono setMetadata(Metadata metadata, BlobAccessConditions accessConditions, Context context) {
+ return blobAsyncRawClient
+ .setMetadata(metadata, accessConditions, context)
+ .then();
+ }
+
+ /**
+ * Creates a read-only snapshot of a blob.
+ *
+ * @return
+ * A reactive response containing the ID of the new snapshot.
+ */
+ public Mono createSnapshot() {
+ return this.createSnapshot(null, null, null);
+ }
+
+ /**
+ * Creates a read-only snapshot of a blob.
+ *
+ * @param metadata
+ * {@link Metadata}
+ * @param accessConditions
+ * {@link BlobAccessConditions}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response containing the ID of the new snapshot.
+ */
+ public Mono createSnapshot(Metadata metadata, BlobAccessConditions accessConditions, Context context) {
+ return blobAsyncRawClient
+ .createSnapshot(metadata, accessConditions, context)
+ .map(response -> response.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.
+ *
+ * @return
+ * A reactive response signalling completion.
+ */
+ public Mono setTier(AccessTier tier) {
+ return this.setTier(tier, null, 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.
+ *
+ * @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 context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response signalling completion.
+ */
+ public Mono setTier(AccessTier tier, LeaseAccessConditions leaseAccessConditions, Context context) {
+ return blobAsyncRawClient
+ .setTier(tier, leaseAccessConditions, context)
+ .then();
+ }
+
+ /**
+ * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots.
+ *
+ * @return
+ * A reactive response signalling completion.
+ */
+ public Mono undelete() {
+ return this.undelete(null);
+ }
+
+ /**
+ * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots.
+ *
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to its
+ * parent, forming a linked list.
+ *
+ * @return
+ * A reactive response signalling completion.
+ */
+ public Mono undelete(Context context) {
+ return blobAsyncRawClient
+ .undelete(context)
+ .then();
+ }
+
+ /**
+ * 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.
+ */
+ public Mono acquireLease(String proposedId, int duration) {
+ return this.acquireLease(proposedId, duration, null, 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).
+ *
+ * @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 context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response containing the lease ID.
+ */
+ public Mono acquireLease(String proposedID, int duration, ModifiedAccessConditions modifiedAccessConditions,
+ Context context) {
+ return blobAsyncRawClient
+ .acquireLease(proposedID, duration, modifiedAccessConditions, context)
+ .map(response -> response.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.
+ */
+ public Mono 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.
+ * @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 context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response containing the renewed lease ID.
+ */
+ public Mono renewLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions, Context context) {
+ return blobAsyncRawClient
+ .renewLease(leaseID, modifiedAccessConditions, context)
+ .map(response -> response.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.
+ */
+ public Mono 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.
+ * @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 context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response signalling completion.
+ */
+ public Mono releaseLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions, Context context) {
+ return blobAsyncRawClient
+ .releaseLease(leaseID, modifiedAccessConditions, context)
+ .then();
+ }
+
+ /**
+ * 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.
+ */
+ public Mono breakLease() {
+ return this.breakLease(null, 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.
+ *
+ * @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 context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response containing the remaining time in the broken lease in seconds.
+ */
+ public Mono breakLease(Integer breakPeriodInSeconds, ModifiedAccessConditions modifiedAccessConditions,
+ Context context) {
+ return blobAsyncRawClient
+ .breakLease(breakPeriodInSeconds, modifiedAccessConditions, context)
+ .map(response -> response.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.
+ */
+ public Mono 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 context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return A reactive response containing the new lease ID.
+ */
+ public Mono changeLease(String leaseId, String proposedID, ModifiedAccessConditions modifiedAccessConditions,
+ Context context) {
+ return blobAsyncRawClient
+ .changeLease(leaseId, proposedID, modifiedAccessConditions, context)
+ .map(response -> response.deserializedHeaders().leaseId());
+ }
+
+ /**
+ * 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.
+ */
+ public Mono getAccountInfo() {
+ return this.getAccountInfo(null);
+ }
+
+ /**
+ * Returns the sku name and account kind for the account. For more information, please see the Azure Docs.
+ *
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return a reactor response containing the sku name and account kind.
+ */
+ // TODO determine this return type
+ public Mono getAccountInfo(Context context) {
+ return blobAsyncRawClient
+ .getAccountInfo(context)
+ .map(ResponseBase::deserializedHeaders)
+ .map(StorageAccountInfo::new);
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlobAsyncRawClient.java b/storage/client/src/main/java/com/azure/storage/blob/BlobAsyncRawClient.java
new file mode 100644
index 0000000000000..12360ccf0de5b
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlobAsyncRawClient.java
@@ -0,0 +1,897 @@
+// 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.*;
+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;
+
+ /**
+ * 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) {
+ this.azureBlobStorage = azureBlobStorage;
+ }
+
+ /**
+ * 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, 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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,
+ Context context) {
+ metadata = metadata == null ? new Metadata() : metadata;
+ sourceModifiedAccessConditions = sourceModifiedAccessConditions == null
+ ? new ModifiedAccessConditions() : sourceModifiedAccessConditions;
+ destAccessConditions = destAccessConditions == null ? new BlobAccessConditions() : destAccessConditions;
+ context = context == null ? Context.NONE : context;
+
+ // 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));
+ }
+
+ /**
+ * 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, 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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, Context context) {
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blobs().abortCopyFromURLWithRestResponseAsync(
+ null, null, copyId, null, null, leaseAccessConditions, context));
+ }
+
+ /**
+ * 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, 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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,
+ Context context) {
+ metadata = metadata == null ? new Metadata() : metadata;
+ sourceModifiedAccessConditions = sourceModifiedAccessConditions == null
+ ? new ModifiedAccessConditions() : sourceModifiedAccessConditions;
+ destAccessConditions = destAccessConditions == null ? new BlobAccessConditions() : destAccessConditions;
+ context = context == null ? Context.NONE : context;
+
+ // 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));
+ }
+
+ /**
+ * 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, null);
+ }
+
+ /**
+ * 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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, Context context) {
+ Boolean getMD5 = rangeGetContentMD5 ? rangeGetContentMD5 : null;
+ range = range == null ? new BlobRange(0) : range;
+ accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions;
+ HTTPGetterInfo info = new HTTPGetterInfo()
+ .withOffset(range.offset())
+ .withCount(range.count())
+ .withETag(accessConditions.modifiedAccessConditions().ifMatch());
+
+ // TODO: range is BlobRange but expected as String
+ // TODO: figure out correct response
+ return postProcessResponse(this.azureBlobStorage.blobs().downloadWithRestResponseAsync(
+ null, null, null, null, null, range.toHeaderValue(), getMD5,
+ null, null, null, null,
+ accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), context))
+ // Convert the autorest response to a DownloadAsyncResponse, which enable reliable download.
+ .map(response -> {
+ // If there wasn't an etag originally specified, lock on the one returned.
+ info.withETag(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().withModifiedAccessConditions(
+ new ModifiedAccessConditions().ifMatch(info.eTag())), false,
+ context == null ? Context.NONE : context));
+ });
+ }
+
+ /**
+ * 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, 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}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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, Context context) {
+ accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions;
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blobs().deleteWithRestResponseAsync(
+ null, null, null, null, null, deleteBlobSnapshotOptions,
+ null, accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(),
+ context));
+ }
+
+ /**
+ * 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, null);
+ }
+
+ /**
+ * Returns the blob's metadata and properties. For more information, see the Azure Docs.
+ *
+ * @param accessConditions
+ * {@link BlobAccessConditions}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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, Context context) {
+ accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions;
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blobs().getPropertiesWithRestResponseAsync(
+ null, null, null, null, null, null,
+ null, null, null, accessConditions.leaseAccessConditions(),
+ accessConditions.modifiedAccessConditions(), context));
+ }
+
+ /**
+ * 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, null);
+ }
+
+ /**
+ * Changes a blob's HTTP header properties. For more information, see the Azure Docs.
+ *
+ * @param headers
+ * {@link BlobHTTPHeaders}
+ * @param accessConditions
+ * {@link BlobAccessConditions}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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, Context context) {
+ accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions;
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blobs().setHTTPHeadersWithRestResponseAsync(
+ null, null, null, null, headers,
+ accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), context));
+ }
+
+ /**
+ * 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, null);
+ }
+
+ /**
+ * Changes a blob's metadata. For more information, see the Azure Docs.
+ *
+ * @param metadata
+ * {@link Metadata}
+ * @param accessConditions
+ * {@link BlobAccessConditions}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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,
+ Context context) {
+ metadata = metadata == null ? new Metadata() : metadata;
+ accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions;
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blobs().setMetadataWithRestResponseAsync(
+ null, null, null, metadata, null, null,
+ null, null, accessConditions.leaseAccessConditions(),
+ accessConditions.modifiedAccessConditions(), context));
+ }
+
+ /**
+ * 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, null);
+ }
+
+ /**
+ * Creates a read-only snapshot of a blob. For more information, see the Azure Docs.
+ *
+ * @param metadata
+ * {@link Metadata}
+ * @param accessConditions
+ * {@link BlobAccessConditions}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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,
+ Context context) {
+ metadata = metadata == null ? new Metadata() : metadata;
+ accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions;
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blobs().createSnapshotWithRestResponseAsync(
+ null, null, null, metadata, null, null,
+ null, null, accessConditions.modifiedAccessConditions(),
+ accessConditions.leaseAccessConditions(), context));
+ }
+
+ /**
+ * 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, 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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,
+ Context context) {
+ Utility.assertNotNull("tier", tier);
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blobs().setTierWithRestResponseAsync(
+ null, null, tier, null, null, leaseAccessConditions, context));
+ }
+
+ /**
+ * 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 this.undelete(null);
+ }
+
+ /**
+ * 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.
+ *
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to its
+ * parent, forming a linked list.
+ *
+ * @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(Context context) {
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blobs().undeleteWithRestResponseAsync(null,
+ null, context));
+ }
+
+ /**
+ * 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, 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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,
+ ModifiedAccessConditions modifiedAccessConditions, Context context) {
+ 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.");
+ }
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blobs().acquireLeaseWithRestResponseAsync(
+ null, null, null, duration, proposedID, null,
+ modifiedAccessConditions, context));
+ }
+
+ /**
+ * 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, 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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,
+ Context context) {
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blobs().renewLeaseWithRestResponseAsync(null,
+ null, leaseID, null, null, modifiedAccessConditions, context));
+ }
+
+ /**
+ * 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, 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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, Context context) {
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blobs().releaseLeaseWithRestResponseAsync(null,
+ null, leaseID, null, null, modifiedAccessConditions, context));
+ }
+
+ /**
+ * 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, 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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, Context context) {
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blobs().breakLeaseWithRestResponseAsync(null,
+ null, null, breakPeriodInSeconds, null, modifiedAccessConditions, context));
+ }
+
+ /**
+ * 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, 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 context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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, Context context) {
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blobs().changeLeaseWithRestResponseAsync(null,
+ null, leaseId, proposedID, null, null, modifiedAccessConditions, context));
+ }
+
+ /**
+ * 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 this.getAccountInfo(null);
+ }
+
+ /**
+ * Returns the sku name and account kind for the account. For more information, please see the Azure Docs.
+ *
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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(Context context) {
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(
+ this.azureBlobStorage.blobs().getAccountInfoWithRestResponseAsync(null, null, context));
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlobClient.java b/storage/client/src/main/java/com/azure/storage/blob/BlobClient.java
new file mode 100644
index 0000000000000..b1b49e1f32cda
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlobClient.java
@@ -0,0 +1,756 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import com.azure.storage.blob.implementation.AzureBlobStorageImpl;
+import com.azure.storage.blob.models.AccessTier;
+import com.azure.storage.blob.models.BlobHTTPHeaders;
+import com.azure.storage.blob.models.BlobStartCopyFromURLHeaders;
+import com.azure.storage.blob.models.DeleteSnapshotsOptionType;
+import com.azure.storage.blob.models.LeaseAccessConditions;
+import com.azure.storage.blob.models.ModifiedAccessConditions;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UncheckedIOException;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.time.Duration;
+
+/**
+ * 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}.
+ *
+ *
+ * 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.
+ */
+public class BlobClient {
+
+ private BlobAsyncClient blobAsyncClient;
+
+ /**
+ * Package-private constructor for use by {@link BlobClientBuilder}.
+ * @param azureBlobStorage the API client for blob storage API
+ */
+ BlobClient(AzureBlobStorageImpl azureBlobStorage) {
+ this.blobAsyncClient = new BlobAsyncClient(azureBlobStorage);
+ }
+
+ /**
+ * Static method for getting a new builder for this class.
+ *
+ * @return
+ * A new {@link BlobClientBuilder} instance.
+ */
+ public static BlobClientBuilder blobClientBuilder() {
+ return new BlobClientBuilder();
+ }
+
+ /**
+ * Creates a new {@link BlockBlobClient} to this resource, maintaining configurations. Only do this for blobs
+ * that are known to be block blobs.
+ *
+ * @return
+ * A {@link BlockBlobClient} to this resource.
+ */
+ public BlockBlobClient asBlockBlobClient() {
+ return new BlockBlobClient(this.blobAsyncClient.blobAsyncRawClient.azureBlobStorage);
+ }
+
+ /**
+ * 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.
+ */
+ public AppendBlobClient asAppendBlobClient() {
+ return new AppendBlobClient(this.blobAsyncClient.blobAsyncRawClient.azureBlobStorage);
+ }
+
+ /**
+ * Creates a new {@link PageBlobClient} to this resource, maintaining configurations. Only do this for blobs
+ * that are known to be page blobs.
+ *
+ * @return
+ * A {@link PageBlobClient} to this resource.
+ */
+ public PageBlobClient asPageBlobClient() {
+ return new PageBlobClient(this.blobAsyncClient.blobAsyncRawClient.azureBlobStorage);
+ }
+
+ /**
+ * 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.
+ */
+ public String startCopyFromURL(URL sourceURL) {
+ return this.startCopyFromURL(sourceURL, null, 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.
+ * @param timeout
+ * An optional timeout value beyond which a {@link RuntimeException} will be raised.
+ *
+ * @return
+ * The copy ID for the long running operation.
+ */
+ public String startCopyFromURL(URL sourceURL, Metadata metadata,
+ ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions,
+ Duration timeout) {
+ Mono response = blobAsyncClient
+ .startCopyFromURL(sourceURL, metadata, sourceModifiedAccessConditions, destAccessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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.
+ */
+ public void abortCopyFromURL(String copyId) {
+ this.abortCopyFromURL(copyId, null, null);
+ }
+
+ /**
+ * 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.
+ */
+ public void abortCopyFromURL(String copyId, LeaseAccessConditions leaseAccessConditions, Duration timeout) {
+ Mono response = blobAsyncClient
+ .abortCopyFromURL(copyId, leaseAccessConditions, null /*context*/);
+
+ if (timeout == null) {
+ response.block();
+ } else {
+ response.block(timeout);
+ }
+ }
+
+ /**
+ * 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.
+ */
+ public String copyFromURL(URL copySource) {
+ return this.copyFromURL(copySource, null, null, null, null);
+ }
+
+ /**
+ * 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.
+ */
+ public String copyFromURL(URL copySource, Metadata metadata,
+ ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions,
+ Duration timeout) {
+ Mono response = blobAsyncClient
+ .copyFromURL(copySource, metadata, sourceModifiedAccessConditions, destAccessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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.
+ */
+ public void download(OutputStream stream) throws IOException {
+ this.download(stream, null, null, null, false, null);
+ }
+
+ /**
+ * 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 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.
+ */
+ public void download(OutputStream stream, ReliableDownloadOptions options, BlobRange range,
+ BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Duration timeout) throws IOException {
+ Flux data = blobAsyncClient
+ .download(range, accessConditions, rangeGetContentMD5, options, null /*context*/);
+
+ data = timeout == null
+ ? data
+ : data.timeout(timeout); //TODO this isn't doing what we want
+
+ for (ByteBuffer buffer : data.toIterable()) {
+ stream.write(buffer.array());
+ }
+ }
+
+ /**
+ * 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}.
+ *
+ * @param filePath
+ * A non-null {@link OutputStream} instance where the downloaded data will be written.
+ */
+ public void downloadToFile(String filePath) throws IOException {
+ this.downloadToFile(filePath, null, null, null, false, null);
+ }
+
+ /**
+ * 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}.
+ *
+ * @param filePath
+ * A non-null {@link OutputStream} instance where the downloaded data will be written.
+ * @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.
+ */
+ public void downloadToFile(String filePath, ReliableDownloadOptions options, BlobRange range,
+ BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Duration timeout) throws IOException {
+ Mono download = blobAsyncClient.downloadToFile(filePath, range, accessConditions, rangeGetContentMD5, options, null);
+
+ try {
+ if (timeout == null) {
+ download.block();
+ } else {
+ download.block(timeout); //TODO this isn't doing what we want
+ }
+ } catch (UncheckedIOException e) {
+ throw e.getCause();
+ }
+ }
+
+ /**
+ * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots.
+ */
+ public void delete() {
+ this.delete(null, null, null);
+ }
+
+ /**
+ * 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.
+ *
+ * @return
+ * A reactive response signalling completion.
+ */
+ public void delete(DeleteSnapshotsOptionType deleteBlobSnapshotOptions,
+ BlobAccessConditions accessConditions, Duration timeout) {
+ Mono response = blobAsyncClient
+ .delete(deleteBlobSnapshotOptions, accessConditions, null /*context*/);
+
+ if (timeout == null) {
+ response.block();
+ } else {
+ response.block(timeout);
+ }
+ }
+
+ /**
+ * Returns the blob's metadata and properties.
+ *
+ * @return
+ * The blob properties and metadata.
+ */
+ public BlobProperties getProperties() {
+ return this.getProperties(null, null);
+ }
+
+ /**
+ * 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.
+ */
+ public BlobProperties getProperties(BlobAccessConditions accessConditions, Duration timeout) {
+ Mono response = blobAsyncClient
+ .getProperties(accessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * Changes a blob's HTTP header properties. if only one HTTP header is updated, the
+ * others will all be erased. In order to preserve existing values, they must be
+ * passed alongside the header being changed. For more information, see the
+ * Azure Docs.
+ *
+ * @param headers
+ * {@link BlobHTTPHeaders}
+ */
+ public void setHTTPHeaders(BlobHTTPHeaders headers) {
+ this.setHTTPHeaders(headers, null, 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
+ * Azure Docs.
+ *
+ * @param headers
+ * {@link BlobHTTPHeaders}
+ * @param accessConditions
+ * {@link BlobAccessConditions}
+ * @param timeout
+ * An optional timeout value beyond which a {@link RuntimeException} will be raised.
+ */
+ public void setHTTPHeaders(BlobHTTPHeaders headers, BlobAccessConditions accessConditions,
+ Duration timeout) {
+ Mono response = blobAsyncClient
+ .setHTTPHeaders(headers, accessConditions, null /*context*/);
+
+ if (timeout == null) {
+ response.block();
+ } else {
+ response.block(timeout);
+ }
+ }
+
+ /**
+ * Changes a blob's metadata. The specified metadata in this method will replace existing
+ * metadata. If old values must be preserved, they must be downloaded and included in the
+ * call to this method. For more information, see the Azure Docs.
+ *
+ * @param metadata
+ * {@link Metadata}
+ */
+ public void setMetadata(Metadata metadata) {
+ this.setMetadata(metadata, null, 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}
+ * @param timeout
+ * An optional timeout value beyond which a {@link RuntimeException} will be raised.
+ */
+ public void setMetadata(Metadata metadata, BlobAccessConditions accessConditions, Duration timeout) {
+ Mono response = blobAsyncClient
+ .setMetadata(metadata, accessConditions, null /*context*/);
+
+ if (timeout == null) {
+ response.block();
+ } else {
+ response.block(timeout);
+ }
+ }
+
+ /**
+ * Creates a read-only snapshot of a blob.
+ *
+ * @return
+ * The ID of the new snapshot.
+ */
+ public String createSnapshot() {
+ return this.createSnapshot(null, null, null);
+ }
+
+ /**
+ * 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.
+ */
+ public String createSnapshot(Metadata metadata, BlobAccessConditions accessConditions, Duration timeout) {
+ Mono response = blobAsyncClient
+ .createSnapshot(metadata, accessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * Sets the tier on a blob. The operation is allowed on a page blob in a premium storage account or a block blob in
+ * a blob storage or GPV2 account. A premium page blob's tier determines the allowed size, IOPS, and bandwidth of
+ * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's etag.
+ *
+ * @param tier
+ * The new tier for the blob.
+ */
+ public void setTier(AccessTier tier) {
+ this.setTier(tier, null, 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.
+ *
+ * @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.
+ */
+ public void setTier(AccessTier tier, LeaseAccessConditions leaseAccessConditions, Duration timeout) {
+ Mono response = blobAsyncClient
+ .setTier(tier, leaseAccessConditions, null /*context*/);
+
+ if (timeout == null) {
+ response.block();
+ } else {
+ response.block(timeout);
+ }
+ }
+
+ /**
+ * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots.
+ */
+ public void undelete() {
+ this.undelete(null);
+ }
+
+ /**
+ * 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.
+ */
+ public void undelete(Duration timeout) {
+ Mono response = blobAsyncClient
+ .undelete(null /*context*/);
+
+ if (timeout == null) {
+ response.block();
+ } else {
+ response.block(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.
+ */
+ public String acquireLease(String proposedId, int duration) {
+ return this.acquireLease(proposedId, duration, null, 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).
+ *
+ * @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 String acquireLease(String proposedID, int duration,
+ ModifiedAccessConditions modifiedAccessConditions, Duration timeout) {
+ Mono response = blobAsyncClient
+ .acquireLease(proposedID, duration, modifiedAccessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * Renews the blob's previously-acquired lease.
+ *
+ * @param leaseID
+ * The leaseId of the active lease on the blob.
+ *
+ * @return
+ * The renewed lease ID.
+ */
+ public String 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.
+ * @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 String renewLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions,
+ Duration timeout) {
+ Mono response = blobAsyncClient
+ .renewLease(leaseID, modifiedAccessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * Releases the blob's previously-acquired lease.
+ *
+ * @param leaseID
+ * The leaseId of the active lease on the blob.
+ */
+ public void releaseLease(String leaseID) {
+ this.releaseLease(leaseID, null, null);
+ }
+
+ /**
+ * 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.
+ */
+ public void releaseLease(String leaseID,
+ ModifiedAccessConditions modifiedAccessConditions, Duration timeout) {
+ Mono response = blobAsyncClient
+ .releaseLease(leaseID, modifiedAccessConditions, null /*context*/);
+
+ if (timeout == null) {
+ response.block();
+ } else {
+ response.block(timeout);
+ }
+ }
+
+ /**
+ * 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.
+ */
+ public int breakLease() {
+ return this.breakLease(null, 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.
+ *
+ * @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 int breakLease(Integer breakPeriodInSeconds,
+ ModifiedAccessConditions modifiedAccessConditions, Duration timeout) {
+ Mono response = blobAsyncClient
+ .breakLease(breakPeriodInSeconds, modifiedAccessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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.
+ */
+ public String 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.
+ *
+ * @return The new lease ID.
+ */
+ public String changeLease(String leaseId, String proposedID,
+ ModifiedAccessConditions modifiedAccessConditions, Duration timeout) {
+ Mono response = blobAsyncClient
+ .changeLease(leaseId, proposedID, modifiedAccessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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.
+ */
+ public StorageAccountInfo getAccountInfo() {
+ return this.getAccountInfo(null);
+ }
+
+ /**
+ * 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 StorageAccountInfo getAccountInfo(Duration timeout) {
+ Mono response = blobAsyncClient
+ .getAccountInfo(null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlobClientBuilder.java b/storage/client/src/main/java/com/azure/storage/blob/BlobClientBuilder.java
new file mode 100644
index 0000000000000..9fe00cbd8fa55
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlobClientBuilder.java
@@ -0,0 +1,220 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import com.azure.core.configuration.Configuration;
+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.util.ImplUtils;
+import com.azure.storage.blob.implementation.AzureBlobStorageBuilder;
+import com.azure.storage.blob.implementation.AzureBlobStorageImpl;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Fluent BlobClientBuilder for instantiating a {@link BlobClient} or {@link BlobAsyncClient}.
+ *
+ *
+ * An instance of this builder may only be created from static method {@link BlobClient#blobClientBuilder()}.
+ * The following information must be provided on this builder:
+ *
+ *
+ * - the endpoint through {@code .endpoint()}, including the container name and blob name, in the format of {@code https://{accountName}.blob.core.windows.net/{containerName}/{blobName}}.
+ *
- the credential through {@code .credentials()} or {@code .connectionString()} if the container is not publicly accessible.
+ *
+ *
+ *
+ * Once all the configurations are set on this builder, call {@code .buildClient()} to create a
+ * {@link BlobClient} or {@code .buildAsyncClient()} to create a {@link BlobAsyncClient}.
+ */
+public final class BlobClientBuilder {
+ private static final String ACCOUNT_NAME = "AccountName".toLowerCase();
+ private static final String ACCOUNT_KEY = "AccountKey".toLowerCase();
+
+ private final List policies;
+
+ private URL endpoint;
+ private ICredentials credentials = new AnonymousCredentials();
+ private HttpClient httpClient;
+ private HttpLogDetailLevel logLevel;
+ private RetryPolicy retryPolicy;
+ private Configuration configuration;
+
+ public BlobClientBuilder() {
+ retryPolicy = new RetryPolicy();
+ logLevel = HttpLogDetailLevel.NONE;
+ policies = new ArrayList<>();
+ }
+
+ /**
+ * Constructs an instance of BlobAsyncClient based on the configurations stored in the appendBlobClientBuilder.
+ * @return a new client instance
+ */
+ private AzureBlobStorageImpl buildImpl() {
+ Objects.requireNonNull(endpoint);
+
+ // Closest to API goes first, closest to wire goes last.
+ final List policies = new ArrayList<>();
+
+ policies.add(new UserAgentPolicy(BlobConfiguration.NAME, BlobConfiguration.VERSION));
+ policies.add(new RequestIdPolicy());
+ policies.add(new AddDatePolicy());
+ policies.add(credentials); // This needs to be a different credential type.
+
+ policies.add(retryPolicy);
+
+ policies.addAll(this.policies);
+ policies.add(new HttpLoggingPolicy(logLevel));
+
+ HttpPipeline pipeline = HttpPipeline.builder()
+ .policies(policies.toArray(new HttpPipelinePolicy[0]))
+ .httpClient(httpClient)
+ .build();
+
+ return new AzureBlobStorageBuilder()
+ .url(endpoint.toString())
+ .pipeline(pipeline)
+ .build();
+ }
+
+ /**
+ * @return a {@link BlobClient} created from the configurations in this builder.
+ */
+ public BlobClient buildClient() {
+ return new BlobClient(buildImpl());
+ }
+
+ /**
+ * @return a {@link BlobAsyncClient} created from the configurations in this builder.
+ */
+ public BlobAsyncClient buildAsyncClient() {
+ return new BlobAsyncClient(buildImpl());
+ }
+
+ /**
+ * Sets the service endpoint, additionally parses it for information (SAS token, container name, blob name)
+ * @param endpoint URL of the service
+ * @return the updated BlobClientBuilder object
+ */
+ public BlobClientBuilder endpoint(String endpoint) {
+ Objects.requireNonNull(endpoint);
+ try {
+ this.endpoint = new URL(endpoint);
+ } catch (MalformedURLException ex) {
+ throw new IllegalArgumentException("The Azure Storage Queue endpoint url is malformed.");
+ }
+
+ return this;
+ }
+
+ /**
+ * Sets the credentials used to authorize requests sent to the service
+ * @param credentials authorization credentials
+ * @return the updated BlobClientBuilder object
+ */
+ public BlobClientBuilder credentials(SharedKeyCredentials credentials) {
+ this.credentials = credentials;
+ return this;
+ }
+
+ /**
+ * Sets the credentials used to authorize requests sent to the service
+ * @param credentials authorization credentials
+ * @return the updated BlobClientBuilder object
+ */
+ public BlobClientBuilder credentials(TokenCredentials credentials) {
+ this.credentials = credentials;
+ return this;
+ }
+
+ /**
+ * Clears the credentials used to authorize requests sent to the service
+ * @return the updated BlobClientBuilder object
+ */
+ public BlobClientBuilder anonymousCredentials() {
+ this.credentials = new AnonymousCredentials();
+ return this;
+ }
+
+ /**
+ * Sets the connection string for the service, parses it for authentication information (account name, account key)
+ * @param connectionString connection string from access keys section
+ * @return the updated BlobClientBuilder object
+ */
+ public BlobClientBuilder connectionString(String connectionString) {
+ Objects.requireNonNull(connectionString);
+
+ Map connectionKVPs = new HashMap<>();
+ for (String s : connectionString.split(";")) {
+ String[] kvp = s.split("=", 2);
+ connectionKVPs.put(kvp[0].toLowerCase(), kvp[1]);
+ }
+
+ String accountName = connectionKVPs.get(ACCOUNT_NAME);
+ String accountKey = connectionKVPs.get(ACCOUNT_KEY);
+
+ if (ImplUtils.isNullOrEmpty(accountName) || ImplUtils.isNullOrEmpty(accountKey)) {
+ throw new IllegalArgumentException("Connection string must contain 'AccountName' and 'AccountKey'.");
+ }
+
+ // Use accountName and accountKey to get the SAS token using the credential class.
+ credentials = new SharedKeyCredentials(accountName, accountKey);
+
+ return this;
+ }
+
+ /**
+ * Sets the http client used to send service requests
+ * @param httpClient http client to send requests
+ * @return the updated BlobClientBuilder object
+ */
+ public BlobClientBuilder httpClient(HttpClient httpClient) {
+ this.httpClient = httpClient;
+ return this;
+ }
+
+ /**
+ * Adds a pipeline policy to apply on each request sent
+ * @param pipelinePolicy a pipeline policy
+ * @return the updated BlobClientBuilder object
+ */
+ public BlobClientBuilder addPolicy(HttpPipelinePolicy pipelinePolicy) {
+ this.policies.add(pipelinePolicy);
+ return this;
+ }
+
+ /**
+ * Sets the logging level for service requests
+ * @param logLevel logging level
+ * @return the updated BlobClientBuilder object
+ */
+ public BlobClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) {
+ this.logLevel = logLevel;
+ return this;
+ }
+
+ /**
+ * Sets the configuration object used to retrieve environment configuration values used to buildClient the client with
+ * when they are not set in the appendBlobClientBuilder, defaults to Configuration.NONE
+ * @param configuration configuration store
+ * @return the updated BlobClientBuilder object
+ */
+ public BlobClientBuilder configuration(Configuration configuration) {
+ this.configuration = configuration;
+ return this;
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlobConfiguration.java b/storage/client/src/main/java/com/azure/storage/blob/BlobConfiguration.java
new file mode 100644
index 0000000000000..ae1e422a24c0a
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlobConfiguration.java
@@ -0,0 +1,8 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+package com.azure.storage.blob;
+
+class BlobConfiguration {
+ static final String NAME = "storage-blob";
+ static final String VERSION = "1.0.0-SNAPSHOT";
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlobListDetails.java b/storage/client/src/main/java/com/azure/storage/blob/BlobListDetails.java
new file mode 100644
index 0000000000000..445bb567f7823
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlobListDetails.java
@@ -0,0 +1,133 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import com.azure.storage.blob.models.ListBlobsIncludeItem;
+
+import java.util.ArrayList;
+
+/**
+ * This type allows users to specify additional information the service should return with each blob when listing blobs
+ * in a container (via a {@link ContainerURL} object). This type is immutable to ensure thread-safety of requests, so
+ * changing the details for a different listing operation requires construction of a new object. Null may be passed if
+ * none of the options are desirable.
+ */
+public final class BlobListDetails {
+
+ private boolean copy;
+
+ private boolean metadata;
+
+ private boolean snapshots;
+
+ private boolean uncommittedBlobs;
+
+ private boolean deletedBlobs;
+
+ public BlobListDetails() {
+ }
+
+ /**
+ * Whether blob metadata related to any current or previous Copy Blob operation should be included in the
+ * response.
+ */
+ public boolean copy() {
+ return copy;
+ }
+
+ /**
+ * Whether blob metadata related to any current or previous Copy Blob operation should be included in the
+ * response.
+ */
+ public BlobListDetails withCopy(boolean copy) {
+ this.copy = copy;
+ return this;
+ }
+
+ /**
+ * Whether blob metadata should be returned.
+ */
+ public boolean metadata() {
+ return metadata;
+ }
+
+ /**
+ * Whether blob metadata should be returned.
+ */
+ public BlobListDetails withMetadata(boolean metadata) {
+ this.metadata = metadata;
+ return this;
+ }
+
+ /**
+ * Whether snapshots should be returned. Snapshots are listed from oldest to newest.
+ */
+ public boolean snapshots() {
+ return snapshots;
+ }
+
+ /**
+ * Whether snapshots should be returned. Snapshots are listed from oldest to newest.
+ */
+ public BlobListDetails withSnapshots(boolean snapshots) {
+ this.snapshots = snapshots;
+ return this;
+ }
+
+ /**
+ * Whether blobs for which blocks have been uploaded, but which have not been committed using Put Block List,
+ * should be included in the response.
+ */
+ public boolean uncommittedBlobs() {
+ return uncommittedBlobs;
+ }
+
+ /**
+ * Whether blobs for which blocks have been uploaded, but which have not been committed using Put Block List,
+ * should be included in the response.
+ */
+ public BlobListDetails withUncommittedBlobs(boolean uncommittedBlobs) {
+ this.uncommittedBlobs = uncommittedBlobs;
+ return this;
+ }
+
+ /**
+ * Whether blobs which have been soft deleted should be returned.
+ */
+ public boolean deletedBlobs() {
+ return deletedBlobs;
+ }
+
+ /**
+ * Whether blobs which have been soft deleted should be returned.
+ */
+ public BlobListDetails withDeletedBlobs(boolean deletedBlobs) {
+ this.deletedBlobs = deletedBlobs;
+ return this;
+ }
+
+ /*
+ This is used internally to convert the details structure into a list to pass to the protocol layer. The customer
+ should never have need for this.
+ */
+ ArrayList toList() {
+ ArrayList details = new ArrayList();
+ if (this.copy) {
+ details.add(ListBlobsIncludeItem.COPY);
+ }
+ if (this.deletedBlobs) {
+ details.add(ListBlobsIncludeItem.DELETED);
+ }
+ if (this.metadata) {
+ details.add(ListBlobsIncludeItem.METADATA);
+ }
+ if (this.snapshots) {
+ details.add(ListBlobsIncludeItem.SNAPSHOTS);
+ }
+ if (this.uncommittedBlobs) {
+ details.add(ListBlobsIncludeItem.UNCOMMITTEDBLOBS);
+ }
+ return details;
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlobProperties.java b/storage/client/src/main/java/com/azure/storage/blob/BlobProperties.java
new file mode 100644
index 0000000000000..ad5026cd63f35
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlobProperties.java
@@ -0,0 +1,70 @@
+package com.azure.storage.blob;
+
+import com.azure.storage.blob.models.BlobGetPropertiesHeaders;
+import com.azure.storage.blob.models.BlobType;
+
+public class BlobProperties {
+
+ private final BlobType blobType;
+
+ private final Metadata metadata;
+
+ private final long blobSize;
+
+ private final byte[] contentMD5;
+
+ private final String contentEncoding;
+
+ private final String contentDisposition;
+
+ private final String contentLanguage;
+
+ private final String cacheControl;
+
+ //todo decide datetime representation for last modified time
+
+
+ BlobProperties(BlobGetPropertiesHeaders generatedHeaders) {
+ this.blobType = generatedHeaders.blobType();
+ this.metadata = new Metadata(generatedHeaders.metadata());
+ this.blobSize = generatedHeaders.contentLength();
+ this.contentMD5 = generatedHeaders.contentMD5();
+ this.contentEncoding = generatedHeaders.contentEncoding();
+ this.contentDisposition = generatedHeaders.contentDisposition();
+ this.contentLanguage = generatedHeaders.contentLanguage();
+ this.cacheControl = generatedHeaders.cacheControl();
+ }
+
+
+ public BlobType blobType() {
+ return blobType;
+ }
+
+ public Metadata metadata() {
+ return metadata;
+ }
+
+ public long blobSize() {
+ return blobSize;
+ }
+
+ public byte[] contentMD5() {
+ return contentMD5;
+ }
+
+ public String contentEncoding() {
+ return contentEncoding;
+ }
+
+ public String contentDisposition() {
+ return contentDisposition;
+ }
+
+ public String contentLanguage() {
+ return contentLanguage;
+ }
+
+ public String cacheControl() {
+ return cacheControl;
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlobRange.java b/storage/client/src/main/java/com/azure/storage/blob/BlobRange.java
new file mode 100644
index 0000000000000..054f9f1a1b782
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlobRange.java
@@ -0,0 +1,91 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import java.util.Locale;
+
+/**
+ * This is a representation of a range of bytes on a blob, typically used during a download operation. This type is
+ * immutable to ensure thread-safety of requests, so changing the values for a different operation requires construction
+ * of a new object. Passing null as a BlobRange value will default to the entire range of the blob.
+ */
+public final class BlobRange {
+
+ private long offset;
+ private Long count;
+
+ /**
+ * Specifies the download operation to start from the offset position (zero-based) and download the
+ * rest of the entire blob to the end.
+ *
+ * @param offset
+ * the zero-based position to start downloading
+ */
+ public BlobRange(long offset) {
+ if (offset < 0) {
+ throw new IllegalArgumentException("BlobRange offset must be greater than or equal to 0.");
+ }
+ this.offset = offset;
+ }
+
+ /**
+ * Specifies the download operation to start from the offset position (zero-based) and download the
+ * count number of bytes.
+ *
+ * @param offset
+ * the zero-based position to start downloading
+ * @param count
+ * the number of bytes to download
+ */
+ public BlobRange(long offset, long count) {
+ this(offset);
+ if (count < 0) {
+ throw new IllegalArgumentException(
+ "BlobRange count must be greater than or equal to 0 if specified.");
+ }
+ this.count = count;
+ }
+
+ /**
+ * The start of the range. Must be greater than or equal to 0.
+ */
+ public long offset() {
+ return offset;
+ }
+
+ /**
+ * How many bytes to include in the range. Must be greater than or equal to 0 if specified.
+ */
+ public Long count() {
+ return count;
+ }
+
+ /**
+ * @return A {@code String} compliant with the format of the Azure Storage x-ms-range and Range headers.
+ */
+ @Override
+ public String toString() {
+ if (this.count != null) {
+ long rangeEnd = this.offset + this.count - 1;
+ return String.format(
+ Locale.ROOT, Constants.HeaderConstants.RANGE_HEADER_FORMAT, this.offset, rangeEnd);
+ }
+
+ return String.format(
+ Locale.ROOT, Constants.HeaderConstants.BEGIN_RANGE_HEADER_FORMAT, this.offset);
+ }
+
+ /*
+ In the case where the customer passes a null BlobRange, constructing the default of "0-" will fail on an empty blob.
+ By returning null as the header value, we elect not to set the header, which has the same effect, namely downloading
+ the whole blob, but it will not fail in the empty case.
+ */
+ String toHeaderValue() {
+ // The default values of a BlobRange
+ if (this.offset == 0 && this.count == null) {
+ return null;
+ }
+ return this.toString();
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlobRawClient.java b/storage/client/src/main/java/com/azure/storage/blob/BlobRawClient.java
new file mode 100644
index 0000000000000..58f48d3454b1f
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlobRawClient.java
@@ -0,0 +1,768 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import com.azure.storage.blob.implementation.AzureBlobStorageImpl;
+import com.azure.storage.blob.models.AccessTier;
+import com.azure.storage.blob.models.BlobHTTPHeaders;
+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.ModifiedAccessConditions;
+import reactor.core.publisher.Mono;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URL;
+import java.time.Duration;
+
+/**
+ * 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 BlobRawClient {
+
+ private BlobAsyncRawClient blobAsyncRawClient;
+
+ /**
+ * Creates a {@code BlobAsyncRawClient} object pointing to the account specified by the URL and using the provided pipeline to
+ * make HTTP requests.
+ */
+ BlobRawClient(AzureBlobStorageImpl azureBlobStorage) {
+ this.blobAsyncRawClient = new BlobAsyncRawClient(azureBlobStorage);
+ }
+
+ /**
+ * 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 BlobsStartCopyFromURLResponse startCopyFromURL(URL sourceURL) {
+ return this.startCopyFromURL(sourceURL, null, 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 BlobsStartCopyFromURLResponse startCopyFromURL(URL sourceURL, Metadata metadata,
+ ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions,
+ Duration timeout) {
+ Mono response = blobAsyncRawClient
+ .startCopyFromURL(sourceURL, metadata, sourceModifiedAccessConditions, destAccessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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 BlobsAbortCopyFromURLResponse abortCopyFromURL(String copyId) {
+ return this.abortCopyFromURL(copyId, null, 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 BlobsAbortCopyFromURLResponse abortCopyFromURL(String copyId, LeaseAccessConditions leaseAccessConditions,
+ Duration timeout) {
+ Mono response = blobAsyncRawClient
+ .abortCopyFromURL(copyId, leaseAccessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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 BlobsCopyFromURLResponse syncCopyFromURL(URL copySource) {
+ return this.syncCopyFromURL(copySource, null, 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 BlobsCopyFromURLResponse syncCopyFromURL(URL copySource, Metadata metadata,
+ ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions,
+ Duration timeout) {
+ Mono response = blobAsyncRawClient
+ .syncCopyFromURL(copySource, metadata, sourceModifiedAccessConditions, destAccessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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 void download(OutputStream stream) throws IOException {
+ this.download(stream, null, null, null, false, null);
+ }
+
+ /**
+ * 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 void download(OutputStream stream, ReliableDownloadOptions options, BlobRange range,
+ BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Duration timeout) throws IOException {
+ Mono response = blobAsyncRawClient
+ .download(range, accessConditions, rangeGetContentMD5, null /*context*/);
+
+ DownloadResponse download = new DownloadResponse(timeout == null
+ ? response.block()
+ : response.block(timeout));
+
+ download.body(stream, options);
+ }
+
+ /**
+ * 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 BlobsDeleteResponse delete() {
+ return this.delete(null, 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 BlobsDeleteResponse delete(DeleteSnapshotsOptionType deleteBlobSnapshotOptions,
+ BlobAccessConditions accessConditions, Duration timeout) {
+ Mono response = blobAsyncRawClient
+ .delete(deleteBlobSnapshotOptions, accessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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 BlobsGetPropertiesResponse getProperties() {
+ return this.getProperties(null, 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 BlobsGetPropertiesResponse getProperties(BlobAccessConditions accessConditions, Duration timeout) {
+ Mono response = blobAsyncRawClient
+ .getProperties(accessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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 BlobsSetHTTPHeadersResponse setHTTPHeaders(BlobHTTPHeaders headers) {
+ return this.setHTTPHeaders(headers, null, 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 BlobsSetHTTPHeadersResponse setHTTPHeaders(BlobHTTPHeaders headers, BlobAccessConditions accessConditions,
+ Duration timeout) {
+ Mono response = blobAsyncRawClient
+ .setHTTPHeaders(headers, accessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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 BlobsSetMetadataResponse setMetadata(Metadata metadata) {
+ return this.setMetadata(metadata, null, 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 BlobsSetMetadataResponse setMetadata(Metadata metadata, BlobAccessConditions accessConditions,
+ Duration timeout) {
+ Mono response = blobAsyncRawClient
+ .setMetadata(metadata, accessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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 BlobsCreateSnapshotResponse createSnapshot() {
+ return this.createSnapshot(null, 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 BlobsCreateSnapshotResponse createSnapshot(Metadata metadata, BlobAccessConditions accessConditions,
+ Duration timeout) {
+ Mono response = blobAsyncRawClient
+ .createSnapshot(metadata, accessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * Sets the tier on a blob. The operation is allowed on a page blob in a premium storage account or a block blob in
+ * a blob storage or GPV2 account. A premium page blob's tier determines the allowed size, IOPS, and bandwidth of
+ * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's etag.
+ *
+ * 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 BlobsSetTierResponse setTier(AccessTier tier) {
+ return this.setTier(tier, null, 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 BlobsSetTierResponse setTier(AccessTier tier, LeaseAccessConditions leaseAccessConditions, Duration timeout) {
+ Mono response = blobAsyncRawClient
+ .setTier(tier, leaseAccessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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 BlobsUndeleteResponse undelete() {
+ return this.undelete(null);
+ }
+
+ /**
+ * 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 BlobsUndeleteResponse undelete(Duration timeout) {
+ Mono response = blobAsyncRawClient
+ .undelete(null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(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). 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 BlobsAcquireLeaseResponse acquireLease(String proposedId, int duration) {
+ return this.acquireLease(proposedId, duration, null, 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.
+ *
+ * @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 BlobsAcquireLeaseResponse acquireLease(String proposedID, int duration,
+ ModifiedAccessConditions modifiedAccessConditions, Duration timeout) {
+ Mono response = blobAsyncRawClient
+ .acquireLease(proposedID, duration, modifiedAccessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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 BlobsRenewLeaseResponse renewLease(String leaseID) {
+ return this.renewLease(leaseID, null, 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 BlobsRenewLeaseResponse renewLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions,
+ Duration timeout) {
+ Mono response = blobAsyncRawClient
+ .renewLease(leaseID, modifiedAccessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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 BlobsReleaseLeaseResponse releaseLease(String leaseID) {
+ return this.releaseLease(leaseID, null, 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 BlobsReleaseLeaseResponse releaseLease(String leaseID,
+ ModifiedAccessConditions modifiedAccessConditions, Duration timeout) {
+ Mono response = blobAsyncRawClient
+ .releaseLease(leaseID, modifiedAccessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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 BlobsBreakLeaseResponse breakLease() {
+ return this.breakLease(null, 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 BlobsBreakLeaseResponse breakLease(Integer breakPeriodInSeconds,
+ ModifiedAccessConditions modifiedAccessConditions, Duration timeout) {
+ Mono response = blobAsyncRawClient
+ .breakLease(breakPeriodInSeconds, modifiedAccessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+
+ /**
+ * 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 BlobsChangeLeaseResponse 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.
+ * @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 BlobsChangeLeaseResponse changeLease(String leaseId, String proposedID,
+ ModifiedAccessConditions modifiedAccessConditions, Duration timeout) {
+ Mono response = blobAsyncRawClient
+ .changeLease(leaseId, proposedID, modifiedAccessConditions, null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(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 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 BlobsGetAccountInfoResponse 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 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 BlobsGetAccountInfoResponse getAccountInfo(Duration timeout) {
+ Mono response = blobAsyncRawClient
+ .getAccountInfo(null /*context*/);
+
+ return timeout == null
+ ? response.block()
+ : response.block(timeout);
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlobSASPermission.java b/storage/client/src/main/java/com/azure/storage/blob/BlobSASPermission.java
new file mode 100644
index 0000000000000..3a7c747b2fc77
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlobSASPermission.java
@@ -0,0 +1,181 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import java.util.Locale;
+
+/**
+ * This is a helper class to construct a string representing the permissions granted by a ServiceSAS to a blob. Setting
+ * a value to true means that any SAS which uses these permissions will grant permissions for that operation. Once all
+ * the values are set, this should be serialized with toString and set as the permissions field on a
+ * {@link ServiceSASSignatureValues} object. It is possible to construct the permissions string without this class, but
+ * the order of the permissions is particular and this class guarantees correctness.
+ */
+final class BlobSASPermission {
+
+ private boolean read;
+
+ private boolean add;
+
+ private boolean create;
+
+ private boolean write;
+
+ private boolean delete;
+
+ /**
+ * Initializes a {@code BlobSASPermission} object with all fields set to false.
+ */
+ public BlobSASPermission() {
+ }
+
+ /**
+ * Creates a {@code BlobSASPermission} from the specified permissions string. This method will throw an
+ * {@code IllegalArgumentException} if it encounters a character that does not correspond to a valid permission.
+ *
+ * @param permString
+ * A {@code String} which represents the {@code BlobSASPermission}.
+ *
+ * @return A {@code BlobSASPermission} generated from the given {@code String}.
+ */
+ public static BlobSASPermission parse(String permString) {
+ BlobSASPermission permissions = new BlobSASPermission();
+
+ for (int i = 0; i < permString.length(); i++) {
+ char c = permString.charAt(i);
+ switch (c) {
+ case 'r':
+ permissions.read = true;
+ break;
+ case 'a':
+ permissions.add = true;
+ break;
+ case 'c':
+ permissions.create = true;
+ break;
+ case 'w':
+ permissions.write = true;
+ break;
+ case 'd':
+ permissions.delete = true;
+ break;
+ default:
+ throw new IllegalArgumentException(
+ String.format(Locale.ROOT, SR.ENUM_COULD_NOT_BE_PARSED_INVALID_VALUE, "Permissions", permString, c));
+ }
+ }
+ return permissions;
+ }
+
+ /**
+ * Specifies Read access granted.
+ */
+ public boolean read() {
+ return read;
+ }
+
+ /**
+ * Specifies Read access granted.
+ */
+ public BlobSASPermission withRead(boolean read) {
+ this.read = read;
+ return this;
+ }
+
+ /**
+ * Specifies Add access granted.
+ */
+ public boolean add() {
+ return add;
+ }
+
+ /**
+ * Specifies Add access granted.
+ */
+ public BlobSASPermission withAdd(boolean add) {
+ this.add = add;
+ return this;
+ }
+
+ /**
+ * Specifies Create access granted.
+ */
+ public boolean create() {
+ return create;
+ }
+
+ /**
+ * Specifies Create access granted.
+ */
+ public BlobSASPermission withCreate(boolean create) {
+ this.create = create;
+ return this;
+ }
+
+ /**
+ * Specifies Write access granted.
+ */
+ public boolean write() {
+ return write;
+ }
+
+ /**
+ * Specifies Write access granted.
+ */
+ public BlobSASPermission withWrite(boolean write) {
+ this.write = write;
+ return this;
+ }
+
+ /**
+ * Specifies Delete access granted.
+ */
+ public boolean delete() {
+ return delete;
+ }
+
+ /**
+ * Specifies Delete access granted.
+ */
+ public BlobSASPermission withDelete(boolean delete) {
+ this.delete = delete;
+ return this;
+ }
+
+ /**
+ * Converts the given permissions to a {@code String}. Using this method will guarantee the permissions are in an
+ * order accepted by the service.
+ *
+ * @return A {@code String} which represents the {@code BlobSASPermission}.
+ */
+ @Override
+ public String toString() {
+ // The order of the characters should be as specified here to ensure correctness:
+ // https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas
+
+ final StringBuilder builder = new StringBuilder();
+
+ if (this.read) {
+ builder.append('r');
+ }
+
+ if (this.add) {
+ builder.append('a');
+ }
+
+ if (this.create) {
+ builder.append('c');
+ }
+
+ if (this.write) {
+ builder.append('w');
+ }
+
+ if (this.delete) {
+ builder.append('d');
+ }
+
+ return builder.toString();
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlobURLParts.java b/storage/client/src/main/java/com/azure/storage/blob/BlobURLParts.java
new file mode 100644
index 0000000000000..f4bf83810b743
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlobURLParts.java
@@ -0,0 +1,197 @@
+// 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 java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A BlobURLParts object represents the components that make up an Azure Storage Container/Blob URL. You may parse an
+ * existing URL into its parts with the {@link URLParser} class. You may construct a URL from parts by calling toURL().
+ * It is also possible to use the empty constructor to buildClient a blobURL from scratch.
+ * NOTE: Changing any SAS-related field requires computing a new SAS signature.
+ *
+ * @apiNote ## Sample Code \n
+ * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=url_parts "Sample code for BlobURLParts")] \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 BlobURLParts {
+
+ private String scheme;
+
+ private String host;
+
+ private String containerName;
+
+ private String blobName;
+
+ private String snapshot;
+
+ private SASQueryParameters sasQueryParameters;
+
+ private Map unparsedParameters;
+
+ /**
+ * Initializes a BlobURLParts object with all fields set to null, except unparsedParameters, which is an empty map.
+ * This may be useful for constructing a URL to a blob storage resource from scratch when the constituent parts are
+ * already known.
+ */
+ public BlobURLParts() {
+ unparsedParameters = new HashMap<>();
+ }
+
+ /**
+ * The scheme. Ex: "https://".
+ */
+ public String scheme() {
+ return scheme;
+ }
+
+ /**
+ * The scheme. Ex: "https://".
+ */
+ public BlobURLParts withScheme(String scheme) {
+ this.scheme = scheme;
+ return this;
+ }
+
+ /**
+ * The host. Ex: "account.blob.core.windows.net".
+ */
+ public String host() {
+ return host;
+ }
+
+ /**
+ * The host. Ex: "account.blob.core.windows.net".
+ */
+ public BlobURLParts withHost(String host) {
+ this.host = host;
+ return this;
+ }
+
+ /**
+ * The container name or {@code null} if a {@link StorageAsyncRawClient} was parsed.
+ */
+ public String containerName() {
+ return containerName;
+ }
+
+ /**
+ * The container name or {@code null} if a {@link StorageAsyncRawClient} was parsed.
+ */
+ public BlobURLParts withContainerName(String containerName) {
+ this.containerName = containerName;
+ return this;
+ }
+
+ /**
+ * The blob name or {@code null} if a {@link StorageAsyncRawClient} 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.
+ */
+ public BlobURLParts withBlobName(String blobName) {
+ this.blobName = blobName;
+ return this;
+ }
+
+ /**
+ * The snapshot time or {@code null} if anything except a URL to a snapshot was parsed.
+ */
+ public String snapshot() {
+ return snapshot;
+ }
+
+ /**
+ * The snapshot time or {@code null} if anything except a URL to a snapshot was parsed.
+ */
+ public BlobURLParts withSnapshot(String snapshot) {
+ this.snapshot = snapshot;
+ return this;
+ }
+
+ /**
+ * A {@link SASQueryParameters} representing the SAS query parameters or {@code null} if there were no such
+ * parameters.
+ */
+ public SASQueryParameters sasQueryParameters() {
+ return sasQueryParameters;
+ }
+
+ /**
+ * A {@link SASQueryParameters} representing the SAS query parameters or {@code null} if there were no such
+ * parameters.
+ */
+ public BlobURLParts withSasQueryParameters(SASQueryParameters sasQueryParameters) {
+ this.sasQueryParameters = sasQueryParameters;
+ return this;
+ }
+
+ /**
+ * The query parameter key value pairs aside from SAS parameters and snapshot time or {@code null} if there were
+ * no such parameters.
+ */
+ public Map unparsedParameters() {
+ return unparsedParameters;
+ }
+
+ /**
+ * The query parameter key value pairs aside from SAS parameters and snapshot time or {@code null} if there were
+ * no such parameters.
+ */
+ public BlobURLParts withUnparsedParameters(Map unparsedParameters) {
+ this.unparsedParameters = unparsedParameters;
+ return this;
+ }
+
+ /**
+ * Converts the blob URL parts to a {@link URL}.
+ *
+ * @return A {@code java.net.URL} to the blob resource composed of all the elements in the object.
+ *
+ * @throws MalformedURLException
+ * The fields present on the BlobURLParts object were insufficient to construct a valid URL or were
+ * ill-formatted.
+ */
+ public URL toURL() throws MalformedURLException {
+ UrlBuilder url = new UrlBuilder().withScheme(this.scheme).withHost(this.host);
+
+ StringBuilder path = new StringBuilder();
+ if (this.containerName != null) {
+ path.append(this.containerName);
+ if (this.blobName != null) {
+ path.append('/');
+ path.append(this.blobName);
+ }
+ }
+ url.withPath(path.toString());
+
+ if (this.snapshot != null) {
+ url.setQueryParameter(Constants.SNAPSHOT_QUERY_PARAMETER, this.snapshot);
+ }
+ if (this.sasQueryParameters != null) {
+ String encodedSAS = this.sasQueryParameters.encode();
+ if (encodedSAS.length() != 0) {
+ url.withQuery(encodedSAS);
+ }
+ }
+
+ for (Map.Entry entry : this.unparsedParameters.entrySet()) {
+ // The commas are intentionally encoded.
+ url.setQueryParameter(entry.getKey(),
+ Utility.safeURLEncode(String.join(",", entry.getValue())));
+ }
+
+ return url.toURL();
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlockBlobAsyncClient.java b/storage/client/src/main/java/com/azure/storage/blob/BlockBlobAsyncClient.java
new file mode 100644
index 0000000000000..617a8be812299
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlockBlobAsyncClient.java
@@ -0,0 +1,395 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import com.azure.core.http.rest.ResponseBase;
+import com.azure.core.util.Context;
+import com.azure.storage.blob.implementation.AzureBlobStorageImpl;
+import com.azure.storage.blob.models.BlobHTTPHeaders;
+import com.azure.storage.blob.models.BlockItem;
+import com.azure.storage.blob.models.BlockListType;
+import com.azure.storage.blob.models.LeaseAccessConditions;
+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;
+import reactor.netty.ByteBufFlux;
+
+import java.io.File;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.nio.file.Paths;
+import java.util.List;
+
+/**
+ * Client to a block blob. It may only be instantiated through a {@link BlockBlobClientBuilder}, via
+ * the method {@link BlobAsyncClient#asBlockBlobAsyncClient()}, or via the method
+ * {@link ContainerAsyncClient#getBlockBlobAsyncClient(String)}. This class does not hold
+ * any state about a particular blob, but is instead a convenient way of sending appropriate
+ * requests to the resource on the service.
+ *
+ *
+ * This client contains operations on a blob. Operations on a container are available on {@link ContainerAsyncClient},
+ * and operations on the service are available on {@link StorageAsyncClient}.
+ *
+ *
+ * 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()}.
+ */
+public final class BlockBlobAsyncClient extends BlobAsyncClient {
+
+ private BlockBlobAsyncRawClient blockBlobAsyncRawClient;
+
+ /**
+ * 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;
+
+ /**
+ * Package-private constructor for use by {@link BlockBlobClientBuilder}.
+ * @param azureBlobStorage the API client for blob storage API
+ */
+ BlockBlobAsyncClient(AzureBlobStorageImpl azureBlobStorage) {
+ super(azureBlobStorage);
+ blockBlobAsyncRawClient = new BlockBlobAsyncRawClient(azureBlobStorage);
+ }
+
+ /**
+ * Static method for getting a new builder for this class.
+ *
+ * @return
+ * A new {@link BlockBlobClientBuilder} instance.
+ */
+ public static BlockBlobClientBuilder builder() {
+ return new BlockBlobClientBuilder();
+ }
+
+ /**
+ * 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 Flux 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
+ * A reactive response containing the information of the uploaded block blob.
+ */
+ public Mono upload(Flux data, long length) {
+ return this.upload(data, length, null, 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 Flux 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}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response containing the information of the uploaded block blob.
+ */
+ public Mono upload(Flux data, long length, BlobHTTPHeaders headers,
+ Metadata metadata, BlobAccessConditions accessConditions, Context context) {
+ return blockBlobAsyncRawClient
+ .upload(data.map(Unpooled::wrappedBuffer), length, headers, metadata, accessConditions, context)
+ .then();
+ }
+
+ public Mono uploadFromFile(String filePath) {
+ return this.uploadFromFile(filePath, null, null, null, null);
+ }
+
+ public Mono uploadFromFile(String filePath, BlobHTTPHeaders headers, Metadata metadata,
+ BlobAccessConditions accessConditions, Context context) {
+ //TODO make this method smart
+ return this.blockBlobAsyncRawClient
+ .upload(ByteBufFlux.fromPath(Paths.get(filePath)), new File(filePath).length())
+ .then();
+ }
+
+ /**
+ * 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 Flux 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
+ * A reactive response signalling completion.
+ */
+ public Mono stageBlock(String base64BlockID, Flux data,
+ long length) {
+ return this.stageBlock(base64BlockID, data, length, null, 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 Flux 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response signalling completion.
+ */
+ public Mono stageBlock(String base64BlockID, Flux data, long length,
+ LeaseAccessConditions leaseAccessConditions, Context context) {
+ return blockBlobAsyncRawClient
+ .stageBlock(base64BlockID, data, length, leaseAccessConditions, context)
+ .then();
+ }
+
+ /**
+ * 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
+ * A reactive response signalling completion.
+ */
+ public Mono stageBlockFromURL(String base64BlockID, URL sourceURL,
+ BlobRange sourceRange) {
+ return this.stageBlockFromURL(base64BlockID, sourceURL, sourceRange, null,
+ 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}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response signalling completion.
+ */
+ public Mono stageBlockFromURL(String base64BlockID, URL sourceURL,
+ BlobRange sourceRange, byte[] sourceContentMD5, LeaseAccessConditions leaseAccessConditions,
+ SourceModifiedAccessConditions sourceModifiedAccessConditions, Context context) {
+ return blockBlobAsyncRawClient
+ .stageBlockFromURL(base64BlockID, sourceURL, sourceRange, sourceContentMD5, leaseAccessConditions, sourceModifiedAccessConditions, context)
+ .then();
+ }
+
+ /**
+ * 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
+ * A reactive response containing the list of blocks.
+ */
+ public Flux listBlocks(BlockListType listType) {
+ return this.listBlocks(listType, null, 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response containing the list of blocks.
+ */
+ public Flux listBlocks(BlockListType listType,
+ LeaseAccessConditions leaseAccessConditions, Context context) {
+ return blockBlobAsyncRawClient
+ .listBlocks(listType, leaseAccessConditions, context)
+ .map(ResponseBase::value)
+ .flatMapMany(bl -> {
+ Flux committed = Flux.fromIterable(bl.committedBlocks())
+ .map(block -> new BlockItem(block, true));
+ Flux uncommitted = Flux.fromIterable(bl.uncommittedBlocks())
+ .map(block -> new BlockItem(block, false));
+ return Flux.concat(committed, uncommitted);
+ });
+ }
+
+ /**
+ * 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
+ * A reactive response containing the information of the block blob.
+ */
+ public Mono commitBlockList(List base64BlockIDs) {
+ return this.commitBlockList(base64BlockIDs, null, 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}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * A reactive response containing the information of the block blob.
+ */
+ public Mono commitBlockList(List base64BlockIDs,
+ BlobHTTPHeaders headers, Metadata metadata, BlobAccessConditions accessConditions, Context context) {
+ return blockBlobAsyncRawClient
+ .commitBlockList(base64BlockIDs, headers, metadata, accessConditions, context)
+ .then();
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlockBlobAsyncRawClient.java b/storage/client/src/main/java/com/azure/storage/blob/BlockBlobAsyncRawClient.java
new file mode 100644
index 0000000000000..7c789842c05e5
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlockBlobAsyncRawClient.java
@@ -0,0 +1,394 @@
+// 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.core.util.Context;
+import com.azure.storage.blob.implementation.AzureBlobStorageImpl;
+import com.azure.storage.blob.models.*;
+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
+ */
+ public BlockBlobAsyncRawClient(AzureBlobStorageImpl azureBlobStorage) {
+ super(azureBlobStorage);
+ }
+
+
+ /**
+ * 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.
+ *
+ * For more efficient bulk-upload scenarios, please refer to the {@link TransferManager} for convenience methods.
+ *
+ * @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, 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.
+ *
+ * For more efficient bulk-upload scenarios, please refer to the {@link TransferManager} for convenience methods.
+ *
+ * @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}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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, Context context) {
+ metadata = metadata == null ? new Metadata() : metadata;
+ accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions;
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blockBlobs().uploadWithRestResponseAsync(null,
+ null, data, length, null, metadata, null, null,
+ null, null, headers, accessConditions.leaseAccessConditions(),
+ accessConditions.modifiedAccessConditions(), context));
+ }
+
+ /**
+ * 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, 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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, Context context) {
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blockBlobs().stageBlockWithRestResponseAsync(null,
+ null, base64BlockID, length, data, null, null, null,
+ null, null, null, leaseAccessConditions, context));
+ }
+
+ /**
+ * 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, 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}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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, Context context) {
+ sourceRange = sourceRange == null ? new BlobRange(0) : sourceRange;
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(
+ this.azureBlobStorage.blockBlobs().stageBlockFromURLWithRestResponseAsync(null, null,
+ base64BlockID, 0, sourceURL, sourceRange.toHeaderValue(), sourceContentMD5, null,
+ null, null, null, null,
+ leaseAccessConditions, sourceModifiedAccessConditions, context));
+ }
+
+ /**
+ * 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, 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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, Context context) {
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blockBlobs().getBlockListWithRestResponseAsync(
+ null, null, listType, null, null, null, null,
+ leaseAccessConditions, context));
+ }
+
+ /**
+ * 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.
+ *
+ * For more efficient bulk-upload scenarios, please refer to the {@link TransferManager} for convenience methods.
+ *
+ * @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, 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.
+ *
+ * For more efficient bulk-upload scenarios, please refer to the {@link TransferManager} for convenience methods.
+ *
+ * @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}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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, Context context) {
+ metadata = metadata == null ? new Metadata() : metadata;
+ accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions;
+ context = context == null ? Context.NONE : context;
+
+ return postProcessResponse(this.azureBlobStorage.blockBlobs().commitBlockListWithRestResponseAsync(
+ null, null, new BlockLookupList().latest(base64BlockIDs), null, metadata,
+ null, null, null, null, headers,
+ accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), context));
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlockBlobClient.java b/storage/client/src/main/java/com/azure/storage/blob/BlockBlobClient.java
new file mode 100644
index 0000000000000..9d2c6088deb73
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlockBlobClient.java
@@ -0,0 +1,398 @@
+// 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.BlobHTTPHeaders;
+import com.azure.storage.blob.models.BlockItem;
+import com.azure.storage.blob.models.BlockListType;
+import com.azure.storage.blob.models.LeaseAccessConditions;
+import com.azure.storage.blob.models.SourceModifiedAccessConditions;
+import io.netty.buffer.Unpooled;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.time.Duration;
+import java.util.List;
+
+/**
+ * Client to a block blob. It may only be instantiated through a {@link BlockBlobClientBuilder}, via
+ * the method {@link BlobClient#asBlockBlobClient()}, or via the method
+ * {@link ContainerClient#getBlockBlobClient(String)}. This class does not hold
+ * any state about a particular blob, but is instead a convenient way of sending appropriate
+ * requests to the resource on the service.
+ *
+ *
+ * This client contains operations on a blob. Operations on a container are available on {@link ContainerClient},
+ * and operations on the service are available on {@link StorageClient}.
+ *
+ *
+ * Please refer to the Azure Docs
+ * for more information.
+ */
+public final class BlockBlobClient extends BlobClient {
+
+ 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;
+
+ /**
+ * 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;
+
+ /**
+ * Package-private constructor for use by {@link BlockBlobClientBuilder}.
+ * @param azureBlobStorage the API client for blob storage API
+ */
+ BlockBlobClient(AzureBlobStorageImpl azureBlobStorage) {
+ super(azureBlobStorage);
+ this.blockBlobAsyncClient = new BlockBlobAsyncClient(azureBlobStorage);
+ }
+
+ /**
+ * Static method for getting a new builder for this class.
+ *
+ * @return
+ * A new {@link BlockBlobClientBuilder} instance.
+ */
+ public static BlockBlobClientBuilder blockBlobClientBuilder() {
+ return new BlockBlobClientBuilder();
+ }
+
+ /**
+ * 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.
+ *
+ * @param data
+ * The data to write to the blob.
+ * @param length
+ * The exact length of the data. It is important that this value match precisely the length of the data
+ * provided in the {@link InputStream}.
+ *
+ * @return
+ * The information of the uploaded block blob.
+ */
+ public void upload(InputStream data, long length) throws IOException {
+ this.upload(data, length, null, null, 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.
+ *
+ * @param data
+ * The data to write to the blob.
+ * @param length
+ * The exact length of the data. It is important that this value match precisely the length of the data
+ * provided in the {@link InputStream}.
+ * @param headers
+ * {@link BlobHTTPHeaders}
+ * @param metadata
+ * {@link Metadata}
+ * @param accessConditions
+ * {@link BlobAccessConditions}
+ * @param timeout
+ * An optional timeout value beyond which a {@link RuntimeException} will be raised.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * The information of the uploaded block blob.
+ */
+ public void upload(InputStream data, long length, BlobHTTPHeaders headers,
+ Metadata metadata, BlobAccessConditions accessConditions, Duration timeout, Context context) throws IOException {
+
+ // buffer strategy for UX study only
+ byte[] bufferedData = new byte[(int)length];
+ data.read(bufferedData);
+
+ Mono upload = blockBlobAsyncClient
+ .upload(Flux.just(ByteBuffer.wrap(bufferedData)), length, headers, metadata, accessConditions, context);
+
+ try {
+ if (timeout == null) {
+ upload.block();
+ } else {
+ upload.block(timeout);
+ }
+ }
+ catch (UncheckedIOException e) {
+ throw e.getCause();
+ }
+ }
+
+ public void uploadFromFile(String filePath) throws IOException {
+ this.uploadFromFile(filePath, null, null, null, null);
+ }
+
+ public void uploadFromFile(String filePath, BlobHTTPHeaders headers, Metadata metadata,
+ BlobAccessConditions accessConditions, Duration timeout) throws IOException {
+ Mono upload = this.blockBlobAsyncClient.uploadFromFile(filePath, headers, metadata, accessConditions, null);
+
+ try {
+ if (timeout == null) {
+ upload.block();
+ } else {
+ upload.block(timeout);
+ }
+ }
+ catch (UncheckedIOException e) {
+ throw e.getCause();
+ }
+ }
+
+ /**
+ * 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.
+ *
+ * @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.
+ * @param length
+ * The exact length of the data. It is important that this value match precisely the length of the data
+ * provided in the {@link InputStream}.
+ */
+ public void stageBlock(String base64BlockID, InputStream data, long length) throws IOException {
+ this.stageBlock(base64BlockID, data, length, null, null, 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.
+ *
+ * @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.
+ * @param length
+ * The exact length of the data. It is important that this value match precisely the length of the data
+ * provided in the {@link InputStream}.
+ * @param leaseAccessConditions
+ * By setting lease access conditions, requests will fail if the provided lease does not match the active
+ * lease on the blob.
+ * @param timeout
+ * An optional timeout value beyond which a {@link RuntimeException} will be raised.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ */
+ public void stageBlock(String base64BlockID, InputStream data, long length,
+ LeaseAccessConditions leaseAccessConditions, Duration timeout, Context context) throws IOException {
+
+ // buffer strategy for UX study only
+ byte[] bufferedData = new byte[(int)length];
+ data.read(bufferedData);
+
+ Mono response = blockBlobAsyncClient.stageBlock(base64BlockID,
+ Flux.just(Unpooled.wrappedBuffer(bufferedData)), length, leaseAccessConditions, context);
+ if (timeout == null) {
+ response.block();
+ } else {
+ response.block(timeout);
+ }
+ }
+
+ /**
+ * 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}
+ */
+ public void stageBlockFromURL(String base64BlockID, URL sourceURL,
+ BlobRange sourceRange) {
+ this.stageBlockFromURL(base64BlockID, sourceURL, sourceRange, null,
+ null, 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}
+ * @param timeout
+ * An optional timeout value beyond which a {@link RuntimeException} will be raised.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ */
+ public void stageBlockFromURL(String base64BlockID, URL sourceURL,
+ BlobRange sourceRange, byte[] sourceContentMD5, LeaseAccessConditions leaseAccessConditions,
+ SourceModifiedAccessConditions sourceModifiedAccessConditions, Duration timeout, Context context) {
+ Mono response = blockBlobAsyncClient.stageBlockFromURL(base64BlockID, sourceURL, sourceRange, sourceContentMD5, leaseAccessConditions, sourceModifiedAccessConditions, context);
+ if (timeout == null) {
+ response.block();
+ } else {
+ response.block(timeout);
+ }
+ }
+
+ /**
+ * 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
+ * The list of blocks.
+ */
+ public Iterable listBlocks(BlockListType listType) {
+ return this.listBlocks(listType, null, null, 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.
+ * @param timeout
+ * An optional timeout value beyond which a {@link RuntimeException} will be raised.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * The list of blocks.
+ */
+ public Iterable listBlocks(BlockListType listType,
+ LeaseAccessConditions leaseAccessConditions, Duration timeout, Context context) {
+ Flux response = blockBlobAsyncClient.listBlocks(listType, leaseAccessConditions, context);
+
+ return timeout == null?
+ response.toIterable():
+ response.timeout(timeout).toIterable();
+ }
+
+ /**
+ * 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
+ * The information of the block blob.
+ */
+ public void commitBlockList(List base64BlockIDs) {
+ this.commitBlockList(base64BlockIDs, null, null, 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}
+ * @param timeout
+ * An optional timeout value beyond which a {@link RuntimeException} will be raised.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @return
+ * The information of the block blob.
+ */
+ public void commitBlockList(List base64BlockIDs,
+ BlobHTTPHeaders headers, Metadata metadata, BlobAccessConditions accessConditions, Duration timeout, Context context) {
+ Mono response = blockBlobAsyncClient.commitBlockList(base64BlockIDs, headers, metadata, accessConditions, context);
+
+ if (timeout == null) {
+ response.block();
+ } else {
+ response.block(timeout);
+ }
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlockBlobClientBuilder.java b/storage/client/src/main/java/com/azure/storage/blob/BlockBlobClientBuilder.java
new file mode 100644
index 0000000000000..5e9798253d854
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlockBlobClientBuilder.java
@@ -0,0 +1,220 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import com.azure.core.configuration.Configuration;
+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.util.ImplUtils;
+import com.azure.storage.blob.implementation.AzureBlobStorageBuilder;
+import com.azure.storage.blob.implementation.AzureBlobStorageImpl;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Fluent BlockBlobClientBuilder for instantiating a {@link BlockBlobClient} or {@link BlockBlobAsyncClient}.
+ *
+ *
+ * An instance of this builder may only be created from static method {@link BlockBlobClient#blockBlobClientBuilder()}.
+ * The following information must be provided on this builder:
+ *
+ *
+ * - the endpoint through {@code .endpoint()}, including the container name and blob name, in the format of {@code https://{accountName}.blob.core.windows.net/{containerName}/{blobName}}.
+ *
- the credential through {@code .credentials()} or {@code .connectionString()} if the container is not publicly accessible.
+ *
+ *
+ *
+ * Once all the configurations are set on this builder, call {@code .buildClient()} to create a
+ * {@link BlockBlobClient} or {@code .buildAsyncClient()} to create a {@link BlockBlobAsyncClient}.
+ */
+public final class BlockBlobClientBuilder {
+ private static final String ACCOUNT_NAME = "AccountName".toLowerCase();
+ private static final String ACCOUNT_KEY = "AccountKey".toLowerCase();
+
+ private final List policies;
+
+ private URL endpoint;
+ private ICredentials credentials = new AnonymousCredentials();
+ private HttpClient httpClient;
+ private HttpLogDetailLevel logLevel;
+ private RetryPolicy retryPolicy;
+ private Configuration configuration;
+
+ public BlockBlobClientBuilder() {
+ retryPolicy = new RetryPolicy();
+ logLevel = HttpLogDetailLevel.NONE;
+ policies = new ArrayList<>();
+ }
+
+ /**
+ * Constructs an instance of BlockBlobAsyncClient based on the configurations stored in the appendBlobClientBuilder.
+ * @return a new client instance
+ */
+ private AzureBlobStorageImpl buildImpl() {
+ Objects.requireNonNull(endpoint);
+
+ // Closest to API goes first, closest to wire goes last.
+ final List policies = new ArrayList<>();
+
+ policies.add(new UserAgentPolicy(BlobConfiguration.NAME, BlobConfiguration.VERSION));
+ policies.add(new RequestIdPolicy());
+ policies.add(new AddDatePolicy());
+ policies.add(credentials); // This needs to be a different credential type.
+
+ policies.add(retryPolicy);
+
+ policies.addAll(this.policies);
+ policies.add(new HttpLoggingPolicy(logLevel));
+
+ HttpPipeline pipeline = HttpPipeline.builder()
+ .policies(policies.toArray(new HttpPipelinePolicy[0]))
+ .httpClient(httpClient)
+ .build();
+
+ return new AzureBlobStorageBuilder()
+ .url(endpoint.toString())
+ .pipeline(pipeline)
+ .build();
+ }
+
+ /**
+ * @return a {@link BlockBlobClient} created from the configurations in this builder.
+ */
+ public BlockBlobClient buildClient() {
+ return new BlockBlobClient(buildImpl());
+ }
+
+ /**
+ * @return a {@link BlockBlobAsyncClient} created from the configurations in this builder.
+ */
+ public BlockBlobAsyncClient buildAsyncClient() {
+ return new BlockBlobAsyncClient(buildImpl());
+ }
+
+ /**
+ * Sets the service endpoint, additionally parses it for information (SAS token, container name)
+ * @param endpoint URL of the service
+ * @return the updated BlockBlobClientBuilder object
+ */
+ public BlockBlobClientBuilder endpoint(String endpoint) {
+ Objects.requireNonNull(endpoint);
+ try {
+ this.endpoint = new URL(endpoint);
+ } catch (MalformedURLException ex) {
+ throw new IllegalArgumentException("The Azure Storage Queue endpoint url is malformed.");
+ }
+
+ return this;
+ }
+
+ /**
+ * Sets the credentials used to authorize requests sent to the service
+ * @param credentials authorization credentials
+ * @return the updated BlockBlobClientBuilder object
+ */
+ public BlockBlobClientBuilder credentials(SharedKeyCredentials credentials) {
+ this.credentials = credentials;
+ return this;
+ }
+
+ /**
+ * Sets the credentials used to authorize requests sent to the service
+ * @param credentials authorization credentials
+ * @return the updated BlockBlobClientBuilder object
+ */
+ public BlockBlobClientBuilder credentials(TokenCredentials credentials) {
+ this.credentials = credentials;
+ return this;
+ }
+
+ /**
+ * Clears the credentials used to authorize requests sent to the service
+ * @return the updated BlockBlobClientBuilder object
+ */
+ public BlockBlobClientBuilder anonymousCredentials() {
+ this.credentials = new AnonymousCredentials();
+ return this;
+ }
+
+ /**
+ * Sets the connection string for the service, parses it for authentication information (account name, account key)
+ * @param connectionString connection string from access keys section
+ * @return the updated BlockBlobClientBuilder object
+ */
+ public BlockBlobClientBuilder connectionString(String connectionString) {
+ Objects.requireNonNull(connectionString);
+
+ Map connectionKVPs = new HashMap<>();
+ for (String s : connectionString.split(";")) {
+ String[] kvp = s.split("=", 2);
+ connectionKVPs.put(kvp[0].toLowerCase(), kvp[1]);
+ }
+
+ String accountName = connectionKVPs.get(ACCOUNT_NAME);
+ String accountKey = connectionKVPs.get(ACCOUNT_KEY);
+
+ if (ImplUtils.isNullOrEmpty(accountName) || ImplUtils.isNullOrEmpty(accountKey)) {
+ throw new IllegalArgumentException("Connection string must contain 'AccountName' and 'AccountKey'.");
+ }
+
+ // Use accountName and accountKey to get the SAS token using the credential class.
+ credentials = new SharedKeyCredentials(accountName, accountKey);
+
+ return this;
+ }
+
+ /**
+ * Sets the http client used to send service requests
+ * @param httpClient http client to send requests
+ * @return the updated BlockBlobClientBuilder object
+ */
+ public BlockBlobClientBuilder httpClient(HttpClient httpClient) {
+ this.httpClient = httpClient;
+ return this;
+ }
+
+ /**
+ * Adds a pipeline policy to apply on each request sent
+ * @param pipelinePolicy a pipeline policy
+ * @return the updated BlockBlobClientBuilder object
+ */
+ public BlockBlobClientBuilder addPolicy(HttpPipelinePolicy pipelinePolicy) {
+ this.policies.add(pipelinePolicy);
+ return this;
+ }
+
+ /**
+ * Sets the logging level for service requests
+ * @param logLevel logging level
+ * @return the updated BlockBlobClientBuilder object
+ */
+ public BlockBlobClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) {
+ this.logLevel = logLevel;
+ return this;
+ }
+
+ /**
+ * Sets the configuration object used to retrieve environment configuration values used to buildClient the client with
+ * when they are not set in the appendBlobClientBuilder, defaults to Configuration.NONE
+ * @param configuration configuration store
+ * @return the updated BlockBlobClientBuilder object
+ */
+ public BlockBlobClientBuilder configuration(Configuration configuration) {
+ this.configuration = configuration;
+ return this;
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/BlockBlobRawClient.java b/storage/client/src/main/java/com/azure/storage/blob/BlockBlobRawClient.java
new file mode 100644
index 0000000000000..07260ffa53f63
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/BlockBlobRawClient.java
@@ -0,0 +1,379 @@
+// 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.core.util.Context;
+import com.azure.storage.blob.implementation.AzureBlobStorageImpl;
+import com.azure.storage.blob.models.*;
+import io.netty.buffer.ByteBuf;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.net.URL;
+import java.time.Duration;
+import java.util.List;
+
+/**
+ * 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 BlockBlobRawClient extends BlobAsyncRawClient {
+
+ private BlockBlobAsyncRawClient blockBlobAsyncRawClient;
+ /**
+ * 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
+ */
+ BlockBlobRawClient(AzureBlobStorageImpl azureBlobStorage) {
+ super(azureBlobStorage);
+ this.blockBlobAsyncRawClient = new BlockBlobAsyncRawClient(azureBlobStorage);
+ }
+
+ /**
+ * 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.
+ *
+ * For more efficient bulk-upload scenarios, please refer to the {@link TransferManager} for convenience methods.
+ *
+ * @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 BlockBlobsUploadResponse upload(Flux data, long length) {
+ return this.upload(data, length, null, null, 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.
+ *
+ * For more efficient bulk-upload scenarios, please refer to the {@link TransferManager} for convenience methods.
+ *
+ * @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}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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 BlockBlobsUploadResponse upload(Flux data, long length, BlobHTTPHeaders headers,
+ Metadata metadata, BlobAccessConditions accessConditions, Duration timeout, Context context) {
+ Mono response = blockBlobAsyncRawClient.upload(data, length, headers, metadata, accessConditions, context);
+ return timeout == null?
+ response.block():
+ response.block(timeout);
+ }
+
+ /**
+ * 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 BlockBlobsStageBlockResponse stageBlock(String base64BlockID, Flux data, long length) {
+ return this.stageBlock(base64BlockID, data, length, null, null, 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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 BlockBlobsStageBlockResponse stageBlock(String base64BlockID, Flux data, long length,
+ LeaseAccessConditions leaseAccessConditions, Duration timeout, Context context) {
+ Mono response = blockBlobAsyncRawClient.stageBlock(base64BlockID, data, length, leaseAccessConditions, context);
+ return timeout == null?
+ response.block():
+ response.block(timeout);
+ }
+
+ /**
+ * 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 BlockBlobsStageBlockFromURLResponse stageBlockFromURL(String base64BlockID, URL sourceURL,
+ BlobRange sourceRange) {
+ return this.stageBlockFromURL(base64BlockID, sourceURL, sourceRange, null,
+ null, 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}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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 BlockBlobsStageBlockFromURLResponse stageBlockFromURL(String base64BlockID, URL sourceURL,
+ BlobRange sourceRange, byte[] sourceContentMD5, LeaseAccessConditions leaseAccessConditions,
+ SourceModifiedAccessConditions sourceModifiedAccessConditions, Duration timeout, Context context) {
+ Mono response = blockBlobAsyncRawClient.stageBlockFromURL(base64BlockID, sourceURL, sourceRange, sourceContentMD5, leaseAccessConditions, sourceModifiedAccessConditions, context);
+ return timeout == null?
+ response.block():
+ response.block(timeout);
+ }
+
+ /**
+ * 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 BlockBlobsGetBlockListResponse getBlockList(BlockListType listType) {
+ return this.getBlockList(listType, null, null, 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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 BlockBlobsGetBlockListResponse getBlockList(BlockListType listType,
+ LeaseAccessConditions leaseAccessConditions, Duration timeout, Context context) {
+ Mono response = blockBlobAsyncRawClient.listBlocks(listType, leaseAccessConditions, context);
+ return timeout == null?
+ response.block():
+ response.block(timeout);
+ }
+
+ /**
+ * 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.
+ *
+ * For more efficient bulk-upload scenarios, please refer to the {@link TransferManager} for convenience methods.
+ *
+ * @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 BlockBlobsCommitBlockListResponse commitBlockList(List base64BlockIDs) {
+ return this.commitBlockList(base64BlockIDs, null, null, 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.
+ *
+ * For more efficient bulk-upload scenarios, please refer to the {@link TransferManager} for convenience methods.
+ *
+ * @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}
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to
+ * its parent, forming a linked list.
+ *
+ * @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 BlockBlobsCommitBlockListResponse commitBlockList(List base64BlockIDs,
+ BlobHTTPHeaders headers, Metadata metadata, BlobAccessConditions accessConditions, Duration timeout, Context context) {
+ Mono response = blockBlobAsyncRawClient.commitBlockList(base64BlockIDs, headers, metadata, accessConditions, context);
+ return timeout == null?
+ response.block():
+ response.block(timeout);
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/CommonRestResponse.java b/storage/client/src/main/java/com/azure/storage/blob/CommonRestResponse.java
new file mode 100644
index 0000000000000..38a68dbd41b6e
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/CommonRestResponse.java
@@ -0,0 +1,110 @@
+// 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.models.BlockBlobsCommitBlockListResponse;
+import com.azure.storage.blob.models.BlockBlobsUploadResponse;
+
+import java.time.OffsetDateTime;
+
+/**
+ * A generic wrapper for any type of blob REST API response. Used and returned by methods in the {@link TransferManager}
+ * class. The methods there return this type because they represent composite operations which may conclude with any of
+ * several possible REST calls depending on the data provided.
+ */
+final class CommonRestResponse {
+
+ private BlockBlobsUploadResponse uploadBlobResponse;
+
+ private BlockBlobsCommitBlockListResponse commitBlockListResponse;
+
+ private CommonRestResponse() {
+ uploadBlobResponse = null;
+ commitBlockListResponse = null;
+ }
+
+ static CommonRestResponse createFromPutBlobResponse(BlockBlobsUploadResponse response) {
+ CommonRestResponse commonRestResponse = new CommonRestResponse();
+ commonRestResponse.uploadBlobResponse = response;
+ return commonRestResponse;
+ }
+
+ static CommonRestResponse createFromPutBlockListResponse(BlockBlobsCommitBlockListResponse response) {
+ CommonRestResponse commonRestResponse = new CommonRestResponse();
+ commonRestResponse.commitBlockListResponse = response;
+ return commonRestResponse;
+ }
+
+ /**
+ * @return The status code for the response
+ */
+ public int statusCode() {
+ if (uploadBlobResponse != null) {
+ return uploadBlobResponse.statusCode();
+ }
+ return commitBlockListResponse.statusCode();
+ }
+
+ /**
+ * @return An HTTP Etag for the blob at the time of the request.
+ */
+ public String eTag() {
+ if (uploadBlobResponse != null) {
+ return uploadBlobResponse.deserializedHeaders().eTag();
+ }
+ return commitBlockListResponse.deserializedHeaders().eTag();
+ }
+
+ /**
+ * @return The time when the blob was last modified.
+ */
+ public OffsetDateTime lastModified() {
+ if (uploadBlobResponse != null) {
+ return uploadBlobResponse.deserializedHeaders().lastModified();
+ }
+ return commitBlockListResponse.deserializedHeaders().lastModified();
+ }
+
+ /**
+ * @return The id of the service request for which this is the response.
+ */
+ public String requestId() {
+ if (uploadBlobResponse != null) {
+ return uploadBlobResponse.deserializedHeaders().requestId();
+ }
+ return commitBlockListResponse.deserializedHeaders().requestId();
+ }
+
+ /**
+ * @return The date of the response.
+ */
+ public OffsetDateTime date() {
+ if (uploadBlobResponse != null) {
+ return uploadBlobResponse.deserializedHeaders().dateProperty();
+ }
+ return commitBlockListResponse.deserializedHeaders().dateProperty();
+ }
+
+ /**
+ * @return The service version responding to the request.
+ */
+ public String version() {
+ if (uploadBlobResponse != null) {
+ return uploadBlobResponse.deserializedHeaders().version();
+ }
+ return commitBlockListResponse.deserializedHeaders().version();
+ }
+
+ /**
+ * @return The underlying response.
+ */
+ public Response response() {
+ if (uploadBlobResponse != null) {
+ return uploadBlobResponse;
+ }
+ return commitBlockListResponse;
+ }
+
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/Constants.java b/storage/client/src/main/java/com/azure/storage/blob/Constants.java
new file mode 100644
index 0000000000000..a7b0d3e145c3f
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/Constants.java
@@ -0,0 +1,299 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+/**
+ * RESERVED FOR INTERNAL USE. Contains storage constants.
+ */
+final class Constants {
+
+ /**
+ * The master Microsoft Azure Storage header prefix.
+ */
+ static final String PREFIX_FOR_STORAGE_HEADER = "x-ms-";
+ /**
+ * Constant representing a kilobyte (Non-SI version).
+ */
+ static final int KB = 1024;
+ /**
+ * Constant representing a megabyte (Non-SI version).
+ */
+ static final int MB = 1024 * KB;
+ /**
+ * An empty {@code String} to use for comparison.
+ */
+ static final String EMPTY_STRING = "";
+ /**
+ * Specifies HTTP.
+ */
+ static final String HTTP = "http";
+ /**
+ * Specifies HTTPS.
+ */
+ static final String HTTPS = "https";
+ /**
+ * Specifies both HTTPS and HTTP.
+ */
+ static final String HTTPS_HTTP = "https,http";
+ /**
+ * The default type for content-type and accept.
+ */
+ static final String UTF8_CHARSET = "UTF-8";
+ /**
+ * The query parameter for snapshots.
+ */
+ static final String SNAPSHOT_QUERY_PARAMETER = "snapshot";
+ /**
+ * The word redacted.
+ */
+ static final String REDACTED = "REDACTED";
+ /**
+ * The default amount of parallelism for TransferManager operations.
+ */
+ // We chose this to match Go, which followed AWS' default.
+ static final int TRANSFER_MANAGER_DEFAULT_PARALLELISM = 5;
+
+ /**
+ * Private Default Ctor
+ */
+ private Constants() {
+ // Private to prevent construction.
+ }
+
+ /**
+ * Defines constants for use with HTTP headers.
+ */
+ static final class HeaderConstants {
+ /**
+ * The Authorization header.
+ */
+ static final String AUTHORIZATION = "Authorization";
+
+ /**
+ * The format string for specifying ranges with only begin offset.
+ */
+ static final String BEGIN_RANGE_HEADER_FORMAT = "bytes=%d-";
+
+ /**
+ * The header that indicates the client request ID.
+ */
+ static final String CLIENT_REQUEST_ID_HEADER = PREFIX_FOR_STORAGE_HEADER + "client-request-id";
+
+ /**
+ * The ContentEncoding header.
+ */
+ static final String CONTENT_ENCODING = "Content-Encoding";
+
+ /**
+ * The ContentLangauge header.
+ */
+ static final String CONTENT_LANGUAGE = "Content-Language";
+
+ /**
+ * The ContentLength header.
+ */
+ static final String CONTENT_LENGTH = "Content-Length";
+
+ /**
+ * The ContentMD5 header.
+ */
+ static final String CONTENT_MD5 = "Content-MD5";
+
+ /**
+ * The ContentType header.
+ */
+ static final String CONTENT_TYPE = "Content-Type";
+
+ /**
+ * The header that specifies the date.
+ */
+ static final String DATE = PREFIX_FOR_STORAGE_HEADER + "date";
+
+ /**
+ * The header that specifies the error code on unsuccessful responses.
+ */
+ static final String ERROR_CODE = PREFIX_FOR_STORAGE_HEADER + "error-code";
+
+ /**
+ * The IfMatch header.
+ */
+ static final String IF_MATCH = "If-Match";
+
+ /**
+ * The IfModifiedSince header.
+ */
+ static final String IF_MODIFIED_SINCE = "If-Modified-Since";
+
+ /**
+ * The IfNoneMatch header.
+ */
+ static final String IF_NONE_MATCH = "If-None-Match";
+
+ /**
+ * The IfUnmodifiedSince header.
+ */
+ static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since";
+
+ /**
+ * The Range header.
+ */
+ static final String RANGE = "Range";
+
+ /**
+ * The format string for specifying ranges.
+ */
+ static final String RANGE_HEADER_FORMAT = "bytes=%d-%d";
+
+ /**
+ * The copy source header.
+ */
+ static final String COPY_SOURCE = "x-ms-copy-source";
+
+ /**
+ * The version header.
+ */
+ static final String VERSION = "x-ms-version";
+
+ /**
+ * The current storage version header value.
+ */
+ static final String TARGET_STORAGE_VERSION = "2018-11-09";
+
+ /**
+ * The UserAgent header.
+ */
+ static final String USER_AGENT = "User-Agent";
+
+ /**
+ * Specifies the value to use for UserAgent header.
+ */
+ static final String USER_AGENT_PREFIX = "Azure-Storage";
+
+ /**
+ * Specifies the value to use for UserAgent header.
+ */
+ static final String USER_AGENT_VERSION = "11.0.1";
+
+ private HeaderConstants() {
+ // Private to prevent construction.
+ }
+ }
+
+ static final class UrlConstants {
+
+ /**
+ * The SAS service version parameter.
+ */
+ static final String SAS_SERVICE_VERSION = "sv";
+
+ /**
+ * The SAS services parameter.
+ */
+ static final String SAS_SERVICES = "ss";
+
+ /**
+ * The SAS resource types parameter.
+ */
+ static final String SAS_RESOURCES_TYPES = "srt";
+
+ /**
+ * The SAS protocol parameter.
+ */
+ static final String SAS_PROTOCOL = "spr";
+
+ /**
+ * The SAS start time parameter.
+ */
+ static final String SAS_START_TIME = "st";
+
+ /**
+ * The SAS expiration time parameter.
+ */
+ static final String SAS_EXPIRY_TIME = "se";
+
+ /**
+ * The SAS IP range parameter.
+ */
+ static final String SAS_IP_RANGE = "sip";
+
+ /**
+ * The SAS signed identifier parameter.
+ */
+ static final String SAS_SIGNED_IDENTIFIER = "si";
+
+ /**
+ * The SAS signed resource parameter.
+ */
+ static final String SAS_SIGNED_RESOURCE = "sr";
+
+ /**
+ * The SAS signed permissions parameter.
+ */
+ static final String SAS_SIGNED_PERMISSIONS = "sp";
+
+ /**
+ * The SAS signature parameter.
+ */
+ static final String SAS_SIGNATURE = "sig";
+
+ /**
+ * The SAS cache control parameter.
+ */
+ static final String SAS_CACHE_CONTROL = "rscc";
+
+ /**
+ * The SAS content disposition parameter.
+ */
+ static final String SAS_CONTENT_DISPOSITION = "rscd";
+
+ /**
+ * The SAS content encoding parameter.
+ */
+ static final String SAS_CONTENT_ENCODING = "rsce";
+
+ /**
+ * The SAS content language parameter.
+ */
+ static final String SAS_CONTENT_LANGUAGE = "rscl";
+
+ /**
+ * The SAS content type parameter.
+ */
+ static final String SAS_CONTENT_TYPE = "rsct";
+
+ /**
+ * The SAS signed object id parameter for user delegation SAS.
+ */
+ public static final String SAS_SIGNED_OBJECT_ID = "skoid";
+
+ /**
+ * The SAS signed tenant id parameter for user delegation SAS.
+ */
+ public static final String SAS_SIGNED_TENANT_ID = "sktid";
+
+ /**
+ * The SAS signed key-start parameter for user delegation SAS.
+ */
+ public static final String SAS_SIGNED_KEY_START = "skt";
+
+ /**
+ * The SAS signed key-expiry parameter for user delegation SAS.
+ */
+ public static final String SAS_SIGNED_KEY_EXPIRY = "ske";
+
+ /**
+ * The SAS signed service parameter for user delegation SAS.
+ */
+ public static final String SAS_SIGNED_KEY_SERVICE = "sks";
+
+ /**
+ * The SAS signed version parameter for user delegation SAS.
+ */
+ public static final String SAS_SIGNED_KEY_VERSION = "skv";
+
+ private UrlConstants() {
+ // Private to prevent construction.
+ }
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/ContainerAccessConditions.java b/storage/client/src/main/java/com/azure/storage/blob/ContainerAccessConditions.java
new file mode 100644
index 0000000000000..f2b9ca1c04f5e
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/ContainerAccessConditions.java
@@ -0,0 +1,64 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import com.azure.storage.blob.models.LeaseAccessConditions;
+import com.azure.storage.blob.models.ModifiedAccessConditions;
+
+/**
+ * This class contains values which will restrict the successful operation of a variety of requests to the conditions
+ * present. These conditions are entirely optional. The entire object or any of its properties may be set to null when
+ * passed to a method to indicate that those conditions are not desired. Please refer to the type of each field for more
+ * information on those particular access conditions.
+ */
+public final class ContainerAccessConditions {
+
+ private ModifiedAccessConditions modifiedAccessConditions;
+
+ private LeaseAccessConditions leaseAccessConditions;
+
+ /**
+ * Creates an instance which has fields set to non-null, empty values.
+ */
+ public ContainerAccessConditions() {
+ this.modifiedAccessConditions = new ModifiedAccessConditions();
+ this.leaseAccessConditions = new LeaseAccessConditions();
+ }
+
+ /**
+ * 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.
+ */
+ public ModifiedAccessConditions modifiedAccessConditions() {
+ return 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.
+ */
+ public ContainerAccessConditions withModifiedAccessConditions(ModifiedAccessConditions modifiedAccessConditions) {
+ this.modifiedAccessConditions = modifiedAccessConditions;
+ return this;
+ }
+
+ /**
+ * By setting lease access conditions, requests will fail if the provided lease does not match the active lease on
+ * the blob.
+ */
+ public LeaseAccessConditions leaseAccessConditions() {
+ return leaseAccessConditions;
+ }
+
+ /**
+ * By setting lease access conditions, requests will fail if the provided lease does not match the active lease on
+ * the blob.
+ */
+ public ContainerAccessConditions withLeaseAccessConditions(LeaseAccessConditions leaseID) {
+ this.leaseAccessConditions = leaseID;
+ return this;
+ }
+}
diff --git a/storage/client/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java b/storage/client/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java
new file mode 100644
index 0000000000000..447501a3666cb
--- /dev/null
+++ b/storage/client/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java
@@ -0,0 +1,759 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.storage.blob;
+
+import com.azure.core.http.rest.ResponseBase;
+import com.azure.core.util.Context;
+import com.azure.storage.blob.models.BlobItem;
+import com.azure.storage.blob.models.ContainerGetAccessPolicyHeaders;
+import com.azure.storage.blob.models.ContainersListBlobFlatSegmentResponse;
+import com.azure.storage.blob.models.LeaseAccessConditions;
+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.Flux;
+import reactor.core.publisher.Mono;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+
+/**
+ * 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.
+ *
+ *
+ * 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;
+ private ContainerClientBuilder builder;
+
+ 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";
+
+ /**
+ * Package-private constructor for use by {@link ContainerClientBuilder}.
+ * @param builder the container client builder
+ */
+ ContainerAsyncClient(ContainerClientBuilder builder) {
+ this.builder = builder;
+ this.containerAsyncRawClient = new ContainerAsyncRawClient(builder.buildImpl());
+ }
+
+ /**
+ * @return a new client {@link ContainerClientBuilder} instance.
+ */
+ public static ContainerClientBuilder containerClientBuilder() {
+ return new ContainerClientBuilder();
+ }
+
+ /**
+ * 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.
+ */
+ public BlockBlobAsyncClient getBlockBlobAsyncClient(String blobName) {
+ try {
+ return new BlockBlobAsyncClient(this.builder.copyBuilder().endpoint(Utility.appendToURLPath(new URL(builder.endpoint()), blobName).toString()).buildImpl());
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * 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) {
+ try {
+ return new PageBlobAsyncClient(this.builder.copyBuilder().endpoint(Utility.appendToURLPath(new URL(builder.endpoint()), blobName).toString()).buildImpl());
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * 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.
+ */
+ public AppendBlobAsyncClient getAppendBlobAsyncClient(String blobName) {
+ try {
+ return new AppendBlobAsyncClient(this.builder.copyBuilder().endpoint(Utility.appendToURLPath(new URL(builder.endpoint()), blobName).toString()).buildImpl());
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * 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) {
+ try {
+ return new BlobAsyncClient(this.builder.copyBuilder().endpoint(Utility.appendToURLPath(new URL(builder.endpoint()), blobName).toString()).buildImpl());
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * 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 reactive response signalling completion.
+ */
+ public Mono 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.
+ * @param context
+ * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an
+ * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass
+ * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is
+ * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to its
+ * parent, forming a linked list.
+ *
+ * @return
+ * A reactive response signalling completion.
+ */
+ public Mono create(Metadata metadata, PublicAccessType accessType, Context context) {
+ return containerAsyncRawClient
+ .create(metadata, accessType, context)
+ .then();
+ }
+
+ /**
+ * 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.
+ */
+ public Mono 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
+ *