From 9012e3b93bd013df3934971078be591fa004aa99 Mon Sep 17 00:00:00 2001 From: empassaro <113031808+empassaro@users.noreply.github.com> Date: Tue, 27 Aug 2024 16:01:43 +0200 Subject: [PATCH] [SELC-4840] feat: added ivass client and ivass connector in rest connectors (#221) --- .../azure_storage/IvassDataConnectorImpl.java | 5 ++ .../connector/rest/IvassConnectorImpl.java | 62 ++++++++++++++ .../rest/client/IvassRestClient.java | 31 +++++++ .../rest/config/RestTemplateConfig.java | 44 ++++++++++ .../config/ivass-rest-config.properties | 4 + .../rest/IvassConnectorImplTest.java | 80 +++++++++++++++++++ .../rest/client/IvassRestClientTest.java | 45 +++++++++++ .../registry_proxy/core/IvassServiceImpl.java | 23 +++++- .../core/IvassServiceImplTest.java | 16 +++- 9 files changed, 308 insertions(+), 2 deletions(-) create mode 100644 connector/rest/src/main/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/IvassConnectorImpl.java create mode 100644 connector/rest/src/main/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/client/IvassRestClient.java create mode 100644 connector/rest/src/main/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/config/RestTemplateConfig.java create mode 100644 connector/rest/src/main/resources/config/ivass-rest-config.properties create mode 100644 connector/rest/src/test/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/IvassConnectorImplTest.java create mode 100644 connector/rest/src/test/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/client/IvassRestClientTest.java diff --git a/connector/azure_storage/src/main/java/it/pagopa/selfcare/party/connector/azure_storage/IvassDataConnectorImpl.java b/connector/azure_storage/src/main/java/it/pagopa/selfcare/party/connector/azure_storage/IvassDataConnectorImpl.java index 70287c73..d08c4238 100644 --- a/connector/azure_storage/src/main/java/it/pagopa/selfcare/party/connector/azure_storage/IvassDataConnectorImpl.java +++ b/connector/azure_storage/src/main/java/it/pagopa/selfcare/party/connector/azure_storage/IvassDataConnectorImpl.java @@ -9,6 +9,7 @@ import it.pagopa.selfcare.party.registry_proxy.connector.model.ResourceResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; @@ -24,6 +25,10 @@ @Service @Slf4j @PropertySource("classpath:config/ivass-config.properties") +@ConditionalOnProperty( + value = "ivass.file.connector.type", + havingValue = "azure", + matchIfMissing = true) public class IvassDataConnectorImpl implements IvassDataConnector { private final FileStorageConnector fileStorageConnector; diff --git a/connector/rest/src/main/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/IvassConnectorImpl.java b/connector/rest/src/main/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/IvassConnectorImpl.java new file mode 100644 index 00000000..4002c69d --- /dev/null +++ b/connector/rest/src/main/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/IvassConnectorImpl.java @@ -0,0 +1,62 @@ +package it.pagopa.selfcare.party.registry_proxy.connector.rest; + +import it.pagopa.selfcare.party.registry_proxy.connector.api.IvassDataConnector; +import it.pagopa.selfcare.party.registry_proxy.connector.model.InsuranceCompany; +import it.pagopa.selfcare.party.registry_proxy.connector.rest.client.IvassRestClient; +import it.pagopa.selfcare.party.registry_proxy.connector.rest.utils.IvassUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service +@PropertySource("classpath:config/ivass-rest-config.properties") +@ConditionalOnProperty( + value = "ivass.file.connector.type", + havingValue = "rest") +public class IvassConnectorImpl implements IvassDataConnector { + private final IvassRestClient ivassRestClient; + private final List registryTypesAdmitted; + private final List workTypesAdmitted; + private final IvassUtils ivassUtils; + + public IvassConnectorImpl( + IvassRestClient ivassRestClient, + @Value("#{'${ivass.registryTypes.admitted}'.split(',')}") List registryTypes, + @Value("#{'${ivass.workTypes.admitted}'.split(',')}") List registryWorkTypes, + IvassUtils ivassUtils + ) { + this.ivassRestClient = ivassRestClient; + this.registryTypesAdmitted = registryTypes; + this.workTypesAdmitted = registryWorkTypes; + this.ivassUtils = ivassUtils; + } + + @Override + public List getInsurances() { + byte[] zip = ivassRestClient.getInsurancesZip(); + byte[] csv = ivassUtils.extractFirstEntryByteArrayFromZip(zip); + csv = ivassUtils.manageUTF8BOM(csv); + List companies = ivassUtils.readCsv(csv); + return filterCompanies(companies); + } + + private List filterCompanies(List companies) { + return companies + .stream() + .filter(company -> StringUtils.hasText(company.getDigitalAddress()) + && workTypesAdmitted.contains(company.getWorkType()) + && registryTypesAdmitted + .stream() + .anyMatch(StringUtils.trimAllWhitespace(company.getRegisterType() + .split("-")[0])::equals)) + .collect(Collectors.toList()); + } + +} diff --git a/connector/rest/src/main/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/client/IvassRestClient.java b/connector/rest/src/main/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/client/IvassRestClient.java new file mode 100644 index 00000000..cd632805 --- /dev/null +++ b/connector/rest/src/main/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/client/IvassRestClient.java @@ -0,0 +1,31 @@ +package it.pagopa.selfcare.party.registry_proxy.connector.rest.client; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +@Slf4j +@Component +@PropertySource("classpath:config/ivass-rest-config.properties") +public class IvassRestClient { + private final RestTemplate ivassRestTemplate; + private final String ivassBasePath; + private final String getInsurancesPath; + + public IvassRestClient( + @Value("${ivass.rest.endpoint}") String ivassBasePath, + @Value("${ivass.rest.getInsurances.path}") String getInsurancesPath, + RestTemplate ivassRestTemplate) { + this.ivassRestTemplate = ivassRestTemplate; + this.ivassBasePath = ivassBasePath; + this.getInsurancesPath = getInsurancesPath; + } + + public byte[] getInsurancesZip() { + log.info("getInsurances start"); + String apiPath = this.ivassBasePath + getInsurancesPath; + return ivassRestTemplate.getForObject(apiPath, byte[].class); + } +} diff --git a/connector/rest/src/main/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/config/RestTemplateConfig.java b/connector/rest/src/main/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/config/RestTemplateConfig.java new file mode 100644 index 00000000..341b7bd1 --- /dev/null +++ b/connector/rest/src/main/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/config/RestTemplateConfig.java @@ -0,0 +1,44 @@ +package it.pagopa.selfcare.party.registry_proxy.connector.rest.config; + +import it.pagopa.selfcare.party.registry_proxy.connector.rest.decoder.RestTemplateErrorHandler; +import it.pagopa.selfcare.party.registry_proxy.connector.rest.interceptor.IvassInterceptor; +import org.apache.http.client.CookieStore; +import org.apache.http.impl.client.BasicCookieStore; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.LaxRedirectStrategy; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + +import java.util.List; + +@Configuration +public class RestTemplateConfig { + private final IvassInterceptor ivassInterceptor; + private final RestTemplateErrorHandler restTemplateErrorHandler; + + public RestTemplateConfig(IvassInterceptor ivassInterceptor, RestTemplateErrorHandler restTemplateErrorHandler) { + this.ivassInterceptor = ivassInterceptor; + this.restTemplateErrorHandler = restTemplateErrorHandler; + } + + @Bean + public RestTemplate ivassRestTemplate() { + CookieStore cookieStore = new BasicCookieStore(); + + CloseableHttpClient httpClient = HttpClientBuilder.create() + .setDefaultCookieStore(cookieStore) + .setRedirectStrategy(new LaxRedirectStrategy()) + .build(); + + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); + + RestTemplate restTemplate = new RestTemplate(factory); + restTemplate.setInterceptors(List.of(ivassInterceptor)); + restTemplate.setErrorHandler(restTemplateErrorHandler); + return restTemplate; + } + +} diff --git a/connector/rest/src/main/resources/config/ivass-rest-config.properties b/connector/rest/src/main/resources/config/ivass-rest-config.properties new file mode 100644 index 00000000..66441641 --- /dev/null +++ b/connector/rest/src/main/resources/config/ivass-rest-config.properties @@ -0,0 +1,4 @@ +ivass.rest.endpoint=${IVASS_BASE_URL:http://localhost:8085} +ivass.rest.getInsurances.path=/RIGAInquiry-public/getAreaDownloadExport.do?referenceDate=&product=VFLUSSO_IMPRESE&language=IT&exportType=CSV&isCompressed=S +ivass.registryTypes.admitted=${IVASS_REGISTRY_TYPES:ElencoI,ElencoII,SezioneI,SezioneII} +ivass.workTypes.admitted=${IVASS_WORK_TYPES:VITA,PICCOLO CUMULO,MISTA} diff --git a/connector/rest/src/test/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/IvassConnectorImplTest.java b/connector/rest/src/test/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/IvassConnectorImplTest.java new file mode 100644 index 00000000..92f1bd8f --- /dev/null +++ b/connector/rest/src/test/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/IvassConnectorImplTest.java @@ -0,0 +1,80 @@ +package it.pagopa.selfcare.party.registry_proxy.connector.rest; + +import it.pagopa.selfcare.party.registry_proxy.connector.model.InsuranceCompany; +import it.pagopa.selfcare.party.registry_proxy.connector.rest.client.IvassRestClient; +import it.pagopa.selfcare.party.registry_proxy.connector.rest.model.IvassDataTemplate; +import it.pagopa.selfcare.party.registry_proxy.connector.rest.utils.IvassUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + +class IvassConnectorImplTest { + private IvassRestClient ivassRestClient; + private IvassUtils ivassUtils; + private IvassConnectorImpl ivassConnector; + + @BeforeEach + void setUp() { + this.ivassRestClient = mock(IvassRestClient.class); + this.ivassUtils = mock(IvassUtils.class); + List registryTypes = Arrays.asList("ElencoI","ElencoII","SezioneI","SezioneII"); + List workTypes = Arrays.asList("VITA","PICCOLO CUMULO","MISTA"); + ivassConnector = new IvassConnectorImpl(ivassRestClient, registryTypes, workTypes, ivassUtils); + } + + @Test + void getInsurances_shouldReturnFilteredCompanies() { + byte[] zip = new byte[]{0, 1, 2, 3, 4}; + byte[] csv = new byte[]{5, 6, 7, 8, 9}; + + IvassDataTemplate company1 = new IvassDataTemplate(); + company1.setDigitalAddress("digitalAddress1"); + company1.setWorkType("VITA"); + company1.setRegisterType("ElencoI - test"); + company1.setTaxCode("taxCode1"); + + IvassDataTemplate company2 = new IvassDataTemplate(); + company2.setDigitalAddress("digitalAddress2"); + company2.setWorkType("VITA"); + company2.setRegisterType("ElencoII - test"); + company2.setTaxCode("taxCode2"); + + + List companies = Arrays.asList(company1, company2); + + when(ivassRestClient.getInsurancesZip()).thenReturn(zip); + when(ivassUtils.extractFirstEntryByteArrayFromZip(zip)).thenReturn(csv); + when(ivassUtils.readCsv(csv)).thenReturn(companies); + when(ivassUtils.manageUTF8BOM(csv)).thenReturn(csv); + + List result = ivassConnector.getInsurances(); + + assertEquals(companies.size(), result.size()); + verify(ivassRestClient, times(1)).getInsurancesZip(); + verify(ivassUtils, times(1)).extractFirstEntryByteArrayFromZip(zip); + } + + @Test + void getInsurances_shouldReturnEmptyList_whenNoCompaniesMatchFilter() { + byte[] zip = new byte[]{0, 1, 2, 3, 4}; + byte[] csv = new byte[]{5, 6, 7, 8, 9}; + List companies = Arrays.asList(new IvassDataTemplate(), new IvassDataTemplate()); + + when(ivassRestClient.getInsurancesZip()).thenReturn(zip); + when(ivassUtils.extractFirstEntryByteArrayFromZip(zip)).thenReturn(csv); + when(ivassUtils.readCsv(csv)).thenReturn(companies); + + ivassConnector = spy(ivassConnector); + + List result = ivassConnector.getInsurances(); + + assertEquals(0, result.size()); + verify(ivassRestClient, times(1)).getInsurancesZip(); + verify(ivassUtils, times(1)).extractFirstEntryByteArrayFromZip(zip); + } +} \ No newline at end of file diff --git a/connector/rest/src/test/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/client/IvassRestClientTest.java b/connector/rest/src/test/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/client/IvassRestClientTest.java new file mode 100644 index 00000000..0ce3710d --- /dev/null +++ b/connector/rest/src/test/java/it/pagopa/selfcare/party/registry_proxy/connector/rest/client/IvassRestClientTest.java @@ -0,0 +1,45 @@ +package it.pagopa.selfcare.party.registry_proxy.connector.rest.client; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.web.client.RestTemplate; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.*; + +class IvassRestClientTest { + + @Mock + private RestTemplate restTemplate; + + @InjectMocks + private IvassRestClient ivassRestClient; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + ivassRestClient = new IvassRestClient("http://example.com", "getInsurancesPath", restTemplate); + } + + @Test + void getInsurancesZip_shouldReturnByteArray_whenSuccessful() { + byte[] expectedResponse = new byte[]{1, 2, 3}; + when(restTemplate.getForObject(anyString(), eq(byte[].class))).thenReturn(expectedResponse); + + byte[] result = ivassRestClient.getInsurancesZip(); + + assertArrayEquals(expectedResponse, result); + verify(restTemplate, times(1)).getForObject(anyString(), eq(byte[].class)); + } + + @Test + void getInsurancesZip_shouldThrowException_whenRestTemplateThrowsException() { + when(restTemplate.getForObject(anyString(), eq(byte[].class))).thenThrow(new RuntimeException("Test exception")); + + assertThrows(RuntimeException.class, () -> ivassRestClient.getInsurancesZip()); + } +} \ No newline at end of file diff --git a/core/src/main/java/it/pagopa/selfcare/party/registry_proxy/core/IvassServiceImpl.java b/core/src/main/java/it/pagopa/selfcare/party/registry_proxy/core/IvassServiceImpl.java index 2813167a..e3228021 100644 --- a/core/src/main/java/it/pagopa/selfcare/party/registry_proxy/core/IvassServiceImpl.java +++ b/core/src/main/java/it/pagopa/selfcare/party/registry_proxy/core/IvassServiceImpl.java @@ -1,6 +1,8 @@ package it.pagopa.selfcare.party.registry_proxy.core; import it.pagopa.selfcare.party.registry_proxy.connector.api.IndexSearchService; +import it.pagopa.selfcare.party.registry_proxy.connector.api.IndexWriterService; +import it.pagopa.selfcare.party.registry_proxy.connector.api.IvassDataConnector; import it.pagopa.selfcare.party.registry_proxy.connector.exception.ResourceNotFoundException; import it.pagopa.selfcare.party.registry_proxy.connector.model.Entity; import it.pagopa.selfcare.party.registry_proxy.connector.model.InsuranceCompany; @@ -8,6 +10,7 @@ import it.pagopa.selfcare.party.registry_proxy.core.exception.TooManyResourceFoundException; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import java.util.List; @@ -18,11 +21,19 @@ public class IvassServiceImpl implements IvassService { private final IndexSearchService indexSearchService; + private final IvassDataConnector ivassDataConnector; + private final IndexWriterService indexWriterService; @Autowired - IvassServiceImpl(IndexSearchService indexSearchService) { + IvassServiceImpl( + IndexSearchService indexSearchService, + IndexWriterService indexWriterService, + IvassDataConnector ivassDataConnector + ) { log.trace("Initializing {}", IvassServiceImpl.class.getSimpleName()); this.indexSearchService = indexSearchService; + this.indexWriterService = indexWriterService; + this.ivassDataConnector = ivassDataConnector; } /** @@ -71,4 +82,14 @@ public QueryResult search(Optional searchText, int pag return queryResult; } + @Scheduled(cron = "0 0 0/6 * * *") + void updateIvassIndex() { + log.trace("start update IVASS Stations index"); + List companies = ivassDataConnector.getInsurances(); + if (!companies.isEmpty()) { + indexWriterService.cleanIndex(Entity.INSURANCE_COMPANY.toString()); + indexWriterService.adds(companies); + } + log.trace("updated IVASS Stations index end"); + } } diff --git a/core/src/test/java/it/pagopa/selfcare/party/registry_proxy/core/IvassServiceImplTest.java b/core/src/test/java/it/pagopa/selfcare/party/registry_proxy/core/IvassServiceImplTest.java index 13a49613..e240c0d1 100644 --- a/core/src/test/java/it/pagopa/selfcare/party/registry_proxy/core/IvassServiceImplTest.java +++ b/core/src/test/java/it/pagopa/selfcare/party/registry_proxy/core/IvassServiceImplTest.java @@ -1,9 +1,12 @@ package it.pagopa.selfcare.party.registry_proxy.core; import it.pagopa.selfcare.party.registry_proxy.connector.api.IndexSearchService; +import it.pagopa.selfcare.party.registry_proxy.connector.api.IndexWriterService; +import it.pagopa.selfcare.party.registry_proxy.connector.api.IvassDataConnector; import it.pagopa.selfcare.party.registry_proxy.connector.exception.ResourceNotFoundException; import it.pagopa.selfcare.party.registry_proxy.connector.model.*; import it.pagopa.selfcare.party.registry_proxy.core.exception.TooManyResourceFoundException; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.function.Executable; @@ -23,7 +26,10 @@ class IvassServiceImplTest { @Mock private IndexSearchService indexSearchService; - + @Mock + private IvassDataConnector ivassDataConnector; + @Mock + private IndexWriterService indexWriterService; @InjectMocks private IvassServiceImpl ivassService; @@ -144,4 +150,12 @@ void search_notEmptySearchText() { .fullTextSearch(InsuranceCompany.Field.DESCRIPTION, searchText.get(), page, limit); verifyNoMoreInteractions(indexSearchService); } + + @Test + void updateIvassIndex() { + List companies = List.of(new DummyInsuranceCompany()); + when(ivassDataConnector.getInsurances()).thenReturn(companies); + Executable executable = () -> ivassService.updateIvassIndex(); + Assertions.assertDoesNotThrow(executable); + } } \ No newline at end of file