diff --git a/pom.xml b/pom.xml
index f91cd79fbc865989163056b9f0685c8cb157de57..955c93f1ae13df87c9e456b3d53357b13969e9fd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
org.opengroup.osdu
core-lib-azure
jar
- 0.0.21
+ 0.0.22
core-lib-azure
diff --git a/src/main/java/org/opengroup/osdu/azure/blobstorage/BlobStore.java b/src/main/java/org/opengroup/osdu/azure/blobstorage/BlobStore.java
index cf88d09af438db950fc79f1b13198da724e4f10b..fb2748f3f6fa3b38bad4f3a65cc61b3dbc433045 100644
--- a/src/main/java/org/opengroup/osdu/azure/blobstorage/BlobStore.java
+++ b/src/main/java/org/opengroup/osdu/azure/blobstorage/BlobStore.java
@@ -15,6 +15,7 @@
package org.opengroup.osdu.azure.blobstorage;
import com.azure.storage.blob.BlobContainerClient;
+import com.azure.storage.blob.BlobServiceClient;
import com.azure.storage.blob.models.BlobErrorCode;
import com.azure.storage.blob.models.BlobStorageException;
import com.azure.storage.blob.specialized.BlockBlobClient;
@@ -55,6 +56,23 @@ import java.util.Collections;;
* {
* Boolean success = blobStorage.deleteFromBlob("dataPartitionId", "filePath");
* }
+ *
+ * String readFromStorageContainerExamole()
+ * {
+ * String content = blobStorage.readFromStorageContainer("dataPartitionId", "filePath", "containerName");
+ * if (content != null)
+ * return content;
+ * }
+ *
+ * void writeToStorageContainerExample()
+ * {
+ * blobStorage.writeToStorageContainer("dataPartitionId", "filePath", "content", "containerName");
+ * }
+ *
+ * void deleteFromStorageContainerExample()
+ * {
+ * Boolean success = blobStorage.deleteFromStorageContainer("dataPartitionId", "filePath", "containerName");
+ * }
* }
*
*/
@@ -66,6 +84,9 @@ public class BlobStore {
@Autowired
private IBlobContainerClientFactory blobContainerClientFactory;
+ @Autowired
+ private IBlobServiceClientFactory blobServiceClientFactory;
+
@Autowired
private ILogger logger;
@@ -136,8 +157,8 @@ public class BlobStore {
* @param dataPartitionId Data partition id
*/
public void writeToBlob(final String dataPartitionId,
- final String filePath,
- final String content) {
+ final String filePath,
+ final String content) {
byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
int bytesSize = bytes.length;
BlobContainerClient blobContainerClient = getBlobContainerClient(dataPartitionId);
@@ -155,6 +176,102 @@ public class BlobStore {
}
}
+ /**
+ *
+ * @param filePath Path of file to be read.
+ * @param dataPartitionId Data partition id
+ * @param containerName Name of the storage container
+ * @return the content of file with provided file path.
+ */
+ public String readFromStorageContainer(
+ final String dataPartitionId,
+ final String filePath,
+ final String containerName) {
+ BlobContainerClient blobContainerClient = getBlobContainerClient(dataPartitionId, containerName);
+ BlockBlobClient blockBlobClient = blobContainerClient.getBlobClient(filePath).getBlockBlobClient();
+ try (ByteArrayOutputStream downloadStream = new ByteArrayOutputStream()) {
+ blockBlobClient.download(downloadStream);
+ return downloadStream.toString(StandardCharsets.UTF_8.name());
+ } catch (BlobStorageException ex) {
+ if (ex.getErrorCode().equals(BlobErrorCode.BLOB_NOT_FOUND)) {
+ String errorMessage = "Specified blob was not found";
+ logger.warning(LOG_PREFIX, errorMessage, Collections.emptyMap());
+ throw new AppException(404, errorMessage, ex.getMessage(), ex);
+ } else {
+ String errorMessage = "Failed to read specified blob";
+ logger.warning(LOG_PREFIX, errorMessage, Collections.emptyMap());
+ throw new AppException(500, errorMessage, ex.getMessage(), ex);
+ }
+ } catch (UnsupportedEncodingException ex) {
+ String errorMessage = String.format("Encoding was not correct for item with name=%s", filePath);
+ logger.warning(LOG_PREFIX, errorMessage, Collections.emptyMap());
+ throw new AppException(400, errorMessage, ex.getMessage(), ex);
+ } catch (IOException ex) {
+ String errorMessage = String.format("Malformed document for item with name=%s", filePath);
+ logger.warning(LOG_PREFIX, errorMessage, Collections.emptyMap());
+ throw new AppException(500, errorMessage, ex.getMessage(), ex);
+ }
+ }
+
+ /**
+ *
+ * @param filePath Path of file to be deleted.
+ * @param dataPartitionId Data partition id
+ * @param containerName Name of the storage container
+ * @return boolean indicating whether the deletion of given file was successful or not.
+ */
+ public boolean deleteFromStorageContainer(
+ final String dataPartitionId,
+ final String filePath,
+ final String containerName) {
+ BlobContainerClient blobContainerClient = getBlobContainerClient(dataPartitionId, containerName);
+ BlockBlobClient blockBlobClient = blobContainerClient.getBlobClient(filePath).getBlockBlobClient();
+ try {
+ blockBlobClient.delete();
+ return true;
+ } catch (BlobStorageException ex) {
+ if (ex.getErrorCode().equals(BlobErrorCode.BLOB_NOT_FOUND)) {
+ String errorMessage = "Specified blob was not found";
+ logger.warning(LOG_PREFIX, errorMessage, Collections.emptyMap());
+ throw new AppException(404, errorMessage, ex.getMessage(), ex);
+ } else {
+ String errorMessage = "Failed to delete blob";
+ logger.warning(LOG_PREFIX, errorMessage, Collections.emptyMap());
+ throw new AppException(500, errorMessage, ex.getMessage(), ex);
+ }
+ }
+ }
+
+ /**
+ *
+ * @param filePath Path of file to be written at.
+ * @param content Content to be written in the file.
+ * @param dataPartitionId Data partition id
+ * @param containerName Name of the storage container
+ */
+ public void writeToStorageContainer(
+ final String dataPartitionId,
+ final String filePath,
+ final String content,
+ final String containerName) {
+ byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
+ int bytesSize = bytes.length;
+ BlobContainerClient blobContainerClient = getBlobContainerClient(dataPartitionId, containerName);
+ BlockBlobClient blockBlobClient = blobContainerClient.getBlobClient(filePath).getBlockBlobClient();
+ try (ByteArrayInputStream dataStream = new ByteArrayInputStream(bytes)) {
+ blockBlobClient.upload(dataStream, bytesSize, true);
+ } catch (BlobStorageException ex) {
+ String errorMessage = "Failed to upload file content.";
+ logger.warning(LOG_PREFIX, errorMessage, Collections.emptyMap());
+ throw new AppException(500, errorMessage, ex.getMessage(), ex);
+ } catch (IOException ex) {
+ String errorMessage = String.format("Malformed document for item with name=%s", filePath);
+ logger.warning(LOG_PREFIX, errorMessage, Collections.emptyMap());
+ throw new AppException(500, errorMessage, ex.getMessage(), ex);
+ }
+ }
+
+
/**
*
* @param dataPartitionId Data partition id
@@ -169,5 +286,22 @@ public class BlobStore {
throw new AppException(500, errorMessage, ex.getMessage(), ex);
}
}
-}
+ /**
+ *
+ * @param dataPartitionId Data partition id.
+ * @param containerName Name of storage container.
+ * @return blob container client corresponding to the dataPartitionId.
+ */
+ private BlobContainerClient getBlobContainerClient(final String dataPartitionId, final String containerName) {
+ try {
+ BlobServiceClient serviceClient = blobServiceClientFactory.getBlobServiceClient(dataPartitionId);
+ return serviceClient.getBlobContainerClient(containerName);
+ } catch (Exception ex) {
+ String errorMessage = "Error creating creating blob container client.";
+ logger.warning(LOG_PREFIX, errorMessage, Collections.emptyMap());
+ throw new AppException(500, errorMessage, ex.getMessage(), ex);
+ }
+ }
+
+}
diff --git a/src/test/java/org/opengroup/osdu/azure/blobstorage/BlobStoreTest.java b/src/test/java/org/opengroup/osdu/azure/blobstorage/BlobStoreTest.java
index 453367ae50d18744888cafb457f2623b6493e9a7..b7c1f53c70b97bea1a5b4e8b3cac540d686f9813 100644
--- a/src/test/java/org/opengroup/osdu/azure/blobstorage/BlobStoreTest.java
+++ b/src/test/java/org/opengroup/osdu/azure/blobstorage/BlobStoreTest.java
@@ -16,6 +16,7 @@ package org.opengroup.osdu.azure.blobstorage;
import com.azure.storage.blob.BlobClient;
import com.azure.storage.blob.BlobContainerClient;
+import com.azure.storage.blob.BlobServiceClient;
import com.azure.storage.blob.models.BlobErrorCode;
import com.azure.storage.blob.models.BlobStorageException;
import com.azure.storage.blob.models.BlockBlobItem;
@@ -44,6 +45,7 @@ public class BlobStoreTest {
private static final String PARTITION_ID = "dataPartitionId";
private static final String FILE_PATH = "filePath";
private static final String CONTENT = "hello world";
+ private static final String STORAGE_CONTAINER_NAME = "containerName";
@InjectMocks
BlobStore blobStore;
@@ -51,6 +53,12 @@ public class BlobStoreTest {
@Mock
IBlobContainerClientFactory blobContainerClientFactory;
+ @Mock
+ IBlobServiceClientFactory blobServiceClientFactory;
+
+ @Mock
+ BlobServiceClient blobServiceClient;
+
@Mock
BlobContainerClient blobContainerClient;
@@ -69,9 +77,11 @@ public class BlobStoreTest {
@BeforeEach
void init() {
initMocks(this);
- lenient().doReturn(blobContainerClient).when(blobContainerClientFactory).getClient(PARTITION_ID);
- lenient().doReturn(blobClient).when(blobContainerClient).getBlobClient(FILE_PATH);
- lenient().doReturn(blockBlobClient).when(blobClient).getBlockBlobClient();
+ lenient().when(blobClient.getBlockBlobClient()).thenReturn(blockBlobClient);
+ lenient().when(blobContainerClient.getBlobClient(FILE_PATH)).thenReturn(blobClient);
+ lenient().when(blobServiceClient.getBlobContainerClient(STORAGE_CONTAINER_NAME)).thenReturn(blobContainerClient);
+ lenient().when(blobServiceClientFactory.getBlobServiceClient(PARTITION_ID)).thenReturn(blobServiceClient);
+ lenient().when(blobContainerClientFactory.getClient(PARTITION_ID)).thenReturn(blobContainerClient);
lenient().doNothing().when(logger).warning(eq("azure-core-lib"), any(), anyMap());
}
@@ -216,6 +226,160 @@ public class BlobStoreTest {
}
}
+ @Test
+ public void readFromStorageContainer_ErrorCreatingBlobContainerClient()
+ {
+ doThrow(AppException.class).when(blobServiceClientFactory).getBlobServiceClient(eq(PARTITION_ID));
+ try {
+ String content = blobStore.readFromStorageContainer(PARTITION_ID, FILE_PATH, STORAGE_CONTAINER_NAME);
+ } catch (AppException ex) {
+ assertEquals(500, ex.getError().getCode());
+ } catch (Exception ex) {
+ fail("should not get different error code");
+ }
+ }
+
+ @Test
+ public void readFromStorageContainer_ErrorCreatingBlobContainerClient_FromServiceClient()
+ {
+ doThrow(AppException.class).when(blobServiceClient).getBlobContainerClient(eq(STORAGE_CONTAINER_NAME));
+ try {
+ String content = blobStore.readFromStorageContainer(PARTITION_ID, FILE_PATH, STORAGE_CONTAINER_NAME);
+ } catch (AppException ex) {
+ assertEquals(500, ex.getError().getCode());
+ } catch (Exception ex) {
+ fail("should not get different error code");
+ }
+ }
+
+ @Test
+ public void readFromStorageContainer_Success()
+ {
+ String content = blobStore.readFromStorageContainer(PARTITION_ID, FILE_PATH, STORAGE_CONTAINER_NAME);
+ ArgumentCaptor outputStream = ArgumentCaptor.forClass(ByteArrayOutputStream.class);
+
+ // validate that the download method is being invoked appropriately.
+ verify(blockBlobClient).download(outputStream.capture());
+ }
+
+ @Test
+ public void readFromStorageContainer_BlobNotFound()
+ {
+ BlobStorageException exception = mockStorageException(BlobErrorCode.BLOB_NOT_FOUND);
+ doThrow(exception).when(blockBlobClient).download(any());
+ try {
+ String content = blobStore.readFromStorageContainer(PARTITION_ID, FILE_PATH, STORAGE_CONTAINER_NAME);
+ } catch (AppException ex) {
+ assertEquals(404, ex.getError().getCode());
+ } catch (Exception ex) {
+ fail("should not get different error code");
+ }
+ }
+
+ @Test
+ public void readFromStorageContainer_InternalError()
+ {
+ BlobStorageException exception = mockStorageException(BlobErrorCode.INTERNAL_ERROR);
+ doThrow(exception).when(blockBlobClient).download(any());
+ try {
+ String content = blobStore.readFromStorageContainer(PARTITION_ID, FILE_PATH, STORAGE_CONTAINER_NAME);
+ } catch (AppException ex) {
+ assertEquals(500, ex.getError().getCode());
+ } catch (Exception ex) {
+ fail("should not get different error code");
+ }
+ }
+
+ @Test
+ public void deleteFromStorageContainer_ErrorCreatingBlobContainerClient()
+ {
+ doThrow(AppException.class).when(blobServiceClientFactory).getBlobServiceClient(eq(PARTITION_ID));
+ try {
+ blobStore.deleteFromStorageContainer(PARTITION_ID, FILE_PATH, STORAGE_CONTAINER_NAME);
+ } catch (AppException ex) {
+ assertEquals(500, ex.getError().getCode());
+ } catch (Exception ex) {
+ fail("should not get different error code");
+ }
+ }
+
+ @Test
+ public void deleteFromStorageContainer_BlobNotFound()
+ {
+ BlobStorageException exception = mockStorageException(BlobErrorCode.BLOB_NOT_FOUND);
+ doThrow(exception).when(blockBlobClient).delete();
+ try {
+ blobStore.deleteFromStorageContainer(PARTITION_ID, FILE_PATH, STORAGE_CONTAINER_NAME);
+ } catch (AppException ex) {
+ assertEquals(404, ex.getError().getCode());
+ } catch (Exception ex) {
+ fail("should not get different error code");
+ }
+ }
+
+ @Test
+ public void deleteFromStorageContainer_InternalError()
+ {
+ BlobStorageException exception = mockStorageException(BlobErrorCode.INTERNAL_ERROR);
+ doThrow(exception).when(blockBlobClient).delete();
+ try {
+ blobStore.deleteFromStorageContainer(PARTITION_ID, FILE_PATH, STORAGE_CONTAINER_NAME);
+ } catch (AppException ex) {
+ assertEquals(500, ex.getError().getCode());
+ } catch (Exception ex) {
+ fail("should not get different error code");
+ }
+ }
+
+ @Test
+ public void deleteFromStorageContainer_Success()
+ {
+ doNothing().when(blockBlobClient).delete();
+ try {
+ blobStore.deleteFromStorageContainer(PARTITION_ID, FILE_PATH, STORAGE_CONTAINER_NAME);
+ } catch (Exception ex) {
+ fail("should not get any exception.");
+ }
+ }
+
+ @Test
+ public void writeToStorageContainer_ErrorCreatingBlobContainerClient()
+ {
+ doThrow(AppException.class).when(blobServiceClientFactory).getBlobServiceClient(eq(PARTITION_ID));
+ try {
+ blobStore.writeToStorageContainer(PARTITION_ID, FILE_PATH, CONTENT, STORAGE_CONTAINER_NAME);
+ } catch (AppException ex) {
+ assertEquals(500, ex.getError().getCode());
+ } catch (Exception ex) {
+ fail("should not get different error code");
+ }
+ }
+
+ @Test
+ public void writeToStorageContainer_InternalError()
+ {
+ BlobStorageException exception = mockStorageException(BlobErrorCode.INTERNAL_ERROR);
+ doThrow(exception).when(blockBlobClient).upload(any(), anyLong(), eq(true));
+ try {
+ blobStore.writeToStorageContainer(PARTITION_ID, FILE_PATH, CONTENT, STORAGE_CONTAINER_NAME);
+ } catch (AppException ex) {
+ assertEquals(500, ex.getError().getCode());
+ } catch (Exception ex) {
+ fail("should not get different error code");
+ }
+ }
+
+ @Test
+ public void writeToStorageContainer_Success()
+ {
+ doReturn(blockBlobItem).when(blockBlobClient).upload(any(), anyLong(), eq(true));
+ try {
+ blobStore.writeToStorageContainer(PARTITION_ID, FILE_PATH, CONTENT, STORAGE_CONTAINER_NAME);
+ } catch (Exception ex) {
+ fail("should not get any exception.");
+ }
+ }
+
private BlobStorageException mockStorageException(BlobErrorCode errorCode) {
BlobStorageException mockException = mock(BlobStorageException.class);
lenient().when(mockException.getErrorCode()).thenReturn(errorCode);