View Javadoc
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 }