1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License.
3
4 package com.azure.storage.blob;
5
6 import com.azure.core.http.rest.Response;
7 import com.azure.core.http.rest.SimpleResponse;
8 import com.azure.storage.blob.implementation.AzureBlobStorageBuilder;
9 import com.azure.storage.blob.models.BlobAccessConditions;
10 import com.azure.storage.blob.models.BlobHTTPHeaders;
11 import com.azure.storage.blob.models.BlobRange;
12 import com.azure.storage.blob.models.CopyStatusType;
13 import com.azure.storage.blob.models.Metadata;
14 import com.azure.storage.blob.models.ModifiedAccessConditions;
15 import com.azure.storage.blob.models.PageBlobAccessConditions;
16 import com.azure.storage.blob.models.PageBlobItem;
17 import com.azure.storage.blob.models.PageRange;
18 import com.azure.storage.blob.models.SequenceNumberActionType;
19 import com.azure.storage.blob.models.SourceModifiedAccessConditions;
20 import io.netty.buffer.Unpooled;
21 import reactor.core.publisher.Flux;
22 import reactor.core.publisher.Mono;
23
24 import java.net.URL;
25 import java.nio.ByteBuffer;
26
27 /**
28 * Client to a page blob. It may only be instantiated through a {@link PageBlobClientBuilder}, via
29 * the method {@link BlobAsyncClient#asPageBlobAsyncClient()}, or via the method
30 * {@link ContainerAsyncClient#getPageBlobAsyncClient(String)}. This class does not hold
31 * any state about a particular blob, but is instead a convenient way of sending appropriate
32 * requests to the resource on the service.
33 *
34 * <p>
35 * This client contains operations on a blob. Operations on a container are available on {@link ContainerAsyncClient},
36 * and operations on the service are available on {@link StorageAsyncClient}.
37 *
38 * <p>
39 * Please refer
40 * to the <a href=https://docs.microsoft.com/en-us/rest/api/storageservices/understanding-block-blobs--append-blobs--and-page-blobs>Azure Docs</a>
41 * for more information.
42 *
43 * <p>
44 * Note this client is an async client that returns reactive responses from Spring Reactor Core
45 * project (https://projectreactor.io/). Calling the methods in this client will <strong>NOT</strong>
46 * start the actual network operation, until {@code .subscribe()} is called on the reactive response.
47 * You can simply convert one of these responses to a {@link java.util.concurrent.CompletableFuture}
48 * object through {@link Mono#toFuture()}.
49 */
50 public final class PageBlobAsyncClient extends BlobAsyncClient {
51
52 final PageBlobAsyncRawClient pageBlobAsyncRawClient;
53
54 /**
55 * Indicates the number of bytes in a page.
56 */
57 public static final int PAGE_BYTES = 512;
58
59 /**
60 * Indicates the maximum number of bytes that may be sent in a call to putPage.
61 */
62 public static final int MAX_PUT_PAGES_BYTES = 4 * Constants.MB;
63
64 /**
65 * Package-private constructor for use by {@link PageBlobClientBuilder}.
66 * @param azureBlobStorageBuilder the API client builder for blob storage API
67 */
68 PageBlobAsyncClient(AzureBlobStorageBuilder azureBlobStorageBuilder, String snapshot) {
69 super(azureBlobStorageBuilder, snapshot);
70 this.pageBlobAsyncRawClient = new PageBlobAsyncRawClient(azureBlobStorageBuilder.build(), snapshot);
71 }
72
73 /**
74 * Creates a page blob of the specified length. Call PutPage to upload data data to a page blob.
75 * For more information, see the
76 * <a href="https://docs.microsoft.com/rest/api/storageservices/put-blob">Azure Docs</a>.
77 *
78 * @param size
79 * Specifies the maximum size for the page blob, up to 8 TB. The page blob size must be aligned to a
80 * 512-byte boundary.
81 *
82 * @return
83 * A reactive response containing the information of the created page blob.
84 */
85 public Mono<Response<PageBlobItem>> create(long size) {
86 return this.create(size, null, null, null, null);
87 }
88
89 /**
90 * Creates a page blob of the specified length. Call PutPage to upload data data to a page blob.
91 * For more information, see the
92 * <a href="https://docs.microsoft.com/rest/api/storageservices/put-blob">Azure Docs</a>.
93 *
94 * @param size
95 * Specifies the maximum size for the page blob, up to 8 TB. The page blob size must be aligned to a
96 * 512-byte boundary.
97 * @param sequenceNumber
98 * A user-controlled value that you can use to track requests. The value of the sequence number must be
99 * between 0 and 2^63 - 1.The default value is 0.
100 * @param headers
101 * {@link BlobHTTPHeaders}
102 * @param metadata
103 * {@link Metadata}
104 * @param accessConditions
105 * {@link BlobAccessConditions}
106 *
107 * @return
108 * A reactive response containing the information of the created page blob.
109 */
110 public Mono<Response<PageBlobItem>> create(long size, Long sequenceNumber, BlobHTTPHeaders headers,
111 Metadata metadata, BlobAccessConditions accessConditions) {
112 return pageBlobAsyncRawClient
113 .create(size, sequenceNumber, headers, metadata, accessConditions)
114 .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders())));
115 }
116
117 /**
118 * Writes 1 or more pages to the page blob. The start and end offsets must be a multiple of 512.
119 * For more information, see the
120 * <a href="https://docs.microsoft.com/rest/api/storageservices/put-page">Azure Docs</a>.
121 * <p>
122 * Note that the data passed must be replayable if retries are enabled (the default). In other words, the
123 * {@code Flux} must produce the same data each time it is subscribed to.
124 *
125 * @param pageRange
126 * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset must
127 * be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges are
128 * 0-511, 512-1023, etc.
129 * @param body
130 * The data to upload. Note that this {@code Flux} must be replayable if retries are enabled
131 * (the default). In other words, the Flowable must produce the same data each time it is subscribed to.
132 *
133 * @return
134 * A reactive response containing the information of the uploaded pages.
135 */
136 public Mono<Response<PageBlobItem>> uploadPages(PageRange pageRange, Flux<ByteBuffer> body) {
137 return this.uploadPages(pageRange, body, null);
138 }
139
140 /**
141 * Writes 1 or more pages to the page blob. The start and end offsets must be a multiple of 512.
142 * For more information, see the
143 * <a href="https://docs.microsoft.com/rest/api/storageservices/put-page">Azure Docs</a>.
144 * <p>
145 * Note that the data passed must be replayable if retries are enabled (the default). In other words, the
146 * {@code Flux} must produce the same data each time it is subscribed to.
147 *
148 * @param pageRange
149 * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset
150 * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges
151 * are 0-511, 512-1023, etc.
152 * @param body
153 * The data to upload. Note that this {@code Flux} must be replayable if retries are enabled
154 * (the default). In other words, the Flowable must produce the same data each time it is subscribed to.
155 * @param pageBlobAccessConditions
156 * {@link PageBlobAccessConditions}
157 *
158 * @return
159 * A reactive response containing the information of the uploaded pages.
160 */
161 public Mono<Response<PageBlobItem>> uploadPages(PageRange pageRange, Flux<ByteBuffer> body,
162 PageBlobAccessConditions pageBlobAccessConditions) {
163 return pageBlobAsyncRawClient
164 .uploadPages(pageRange, body.map(Unpooled::wrappedBuffer), pageBlobAccessConditions)
165 .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders())));
166 }
167
168 /**
169 * Writes 1 or more pages from the source page blob to this page blob. The start and end offsets must be a multiple
170 * of 512.
171 * For more information, see the
172 * <a href="https://docs.microsoft.com/rest/api/storageservices/put-page">Azure Docs</a>.
173 * <p>
174 *
175 * @param range
176 * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset
177 * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges
178 * are 0-511, 512-1023, etc.
179 * @param sourceURL
180 * The url to the blob that will be the source of the copy. A source blob in the same storage account can be
181 * authenticated via Shared Key. However, if the source is a blob in another account, the source blob must
182 * either be public or must be authenticated via a shared access signature. If the source blob is public, no
183 * authentication is required to perform the operation.
184 * @param sourceOffset
185 * The source offset to copy from. Pass null or 0 to copy from the beginning of source page blob.
186 *
187 * @return
188 * A reactive response containing the information of the uploaded pages.
189 */
190 public Mono<Response<PageBlobItem>> uploadPagesFromURL(PageRange range, URL sourceURL, Long sourceOffset) {
191 return this.uploadPagesFromURL(range, sourceURL, sourceOffset, null, null,
192 null);
193 }
194
195 /**
196 * Writes 1 or more pages from the source page blob to this page blob. The start and end offsets must be a multiple
197 * of 512.
198 * For more information, see the
199 * <a href="https://docs.microsoft.com/rest/api/storageservices/put-page">Azure Docs</a>.
200 * <p>
201 *
202 * @param range
203 * The destination {@link PageRange} range. Given that pages must be aligned with 512-byte boundaries, the start offset
204 * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges
205 * are 0-511, 512-1023, etc.
206 * @param sourceURL
207 * The url to the blob that will be the source of the copy. A source blob in the same storage account can be
208 * authenticated via Shared Key. However, if the source is a blob in another account, the source blob must
209 * either be public or must be authenticated via a shared access signature. If the source blob is public, no
210 * authentication is required to perform the operation.
211 * @param sourceOffset
212 * The source offset to copy from. Pass null or 0 to copy from the beginning of source blob.
213 * @param sourceContentMD5
214 * An MD5 hash of the block content from the source blob. If specified, the service will calculate the MD5
215 * of the received data and fail the request if it does not match the provided MD5.
216 * @param destAccessConditions
217 * {@link PageBlobAccessConditions}
218 * @param sourceAccessConditions
219 * {@link SourceModifiedAccessConditions}
220 *
221 * @return
222 * A reactive response containing the information of the uploaded pages.
223 */
224 public Mono<Response<PageBlobItem>> uploadPagesFromURL(PageRange range, URL sourceURL, Long sourceOffset,
225 byte[] sourceContentMD5, PageBlobAccessConditions destAccessConditions,
226 SourceModifiedAccessConditions sourceAccessConditions) {
227
228 return pageBlobAsyncRawClient
229 .uploadPagesFromURL(range, sourceURL, sourceOffset, sourceContentMD5, destAccessConditions, sourceAccessConditions)
230 .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders())));
231 }
232
233 /**
234 * Frees the specified pages from the page blob.
235 * For more information, see the
236 * <a href="https://docs.microsoft.com/rest/api/storageservices/put-page">Azure Docs</a>.
237 *
238 * @param pageRange
239 * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset
240 * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges
241 * are 0-511, 512-1023, etc.
242 *
243 * @return
244 * A reactive response containing the information of the cleared pages.
245 */
246 public Mono<Response<PageBlobItem>> clearPages(PageRange pageRange) {
247 return this.clearPages(pageRange, null);
248 }
249
250 /**
251 * Frees the specified pages from the page blob.
252 * For more information, see the
253 * <a href="https://docs.microsoft.com/rest/api/storageservices/put-page">Azure Docs</a>.
254 *
255 * @param pageRange
256 * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset
257 * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges
258 * are 0-511, 512-1023, etc.
259 * @param pageBlobAccessConditions
260 * {@link PageBlobAccessConditions}
261 *
262 * @return
263 * A reactive response containing the information of the cleared pages.
264 */
265 public Mono<Response<PageBlobItem>> clearPages(PageRange pageRange,
266 PageBlobAccessConditions pageBlobAccessConditions) {
267 return pageBlobAsyncRawClient
268 .clearPages(pageRange, pageBlobAccessConditions)
269 .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders())));
270 }
271
272 /**
273 * Returns the list of valid page ranges for a page blob or snapshot of a page blob.
274 * For more information, see the <a href="https://docs.microsoft.com/rest/api/storageservices/get-page-ranges">Azure Docs</a>.
275 *
276 * @param blobRange
277 * {@link BlobRange}
278 *
279 * @return
280 * A reactive response containing the information of the cleared pages.
281 */
282 public Flux<PageRange> getPageRanges(BlobRange blobRange) {
283 return this.getPageRanges(blobRange, null);
284 }
285
286 /**
287 * Returns the list of valid page ranges for a page blob or snapshot of a page blob.
288 * For more information, see the <a href="https://docs.microsoft.com/rest/api/storageservices/get-page-ranges">Azure Docs</a>.
289 *
290 * @param blobRange
291 * {@link BlobRange}
292 * @param accessConditions
293 * {@link BlobAccessConditions}
294 *
295 * @return
296 * A reactive response emitting all the page ranges.
297 */
298 public Flux<PageRange> getPageRanges(BlobRange blobRange,
299 BlobAccessConditions accessConditions) {
300 return pageBlobAsyncRawClient
301 .getPageRanges(blobRange, accessConditions)
302 .flatMapMany(response -> Flux.fromIterable(response.value().pageRange()));
303 }
304
305 /**
306 * Gets the collection of page ranges that differ between a specified snapshot and this page blob.
307 * For more information, see the <a href="https://docs.microsoft.com/rest/api/storageservices/get-page-ranges">Azure Docs</a>.
308 *
309 * @param blobRange
310 * {@link BlobRange}
311 * @param prevSnapshot
312 * Specifies that the response will contain only pages that were changed between target blob and previous
313 * snapshot. Changed pages include both updated and cleared pages. The target
314 * blob may be a snapshot, as long as the snapshot specified by prevsnapshot is the older of the two.
315 *
316 * @return
317 * A reactive response emitting all the different page ranges.
318 */
319 public Flux<PageRange> getPageRangesDiff(BlobRange blobRange, String prevSnapshot) {
320 return this.getPageRangesDiff(blobRange, prevSnapshot, null);
321 }
322
323 /**
324 * Gets the collection of page ranges that differ between a specified snapshot and this page blob.
325 * For more information, see the <a href="https://docs.microsoft.com/rest/api/storageservices/get-page-ranges">Azure Docs</a>.
326 *
327 * @param blobRange
328 * {@link BlobRange}
329 * @param prevSnapshot
330 * Specifies that the response will contain only pages that were changed between target blob and previous
331 * snapshot. Changed pages include both updated and cleared pages. The target
332 * blob may be a snapshot, as long as the snapshot specified by prevsnapshot is the older of the two.
333 * @param accessConditions
334 * {@link BlobAccessConditions}
335 *
336 * @return
337 * A reactive response emitting all the different page ranges.
338 */
339 public Flux<PageRange> getPageRangesDiff(BlobRange blobRange, String prevSnapshot,
340 BlobAccessConditions accessConditions) {
341 return pageBlobAsyncRawClient
342 .getPageRangesDiff(blobRange, prevSnapshot, accessConditions)
343 .flatMapMany(response -> Flux.fromIterable(response.value().pageRange()));
344 }
345
346 /**
347 * Resizes the page blob to the specified size (which must be a multiple of 512).
348 * For more information, see the <a href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">Azure Docs</a>.
349 *
350 * @param size
351 * Resizes a page blob to the specified size. If the specified value is less than the current size of the
352 * blob, then all pages above the specified value are cleared.
353 *
354 * @return
355 * A reactive response emitting the resized page blob.
356 */
357 public Mono<Response<PageBlobItem>> resize(long size) {
358 return this.resize(size, null);
359 }
360
361 /**
362 * Resizes the page blob to the specified size (which must be a multiple of 512).
363 * For more information, see the <a href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">Azure Docs</a>.
364 *
365 * @param size
366 * Resizes a page blob to the specified size. If the specified value is less than the current size of the
367 * blob, then all pages above the specified value are cleared.
368 * @param accessConditions
369 * {@link BlobAccessConditions}
370 *
371 * @return
372 * A reactive response emitting the resized page blob.
373 */
374 public Mono<Response<PageBlobItem>> resize(long size, BlobAccessConditions accessConditions) {
375 return pageBlobAsyncRawClient
376 .resize(size, accessConditions)
377 .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders())));
378 }
379
380 /**
381 * Sets the page blob's sequence number.
382 * For more information, see the <a href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">Azure Docs</a>.
383 *
384 * @param action
385 * Indicates how the service should modify the blob's sequence number.
386 * @param sequenceNumber
387 * The blob's sequence number. The sequence number is a user-controlled property that you can use to track
388 * requests and manage concurrency issues.
389 *
390 * @return
391 * A reactive response emitting the updated page blob.
392 */
393 public Mono<Response<PageBlobItem>> updateSequenceNumber(SequenceNumberActionType action,
394 Long sequenceNumber) {
395 return this.updateSequenceNumber(action, sequenceNumber, null);
396 }
397
398 /**
399 * Sets the page blob's sequence number.
400 * For more information, see the <a href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">Azure Docs</a>.
401 *
402 * @param action
403 * Indicates how the service should modify the blob's sequence number.
404 * @param sequenceNumber
405 * The blob's sequence number. The sequence number is a user-controlled property that you can use to track
406 * requests and manage concurrency issues.
407 * @param accessConditions
408 * {@link BlobAccessConditions}
409 *
410 * @return
411 * A reactive response emitting the updated page blob.
412 */
413 public Mono<Response<PageBlobItem>> updateSequenceNumber(SequenceNumberActionType action,
414 Long sequenceNumber, BlobAccessConditions accessConditions) {
415 return pageBlobAsyncRawClient
416 .updateSequenceNumber(action, sequenceNumber, accessConditions)
417 .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders())));
418 }
419
420 /**
421 * Begins an operation to start an incremental copy from one page blob's snapshot to this page
422 * blob. The snapshot is copied such that only the differential changes between the previously copied snapshot are
423 * transferred to the destination. The copied snapshots are complete copies of the original snapshot and can be read
424 * or copied from as usual. For more information, see
425 * the Azure Docs <a href="https://docs.microsoft.com/rest/api/storageservices/incremental-copy-blob">here</a> and
426 * <a href="https://docs.microsoft.com/en-us/azure/virtual-machines/windows/incremental-snapshots">here</a>.
427 *
428 * @param source
429 * The source page blob.
430 * @param snapshot
431 * The snapshot on the copy source.
432 *
433 * @return
434 * A reactive response emitting the copy status.
435 */
436 public Mono<Response<CopyStatusType>> copyIncremental(URL source, String snapshot) {
437 return this.copyIncremental(source, snapshot, null);
438 }
439
440 /**
441 * Begins an operation to start an incremental copy from one page blob's snapshot to this page
442 * blob. The snapshot is copied such that only the differential changes between the previously copied snapshot are
443 * transferred to the destination. The copied snapshots are complete copies of the original snapshot and can be read
444 * or copied from as usual. For more information, see
445 * the Azure Docs <a href="https://docs.microsoft.com/rest/api/storageservices/incremental-copy-blob">here</a> and
446 * <a href="https://docs.microsoft.com/en-us/azure/virtual-machines/windows/incremental-snapshots">here</a>.
447 *
448 * @param source
449 * The source page blob.
450 * @param snapshot
451 * The snapshot on the copy source.
452 * @param modifiedAccessConditions
453 * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used
454 * to construct conditions related to when the blob was changed relative to the given request. The request
455 * will fail if the specified condition is not satisfied.
456 *
457 * @return
458 * A reactive response emitting the copy status.
459 */
460 public Mono<Response<CopyStatusType>> copyIncremental(URL source, String snapshot,
461 ModifiedAccessConditions modifiedAccessConditions) {
462 return pageBlobAsyncRawClient
463 .copyIncremental(source, snapshot, modifiedAccessConditions)
464 .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().copyStatus()));
465 }
466 }