From 1e5494692d022068fce0dc70e475984ad6e939c0 Mon Sep 17 00:00:00 2001 From: "Riabokon Stanislav(EPAM)[GCP]" <stanislav_riabokon@epam.com> Date: Fri, 13 Dec 2024 10:43:40 +0000 Subject: [PATCH] Add cache to fetch Legal_COO.json from blob storage (GONRG-10325) --- ...heConfig.java => CorePlusCacheConfig.java} | 8 +- .../countries/StorageReaderFactoryImpl.java | 10 +- .../legal/countries/StorageReaderImpl.java | 41 ++++---- .../countries/StorageReaderImplTests.java | 96 ++++++++++++++----- .../LegalTagCountriesTenantRepositories.java | 17 ++-- 5 files changed, 111 insertions(+), 61 deletions(-) rename legal-core-plus/src/main/java/org/opengroup/osdu/legal/config/{CacheConfig.java => CorePlusCacheConfig.java} (85%) diff --git a/legal-core-plus/src/main/java/org/opengroup/osdu/legal/config/CacheConfig.java b/legal-core-plus/src/main/java/org/opengroup/osdu/legal/config/CorePlusCacheConfig.java similarity index 85% rename from legal-core-plus/src/main/java/org/opengroup/osdu/legal/config/CacheConfig.java rename to legal-core-plus/src/main/java/org/opengroup/osdu/legal/config/CorePlusCacheConfig.java index 508e50439..2ac916767 100644 --- a/legal-core-plus/src/main/java/org/opengroup/osdu/legal/config/CacheConfig.java +++ b/legal-core-plus/src/main/java/org/opengroup/osdu/legal/config/CorePlusCacheConfig.java @@ -1,6 +1,6 @@ /* - * Copyright 2020-2023 Google LLC - * Copyright 2020-2023 EPAM Systems, Inc + * Copyright 2020-2024 Google LLC + * Copyright 2020-2024 EPAM Systems, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ package org.opengroup.osdu.legal.config; -import lombok.RequiredArgsConstructor; import org.opengroup.osdu.core.common.cache.ICache; import org.opengroup.osdu.core.common.cache.VmCache; import org.opengroup.osdu.core.common.partition.PartitionInfo; @@ -25,8 +24,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration -@RequiredArgsConstructor -public class CacheConfig { +public class CorePlusCacheConfig { @Bean public ICache<String, PartitionInfo> partitionInfoCache() { diff --git a/legal-core-plus/src/main/java/org/opengroup/osdu/legal/countries/StorageReaderFactoryImpl.java b/legal-core-plus/src/main/java/org/opengroup/osdu/legal/countries/StorageReaderFactoryImpl.java index b1bb384ad..e4e339c67 100644 --- a/legal-core-plus/src/main/java/org/opengroup/osdu/legal/countries/StorageReaderFactoryImpl.java +++ b/legal-core-plus/src/main/java/org/opengroup/osdu/legal/countries/StorageReaderFactoryImpl.java @@ -1,6 +1,6 @@ /* - * Copyright 2020-2023 Google LLC - * Copyright 2020-2023 EPAM Systems, Inc + * Copyright 2020-2024 Google LLC + * Copyright 2020-2024 EPAM Systems, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.opengroup.osdu.legal.countries; import lombok.RequiredArgsConstructor; +import org.opengroup.osdu.core.common.cache.ICache; import org.opengroup.osdu.core.common.model.tenant.TenantInfo; import org.opengroup.osdu.core.common.partition.PartitionPropertyResolver; import org.opengroup.osdu.core.obm.core.Driver; @@ -30,14 +31,13 @@ import org.springframework.stereotype.Component; public class StorageReaderFactoryImpl implements IStorageReaderFactory { private final Driver storage; - private final PartitionPropertyResolver partitionPropertyResolver; - private final PartitionPropertyNames partitionPropertyNames; + private final ICache<String, byte[]> legalCOOCache; @Override public IStorageReader getReader(TenantInfo tenant, String projectRegion) { return new StorageReaderImpl( - tenant, storage, partitionPropertyResolver, partitionPropertyNames); + tenant, storage, partitionPropertyResolver, partitionPropertyNames, legalCOOCache); } } diff --git a/legal-core-plus/src/main/java/org/opengroup/osdu/legal/countries/StorageReaderImpl.java b/legal-core-plus/src/main/java/org/opengroup/osdu/legal/countries/StorageReaderImpl.java index 63af08f12..80eb32367 100644 --- a/legal-core-plus/src/main/java/org/opengroup/osdu/legal/countries/StorageReaderImpl.java +++ b/legal-core-plus/src/main/java/org/opengroup/osdu/legal/countries/StorageReaderImpl.java @@ -1,6 +1,6 @@ /* - * Copyright 2020-2023 Google LLC - * Copyright 2020-2023 EPAM Systems, Inc + * Copyright 2020-2024 Google LLC + * Copyright 2020-2024 EPAM Systems, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,10 @@ package org.opengroup.osdu.legal.countries; +import java.util.Objects; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.opengroup.osdu.core.common.cache.ICache; import org.opengroup.osdu.core.common.model.tenant.TenantInfo; import org.opengroup.osdu.core.common.partition.PartitionPropertyResolver; import org.opengroup.osdu.core.obm.core.Driver; @@ -28,31 +30,31 @@ import org.opengroup.osdu.core.obm.core.persistence.ObmDestination; import org.opengroup.osdu.legal.config.PartitionPropertyNames; import org.opengroup.osdu.legal.provider.interfaces.IStorageReader; -import java.util.Objects; - @RequiredArgsConstructor @Slf4j public class StorageReaderImpl implements IStorageReader { + private static final String SEPARATOR = "-"; + private static final String FILE_NAME = "Legal_COO.json"; + protected static final String BUCKET_NAME = "legal-config"; + private PartitionPropertyResolver partitionPropertyResolver; private PartitionPropertyNames partitionPropertyNames; - private TenantInfo tenantInfo; private Driver storage; - - protected static final String BUCKET_NAME = "legal-config"; - private static final String FILE_NAME = "Legal_COO.json"; - private boolean isFullBucketName = false; + private ICache<String, byte[]> legalCOOCache; public StorageReaderImpl( TenantInfo tenantInfo, Driver storage, PartitionPropertyResolver partitionPropertyResolver, - PartitionPropertyNames partitionPropertyNames) { + PartitionPropertyNames partitionPropertyNames, + ICache<String, byte[]> legalCOOCache) { this.tenantInfo = tenantInfo; this.storage = storage; this.partitionPropertyResolver = partitionPropertyResolver; this.partitionPropertyNames = partitionPropertyNames; + this.legalCOOCache = legalCOOCache; } @Override @@ -66,12 +68,17 @@ public class StorageReaderImpl implements IStorageReader { log.warn("Bucket %s is not existing.".formatted(tenantBucketName)); return new byte[0]; } - - Blob blob = storage.getBlob(tenantBucketName, FILE_NAME, destination); - if (Objects.isNull(blob)) { - log.warn("File %s in bucket %s is not existing.".formatted(FILE_NAME, tenantBucketName)); + String dataPartitionId = tenantInfo.getDataPartitionId(); + if (Objects.isNull(legalCOOCache.get(dataPartitionId))) { + Blob blob = storage.getBlob(tenantBucketName, FILE_NAME, destination); + if (Objects.isNull(blob)) { + log.warn("File %s in bucket %s is not existing.".formatted(FILE_NAME, tenantBucketName)); + } else { + content = storage.getBlobContent(getTenantBucketName(), FILE_NAME, getDestination()); + legalCOOCache.put(dataPartitionId, content); + } } else { - content = storage.getBlobContent(getTenantBucketName(), FILE_NAME, getDestination()); + content = legalCOOCache.get(dataPartitionId); } } catch (ObmDriverRuntimeException e) { log.error(e.getMessage(), e); @@ -86,9 +93,9 @@ public class StorageReaderImpl implements IStorageReader { .orElseGet( () -> this.tenantInfo.getProjectId() - + "-" + + SEPARATOR + this.tenantInfo.getName() - + "-" + + SEPARATOR + BUCKET_NAME); } diff --git a/legal-core-plus/src/test/java/org/opengroup/osdu/legal/countries/StorageReaderImplTests.java b/legal-core-plus/src/test/java/org/opengroup/osdu/legal/countries/StorageReaderImplTests.java index 939b54e48..3ebb7cbea 100644 --- a/legal-core-plus/src/test/java/org/opengroup/osdu/legal/countries/StorageReaderImplTests.java +++ b/legal-core-plus/src/test/java/org/opengroup/osdu/legal/countries/StorageReaderImplTests.java @@ -17,13 +17,20 @@ package org.opengroup.osdu.legal.countries; -import org.junit.Before; +import static org.junit.Assert.*; +import static org.powermock.api.mockito.PowerMockito.when; + +import java.nio.charset.StandardCharsets; +import java.util.Optional; import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.junit.MockitoJUnitRunner; +import org.opengroup.osdu.core.common.cache.ICache; import org.opengroup.osdu.core.common.model.tenant.TenantInfo; import org.opengroup.osdu.core.common.partition.PartitionPropertyResolver; import org.opengroup.osdu.core.obm.core.Driver; @@ -32,32 +39,52 @@ import org.opengroup.osdu.core.obm.core.model.Bucket; import org.opengroup.osdu.core.obm.core.persistence.ObmDestination; import org.opengroup.osdu.legal.config.PartitionPropertyNames; -import java.util.Optional; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.powermock.api.mockito.PowerMockito.when; - @RunWith(MockitoJUnitRunner.class) public class StorageReaderImplTests { private static final String TENANT_1 = "tenant1"; private static final String FILE_NAME = "Legal_COO.json"; private static final String BUCKET_FULL_NAME = "tenant1-tenant1-legal-config"; + private static final String CONTENT = + """ + [{ + "name": "Malaysia", + "alpha2": "MY", + "numeric": 458, + "residencyRisk": "Client consent required" + }]"""; + private static final String PARTITION_BUCKET_NAME = "partition-bucket-name"; + + @Mock + private TenantInfo tenantInfo; + + @Mock + private Driver storage; - @Mock private TenantInfo tenantInfo; + @Mock + private PartitionPropertyNames partitionPropertyNames; - @Mock private Driver storage; + @Mock + private PartitionPropertyResolver partitionPropertyResolver; - @Mock private PartitionPropertyNames partitionPropertyNames; + @Mock + private ICache<String, byte[]> legalCOOCache; - @Mock private PartitionPropertyResolver partitionPropertyResolver; + @InjectMocks + private StorageReaderImpl sut; - @InjectMocks private StorageReaderImpl sut; + private AutoCloseable mocks; - @Before - public void setup() { - MockitoAnnotations.initMocks(this); + @BeforeEach + void setup() { + mocks = MockitoAnnotations.openMocks(this); + } + + @AfterEach + void tearDown() throws Exception { + if (mocks != null) { + mocks.close(); + } } @Test @@ -68,11 +95,12 @@ public class StorageReaderImplTests { when(storage.getBucket(BUCKET_FULL_NAME, getDestination())).thenReturn(new Bucket(TENANT_1)); when(storage.getBlob(BUCKET_FULL_NAME, FILE_NAME, getDestination())) .thenReturn(Blob.builder().build()); - byte[] expectedBytes = "test".getBytes(); + byte[] expectedBytes = CONTENT.getBytes(); when(storage.getBlobContent(BUCKET_FULL_NAME, FILE_NAME, getDestination())) .thenReturn(expectedBytes); - + byte[] bytes = sut.readAllBytes(); + assertEquals(expectedBytes, bytes); } @@ -83,7 +111,8 @@ public class StorageReaderImplTests { when(tenantInfo.getProjectId()).thenReturn(TENANT_1); byte[] bytes = sut.readAllBytes(); - assertTrue(bytes.length == 0); + + assertEquals(0, bytes.length); } @Test @@ -97,21 +126,40 @@ public class StorageReaderImplTests { when(storage.getBlobContent(BUCKET_FULL_NAME, FILE_NAME, getDestination())).thenReturn(null); byte[] bytes = sut.readAllBytes(); - assertTrue(bytes.length == 0); + + assertEquals(0, bytes.length); } @Test public void should_returnBucketName_fromPartition() { - when(partitionPropertyNames.getLegalBucketName()).thenReturn("partition-bucket-name"); + when(partitionPropertyNames.getLegalBucketName()).thenReturn(PARTITION_BUCKET_NAME); when(partitionPropertyResolver.getOptionalPropertyValue( partitionPropertyNames.getLegalBucketName(), tenantInfo.getDataPartitionId())) - .thenReturn(Optional.of("partition-bucket-name")); + .thenReturn(Optional.of(PARTITION_BUCKET_NAME)); + StorageReaderImpl storageReader = new StorageReaderImpl( - tenantInfo, storage, partitionPropertyResolver, partitionPropertyNames); - + tenantInfo, storage, partitionPropertyResolver, partitionPropertyNames, legalCOOCache); String resultBucketName = storageReader.getTenantBucketName(); - assertEquals("partition-bucket-name", resultBucketName); + + assertEquals(PARTITION_BUCKET_NAME, resultBucketName); + } + + @Test + public void shouldReturnContentAsBytes_whenCacheEntryFound() { + byte[] expected = CONTENT.getBytes(StandardCharsets.UTF_8); + when(tenantInfo.getName()).thenReturn(TENANT_1); + when(tenantInfo.getDataPartitionId()).thenReturn(TENANT_1); + when(tenantInfo.getProjectId()).thenReturn(TENANT_1); + when(storage.getBucket(BUCKET_FULL_NAME, getDestination())).thenReturn(new Bucket(TENANT_1)); + when(legalCOOCache.get(tenantInfo.getDataPartitionId())).thenReturn(expected); + + StorageReaderImpl storageReader = + new StorageReaderImpl( + tenantInfo, storage, partitionPropertyResolver, partitionPropertyNames, legalCOOCache); + byte[] actual = storageReader.readAllBytes(); + + assertArrayEquals(expected, actual); } private ObmDestination getDestination() { diff --git a/legal-core/src/main/java/org/opengroup/osdu/legal/countries/LegalTagCountriesTenantRepositories.java b/legal-core/src/main/java/org/opengroup/osdu/legal/countries/LegalTagCountriesTenantRepositories.java index 8979205ac..b893fcaae 100644 --- a/legal-core/src/main/java/org/opengroup/osdu/legal/countries/LegalTagCountriesTenantRepositories.java +++ b/legal-core/src/main/java/org/opengroup/osdu/legal/countries/LegalTagCountriesTenantRepositories.java @@ -1,20 +1,17 @@ package org.opengroup.osdu.legal.countries; +import jakarta.inject.Inject; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import lombok.extern.java.Log; +import org.apache.commons.lang3.StringUtils; +import org.opengroup.osdu.core.common.model.http.AppException; import org.opengroup.osdu.core.common.model.http.DpsHeaders; import org.opengroup.osdu.core.common.model.tenant.TenantInfo; -import org.opengroup.osdu.core.common.model.http.AppException; import org.opengroup.osdu.legal.provider.interfaces.IStorageReader; import org.opengroup.osdu.legal.provider.interfaces.IStorageReaderFactory; - import org.springframework.stereotype.Repository; -import lombok.extern.java.Log; -import org.apache.commons.lang3.StringUtils; - -import java.util.HashMap; -import java.util.Map; -import jakarta.inject.Inject; - @Repository @Log public class LegalTagCountriesTenantRepositories { @@ -22,7 +19,7 @@ public class LegalTagCountriesTenantRepositories { @Inject private IStorageReaderFactory storageReaderFactory; - private final Map<String, LegalTagCountriesRepository> countriesTenantRepositories = new HashMap<>(); + private final Map<String, LegalTagCountriesRepository> countriesTenantRepositories = new ConcurrentHashMap<>(); LegalTagCountriesRepository get(TenantInfo tenant, String projectRegion){ String tenantName = tenant.getName(); -- GitLab