Skip to content

Commit 8063e98

Browse files
authored
Implemented features for STG 76 (Azure#18679)
1 parent 443fbfd commit 8063e98

File tree

590 files changed

+37086
-27896
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

590 files changed

+37086
-27896
lines changed

eng/code-quality-reports/src/main/resources/revapi/revapi.json

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,20 @@
269269
"code": "java.annotation.added",
270270
"new": "class com.azure.storage.blob.models.PageList",
271271
"justification": "Annotation required to resolve deserialization bug."
272-
},{
272+
},
273+
{
274+
"code": "java.annotation.attributeValueChanged",
275+
"old": "class com.azure.storage.file.share.models.ShareProtocolSettings",
276+
"new": "class com.azure.storage.file.share.models.ShareProtocolSettings",
277+
"justification": "Annotation required to resolve a swagger error. The value is now correct."
278+
},
279+
{
280+
"code": "java.annotation.attributeValueChanged",
281+
"old": "class com.azure.storage.file.share.models.ShareSmbSettings",
282+
"new": "class com.azure.storage.file.share.models.ShareSmbSettings",
283+
"justification": "Annotation required to resolve a swagger error. The value is now correct."
284+
},
285+
{
273286
"code": "java.method.returnTypeChanged",
274287
"old": "method com.azure.core.util.IterableStream<byte[]> com.azure.core.amqp.models.AmqpDataBody::getData()",
275288
"new": "method java.util.List<byte[]> com.azure.core.amqp.models.AmqpDataBody::getData()",

sdk/storage/azure-storage-blob-batch/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Release History
22

33
## 12.9.0-beta.1 (Unreleased)
4-
4+
- Added support for the 2020-06-12 service version.
5+
- Added support to create a BlobBatchClient from a BlobContainerClient to perform container level operations.
56

67
## 12.8.0 (2021-01-14)
78
- GA release

sdk/storage/azure-storage-blob-batch/src/main/java/com/azure/storage/blob/batch/BlobBatchAsyncClient.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,15 @@ public final class BlobBatchAsyncClient {
5151
private final ClientLogger logger = new ClientLogger(BlobBatchAsyncClient.class);
5252

5353
private final AzureBlobStorageImpl client;
54+
private final boolean containerScoped;
5455

55-
BlobBatchAsyncClient(String accountUrl, HttpPipeline pipeline, BlobServiceVersion version) {
56+
BlobBatchAsyncClient(String clientUrl, HttpPipeline pipeline, BlobServiceVersion version, boolean containerScoped) {
5657
this.client = new AzureBlobStorageBuilder()
57-
.url(accountUrl)
58+
.url(clientUrl)
5859
.pipeline(pipeline)
5960
.version(version.getVersion())
6061
.build();
62+
this.containerScoped = containerScoped;
6163
}
6264

6365
/**
@@ -121,12 +123,18 @@ public Mono<Response<Void>> submitBatchWithResponse(BlobBatch batch, boolean thr
121123
}
122124

123125
Mono<Response<Void>> submitBatchWithResponse(BlobBatch batch, boolean throwOnAnyFailure, Context context) {
126+
Context finalContext = context == null ? Context.NONE : context;
124127
return batch.prepareBlobBatchSubmission()
125-
.flatMap(batchOperationInfo -> client.services()
126-
.submitBatchWithRestResponseAsync(Flux.fromIterable(batchOperationInfo.getBody()),
127-
batchOperationInfo.getContentLength(), batchOperationInfo.getContentType(),
128-
context == null ? Context.NONE.addData(AZ_TRACING_NAMESPACE_KEY, STORAGE_TRACING_NAMESPACE_VALUE)
129-
: context.addData(AZ_TRACING_NAMESPACE_KEY, STORAGE_TRACING_NAMESPACE_VALUE))
128+
.flatMap(batchOperationInfo -> containerScoped
129+
? client.containers().submitBatchWithRestResponseAsync(null,
130+
Flux.fromIterable(batchOperationInfo.getBody()),
131+
batchOperationInfo.getContentLength(), batchOperationInfo.getContentType(),
132+
finalContext.addData(AZ_TRACING_NAMESPACE_KEY, STORAGE_TRACING_NAMESPACE_VALUE))
133+
.flatMap(response ->
134+
BlobBatchHelper.mapBatchResponse(batchOperationInfo, response, throwOnAnyFailure, logger))
135+
: client.services().submitBatchWithRestResponseAsync(Flux.fromIterable(batchOperationInfo.getBody()),
136+
batchOperationInfo.getContentLength(), batchOperationInfo.getContentType(),
137+
finalContext.addData(AZ_TRACING_NAMESPACE_KEY, STORAGE_TRACING_NAMESPACE_VALUE))
130138
.flatMap(response ->
131139
BlobBatchHelper.mapBatchResponse(batchOperationInfo, response, throwOnAnyFailure, logger)));
132140
}

sdk/storage/azure-storage-blob-batch/src/main/java/com/azure/storage/blob/batch/BlobBatchClient.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ public PagedIterable<Response<Void>> setBlobsAccessTier(List<String> blobUrls, A
162162
* @throws BlobStorageException If the batch request is malformed.
163163
* @throws BlobBatchStorageException If any of the set tier operations fail.
164164
*/
165+
@ServiceMethod(returns = ReturnType.COLLECTION)
165166
public PagedIterable<Response<Void>> setBlobsAccessTier(List<String> blobUrls, AccessTier accessTier,
166167
Duration timeout, Context context) {
167168
return new PagedIterable<>(client.setBlobsAccessTierWithTimeout(blobUrls, accessTier, timeout, context));

sdk/storage/azure-storage-blob-batch/src/main/java/com/azure/storage/blob/batch/BlobBatchClientBuilder.java

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
import com.azure.core.annotation.ServiceClientBuilder;
77
import com.azure.core.http.HttpPipeline;
8+
import com.azure.storage.blob.BlobContainerAsyncClient;
9+
import com.azure.storage.blob.BlobContainerClient;
810
import com.azure.storage.blob.BlobServiceAsyncClient;
911
import com.azure.storage.blob.BlobServiceClient;
1012
import com.azure.storage.blob.BlobServiceVersion;
@@ -16,9 +18,10 @@
1618
*/
1719
@ServiceClientBuilder(serviceClients = {BlobBatchClient.class, BlobBatchAsyncClient.class})
1820
public final class BlobBatchClientBuilder {
19-
private final String accountUrl;
21+
private final String clientUrl;
2022
private final HttpPipeline pipeline;
2123
private final BlobServiceVersion version;
24+
private final boolean containerScoped;
2225

2326
/**
2427
* Constructs the {@link BlobBatchClientBuilder} using the {@link BlobServiceClient#getAccountUrl() account URL} and
@@ -27,22 +30,52 @@ public final class BlobBatchClientBuilder {
2730
* @param client {@link BlobServiceClient} whose properties are used to configure the builder.
2831
*/
2932
public BlobBatchClientBuilder(BlobServiceClient client) {
30-
this.accountUrl = client.getAccountUrl();
33+
this.clientUrl = client.getAccountUrl();
3134
this.pipeline = client.getHttpPipeline();
3235
this.version = client.getServiceVersion();
36+
this.containerScoped = false;
3337
}
3438

3539
/**
3640
* Constructs the {@link BlobBatchClientBuilder} using the {@link BlobServiceAsyncClient#getAccountUrl() account
3741
* URL} and {@link BlobServiceAsyncClient#getHttpPipeline() HttpPipeline} properties of the passed {@link
3842
* BlobServiceAsyncClient}.
3943
*
40-
* @param client {@link BlobServiceClient} whose properties are used to configure the builder.
44+
* @param client {@link BlobServiceAsyncClient} whose properties are used to configure the builder.
4145
*/
4246
public BlobBatchClientBuilder(BlobServiceAsyncClient client) {
43-
this.accountUrl = client.getAccountUrl();
47+
this.clientUrl = client.getAccountUrl();
48+
this.pipeline = client.getHttpPipeline();
49+
this.version = client.getServiceVersion();
50+
this.containerScoped = false;
51+
}
52+
53+
/**
54+
* Constructs the {@link BlobBatchClientBuilder} using the {@link BlobContainerClient#getBlobContainerUrl()
55+
* container URL} and {@link BlobContainerClient#getHttpPipeline() HttpPipeline} properties of the passed
56+
* {@link BlobContainerClient}.
57+
*
58+
* @param client {@link BlobContainerClient} whose properties are used to configure the builder.
59+
*/
60+
public BlobBatchClientBuilder(BlobContainerClient client) {
61+
this.clientUrl = client.getBlobContainerUrl();
62+
this.pipeline = client.getHttpPipeline();
63+
this.version = client.getServiceVersion();
64+
this.containerScoped = true;
65+
}
66+
67+
/**
68+
* Constructs the {@link BlobBatchClientBuilder} using the {@link BlobContainerAsyncClient#getBlobContainerUrl()
69+
* container URL} and {@link BlobContainerAsyncClient#getHttpPipeline() HttpPipeline} properties of the
70+
* passed {@link BlobContainerAsyncClient}.
71+
*
72+
* @param client {@link BlobContainerAsyncClient} whose properties are used to configure the builder.
73+
*/
74+
public BlobBatchClientBuilder(BlobContainerAsyncClient client) {
75+
this.clientUrl = client.getBlobContainerUrl();
4476
this.pipeline = client.getHttpPipeline();
4577
this.version = client.getServiceVersion();
78+
this.containerScoped = true;
4679
}
4780

4881
/**
@@ -69,6 +102,6 @@ public BlobBatchClient buildClient() {
69102
*/
70103
public BlobBatchAsyncClient buildAsyncClient() {
71104
BlobServiceVersion serviceVersion = version != null ? version : BlobServiceVersion.getLatest();
72-
return new BlobBatchAsyncClient(accountUrl, pipeline, serviceVersion);
105+
return new BlobBatchAsyncClient(clientUrl, pipeline, serviceVersion, containerScoped);
73106
}
74107
}

sdk/storage/azure-storage-blob-batch/src/main/java/com/azure/storage/blob/batch/BlobBatchHelper.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
import com.azure.core.http.HttpHeaders;
77
import com.azure.core.http.HttpRequest;
88
import com.azure.core.http.HttpResponse;
9+
import com.azure.core.http.rest.Response;
910
import com.azure.core.http.rest.SimpleResponse;
1011
import com.azure.core.util.CoreUtils;
1112
import com.azure.core.util.FluxUtil;
1213
import com.azure.core.util.logging.ClientLogger;
13-
import com.azure.storage.blob.implementation.models.ServicesSubmitBatchResponse;
1414
import com.azure.storage.blob.models.BlobStorageException;
15+
import com.azure.storage.common.implementation.Constants;
1516
import reactor.core.publisher.Flux;
1617
import reactor.core.publisher.Mono;
1718

@@ -52,12 +53,12 @@ class BlobBatchHelper {
5253

5354
// This method connects the batch response values to the individual batch operations based on their Content-Id
5455
static Mono<SimpleResponse<Void>> mapBatchResponse(BlobBatchOperationInfo batchOperationInfo,
55-
ServicesSubmitBatchResponse batchResponse, boolean throwOnAnyFailure, ClientLogger logger) {
56+
Response<Flux<ByteBuffer>> rawResponse, boolean throwOnAnyFailure, ClientLogger logger) {
5657
/*
5758
* Content-Type will contain the boundary for each batch response. The expected format is:
5859
* "Content-Type: multipart/mixed; boundary=batchresponse_66925647-d0cb-4109-b6d3-28efe3e1e5ed"
5960
*/
60-
String contentType = batchResponse.getDeserializedHeaders().getContentType();
61+
String contentType = rawResponse.getHeaders().getValue(Constants.HeaderConstants.CONTENT_TYPE);
6162

6263
// Split on the boundary [ "multipart/mixed; boundary", "batchresponse_66925647-d0cb-4109-b6d3-28efe3e1e5ed"]
6364
String[] boundaryPieces = contentType.split("=", 2);
@@ -68,7 +69,7 @@ static Mono<SimpleResponse<Void>> mapBatchResponse(BlobBatchOperationInfo batchO
6869

6970
String boundary = boundaryPieces[1];
7071

71-
return FluxUtil.collectBytesInByteBufferStream(batchResponse.getValue())
72+
return FluxUtil.collectBytesInByteBufferStream(rawResponse.getValue())
7273
.flatMap(byteArrayBody -> Mono.fromRunnable(() -> {
7374
String body = new String(byteArrayBody, StandardCharsets.UTF_8);
7475
List<BlobStorageException> exceptions = new ArrayList<>();
@@ -79,8 +80,9 @@ static Mono<SimpleResponse<Void>> mapBatchResponse(BlobBatchOperationInfo batchO
7980
int statusCode = getStatusCode(exceptionSections[1], logger);
8081
HttpHeaders headers = getHttpHeaders(exceptionSections[1]);
8182

82-
throw logger.logExceptionAsError(new BlobStorageException(headers.getValue("x-ms-error-code"),
83-
createHttpResponse(batchResponse.getRequest(), statusCode, headers, body), body));
83+
throw logger.logExceptionAsError(new BlobStorageException(
84+
headers.getValue(Constants.HeaderConstants.ERROR_CODE),
85+
createHttpResponse(rawResponse.getRequest(), statusCode, headers, body), body));
8486
}
8587

8688
// Split the batch response body into batch operation responses.
@@ -110,10 +112,10 @@ static Mono<SimpleResponse<Void>> mapBatchResponse(BlobBatchOperationInfo batchO
110112

111113
if (throwOnAnyFailure && exceptions.size() != 0) {
112114
throw logger.logExceptionAsError(new BlobBatchStorageException("Batch had operation failures.",
113-
createHttpResponse(batchResponse), exceptions));
115+
createHttpResponse(rawResponse), exceptions));
114116
}
115117

116-
new SimpleResponse<>(batchResponse, null);
118+
new SimpleResponse<>(rawResponse, null);
117119
}));
118120
}
119121

@@ -212,7 +214,7 @@ public Mono<String> getBodyAsString(Charset charset) {
212214
};
213215
}
214216

215-
private static HttpResponse createHttpResponse(ServicesSubmitBatchResponse response) {
217+
private static HttpResponse createHttpResponse(Response<Flux<ByteBuffer>> response) {
216218
return new HttpResponse(response.getRequest()) {
217219
@Override
218220
public int getStatusCode() {

sdk/storage/azure-storage-blob-batch/src/test/java/com/azure/storage/blob/batch/APISpec.groovy

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import com.azure.core.test.utils.TestResourceNamer
1313
import com.azure.core.util.Configuration
1414
import com.azure.core.util.logging.ClientLogger
1515
import com.azure.identity.EnvironmentCredentialBuilder
16+
import com.azure.storage.blob.BlobContainerClient
17+
import com.azure.storage.blob.BlobContainerClientBuilder
1618
import com.azure.storage.blob.BlobServiceAsyncClient
1719
import com.azure.storage.blob.BlobServiceClient
1820
import com.azure.storage.blob.BlobServiceClientBuilder
@@ -26,6 +28,7 @@ import spock.lang.Specification
2628

2729
import java.nio.ByteBuffer
2830
import java.nio.charset.StandardCharsets
31+
import java.time.OffsetDateTime
2932
import java.util.function.Supplier
3033

3134
class APISpec extends Specification {
@@ -180,6 +183,10 @@ class APISpec extends Specification {
180183
return getServiceClientBuilder(credential, endpoint, policies).buildClient()
181184
}
182185

186+
BlobServiceClient getServiceClient(String sasToken, String endpoint) {
187+
return getServiceClientBuilder(null, endpoint, null).sasToken(sasToken).buildClient()
188+
}
189+
183190
BlobServiceAsyncClient getServiceAsyncClient(StorageSharedKeyCredential credential) {
184191
return getServiceClientBuilder(credential, String.format(defaultEndpointTemplate, credential.getAccountName()))
185192
.buildAsyncClient()
@@ -206,6 +213,22 @@ class APISpec extends Specification {
206213
return builder
207214
}
208215

216+
BlobContainerClient getContainerClient(String sasToken, String endpoint) {
217+
getContainerClientBuilder(endpoint).sasToken(sasToken).buildClient()
218+
}
219+
220+
BlobContainerClientBuilder getContainerClientBuilder(String endpoint) {
221+
BlobContainerClientBuilder builder = new BlobContainerClientBuilder()
222+
.endpoint(endpoint)
223+
.httpClient(getHttpClient())
224+
225+
if (testMode == TestMode.RECORD) {
226+
builder.addPolicy(interceptorManager.getRecordPolicy())
227+
}
228+
229+
return builder
230+
}
231+
209232
HttpClient getHttpClient() {
210233
NettyAsyncHttpClientBuilder builder = new NettyAsyncHttpClientBuilder()
211234
if (testMode != TestMode.PLAYBACK) {
@@ -233,6 +256,10 @@ class APISpec extends Specification {
233256
return resourceNamer.randomName(prefix + testName + entityNo, 63)
234257
}
235258

259+
OffsetDateTime getUTCNow() {
260+
return resourceNamer.now()
261+
}
262+
236263
/**
237264
* This helper method will acquire a lease on a blob to prepare for testing lease Id. We want to test
238265
* against a valid lease in both the success and failure cases to guarantee that the results actually indicate

0 commit comments

Comments
 (0)