From 712a36e23e3e67859620bf9678427255e7abb6d6 Mon Sep 17 00:00:00 2001 From: Rabab Ibrahim Date: Thu, 19 Jan 2023 19:03:11 -0800 Subject: [PATCH] AppendBlobClient.getOutputStream(boolean) to overwrite correctly if set to true (#33086) --- sdk/storage/azure-storage-blob/CHANGELOG.md | 1 + .../blob/specialized/AppendBlobClient.java | 26 ++++++++- .../storage/blob/BlobOutputStreamTest.groovy | 55 +++++++++++++++++++ 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/sdk/storage/azure-storage-blob/CHANGELOG.md b/sdk/storage/azure-storage-blob/CHANGELOG.md index 63d2a6616780..1299838ca303 100644 --- a/sdk/storage/azure-storage-blob/CHANGELOG.md +++ b/sdk/storage/azure-storage-blob/CHANGELOG.md @@ -6,6 +6,7 @@ - Added support for 2021-12-02 service version. - Added support for Blob Cold Tier `AccessTier.COLD`. - Fixed bug where `BlobErrorCode.IncrementalCopyOfEarlierVersionSnapshotNotAllowed` was spelled incorrectly. +- Added new overload `AppendBlobClient.getBlobOutputStream(boolean)` that takes in a boolean for overwrite and appends to existing data if overwrite is specified `false`, or deletes and recreates a blob if overwrite is specified `true`. ### Breaking Changes diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/AppendBlobClient.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/AppendBlobClient.java index eca6dc7dc3e3..a805f6e38e0e 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/AppendBlobClient.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/AppendBlobClient.java @@ -52,6 +52,7 @@ */ @ServiceClient(builder = SpecializedBlobClientBuilder.class) public final class AppendBlobClient extends BlobClientBase { + private final AppendBlobAsyncClient appendBlobAsyncClient; /** @@ -99,7 +100,7 @@ public AppendBlobClient getCustomerProvidedKeyClient(CustomerProvidedKey custome /** * Creates and opens an output stream to write data to the append blob. If the blob already exists on the service, - * it will be overwritten. + * new data will get appended to the existing blob. * * @return A {@link BlobOutputStream} object used to write data to the blob. * @throws BlobStorageException If a storage service error occurred. @@ -109,8 +110,27 @@ public BlobOutputStream getBlobOutputStream() { } /** - * Creates and opens an output stream to write data to the append blob. If the blob already exists on the service, - * it will be overwritten. + * Creates and opens an output stream to write data to the append blob. If overwrite is specified {@code true}, + * the existing blob will be deleted and recreated, should data exist on the blob. If overwrite is specified + * {@code false}, new data will get appended to the existing blob. + * + * @return A {@link BlobOutputStream} object used to write data to the blob. + * @param overwrite Whether an existing blob should be deleted and recreated, should data exist on the blob. + * @throws BlobStorageException If a storage service error occurred. + */ + public BlobOutputStream getBlobOutputStream(boolean overwrite) { + AppendBlobRequestConditions requestConditions = null; + if (!overwrite) { + requestConditions = new AppendBlobRequestConditions().setIfNoneMatch(Constants.HeaderConstants.ETAG_WILDCARD); + } else { + // creating new blob to overwrite existing blob + create(true); + } + return getBlobOutputStream(requestConditions); + } + + /** + * Creates and opens an output stream to write data to the append blob. * * @param requestConditions A {@link BlobRequestConditions} object that represents the access conditions for the * blob. diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobOutputStreamTest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobOutputStreamTest.groovy index e79d09dcddc0..4748ef7af8b9 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobOutputStreamTest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobOutputStreamTest.groovy @@ -218,6 +218,61 @@ class BlobOutputStreamTest extends APISpec { convertInputStreamToByteArray(appendBlobClient.openInputStream()) == data } + @LiveOnly + def "AppendBlob output stream overwrite"() { + setup: + def data = getRandomByteArray(FOUR_MB) + def appendBlobClient = cc.getBlobClient(generateBlobName()).getAppendBlobClient() + appendBlobClient.create() + + when: + def outputStream = appendBlobClient.getBlobOutputStream() + outputStream.write(data) + outputStream.close() + + then: + convertInputStreamToByteArray(appendBlobClient.openInputStream()) == data + + when: + def data2 = getRandomByteArray(FOUR_MB) + + def outputStream2 = appendBlobClient.getBlobOutputStream(true) + outputStream2.write(data2) + outputStream2.close() + + then: + appendBlobClient.getProperties().getBlobSize() == data2.length + convertInputStreamToByteArray(appendBlobClient.openInputStream()) == data2 + } + + @LiveOnly + def "AppendBlob output stream overwrite false"() { + setup: + def data = getRandomByteArray(Constants.MB) + def appendBlobClient = cc.getBlobClient(generateBlobName()).getAppendBlobClient() + appendBlobClient.create() + + when: + def outputStream = appendBlobClient.getBlobOutputStream() + outputStream.write(data) + outputStream.close() + + then: + convertInputStreamToByteArray(appendBlobClient.openInputStream()) == data + + when: + def data2 = getRandomByteArray(Constants.MB) + outputStream = appendBlobClient.getBlobOutputStream(false) + outputStream.write(data2) + outputStream.close() + + then: + def finalData = new byte[2 * Constants.MB] + System.arraycopy(data, 0, finalData, 0, data.length) + System.arraycopy(data2, 0, finalData, data.length, data2.length) + convertInputStreamToByteArray(appendBlobClient.openInputStream()) == finalData + } + def convertInputStreamToByteArray(InputStream inputStream) { int b ByteArrayOutputStream outputStream = new ByteArrayOutputStream()