From deac4777c1a245be1dc4c423658523b41071b110 Mon Sep 17 00:00:00 2001 From: JosephKeenan Date: Mon, 28 Mar 2022 12:26:07 +0100 Subject: Query based on Public CM Properties -Updated OpenAPI for new Endpoint -Will replace SQL with CPSPathQuery once investigation is complete -Functionality in place to determine if public properties match - -Added Unit and CSIT tests - small modifications may need to be made -CSIT tests enhanced to add additional nodes and tests Issue-ID: CPS-731 Change-Id: I403e603ce79c4a4a6994d51b459b5703510d5a83 Signed-off-by: DylanB95EST Signed-off-by: JosephKeenan --- .../spi/impl/CpsAdminPersistenceServiceImpl.java | 9 ++++ .../cps/spi/repository/ModuleReferenceQuery.java | 10 ++++ .../spi/repository/ModuleReferenceRepository.java | 3 +- .../repository/ModuleReferenceRepositoryImpl.java | 63 +++++++++++++++++++++- .../spi/impl/CpsAdminPersistenceServiceSpec.groovy | 25 ++++++++- cps-ri/src/test/resources/data/fragment.sql | 21 ++++++-- 6 files changed, 123 insertions(+), 8 deletions(-) (limited to 'cps-ri') diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java index 50b27207e..2e7bb7e96 100755 --- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java @@ -24,6 +24,7 @@ package org.onap.cps.spi.impl; import java.util.Collection; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import javax.transaction.Transactional; import lombok.AllArgsConstructor; @@ -36,8 +37,10 @@ import org.onap.cps.spi.exceptions.AlreadyDefinedException; import org.onap.cps.spi.exceptions.DataspaceInUseException; import org.onap.cps.spi.exceptions.ModuleNamesNotFoundException; import org.onap.cps.spi.model.Anchor; +import org.onap.cps.spi.model.CmHandleQueryParameters; import org.onap.cps.spi.repository.AnchorRepository; import org.onap.cps.spi.repository.DataspaceRepository; +import org.onap.cps.spi.repository.ModuleReferenceRepository; import org.onap.cps.spi.repository.SchemaSetRepository; import org.onap.cps.spi.repository.YangResourceRepository; import org.springframework.dao.DataIntegrityViolationException; @@ -51,6 +54,7 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic private final AnchorRepository anchorRepository; private final SchemaSetRepository schemaSetRepository; private final YangResourceRepository yangResourceRepository; + private final ModuleReferenceRepository moduleReferenceRepository; @Override public void createDataspace(final String dataspaceName) { @@ -132,6 +136,11 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic anchorRepository.delete(anchorEntity); } + @Override + public Set queryCmHandles(final CmHandleQueryParameters cmHandleQueryParameters) { + return moduleReferenceRepository.queryCmHandles(cmHandleQueryParameters); + } + private AnchorEntity getAnchorEntity(final String dataspaceName, final String anchorName) { final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName); return anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName); diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java index 6551937e1..4bc9dd960 100644 --- a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java @@ -21,6 +21,8 @@ package org.onap.cps.spi.repository; import java.util.Collection; +import java.util.Set; +import org.onap.cps.spi.model.CmHandleQueryParameters; import org.onap.cps.spi.model.ModuleReference; /** @@ -31,4 +33,12 @@ public interface ModuleReferenceQuery { Collection identifyNewModuleReferences( final Collection moduleReferencesToCheck); + /** + * Query and return cm handles that match the given query parameters. + * + * @param cmHandleQueryParameters the cm handle query parameters + * @return collection of cm handle ids + */ + Set queryCmHandles(CmHandleQueryParameters cmHandleQueryParameters); + } diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepository.java index ce2bfe784..f70e21837 100644 --- a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepository.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepository.java @@ -27,8 +27,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository -public interface ModuleReferenceRepository extends - JpaRepository, ModuleReferenceQuery { +public interface ModuleReferenceRepository extends JpaRepository, ModuleReferenceQuery { Collection identifyNewModuleReferences( final Collection moduleReferencesToCheck); diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java index 0e79deb8e..40a93da71 100644 --- a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java @@ -24,21 +24,32 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; +import lombok.AllArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.onap.cps.spi.CpsDataPersistenceService; +import org.onap.cps.spi.FetchDescendantsOption; +import org.onap.cps.spi.model.CmHandleQueryParameters; +import org.onap.cps.spi.model.DataNode; import org.onap.cps.spi.model.ModuleReference; import org.springframework.transaction.annotation.Transactional; @Slf4j @Transactional +@AllArgsConstructor public class ModuleReferenceRepositoryImpl implements ModuleReferenceQuery { @PersistenceContext private EntityManager entityManager; + private final CpsDataPersistenceService cpsDataPersistenceService; + @Override @SneakyThrows public Collection identifyNewModuleReferences( @@ -57,6 +68,56 @@ public class ModuleReferenceRepositoryImpl implements ModuleReferenceQuery { return identifyNewModuleReferencesForCmHandle(tempTableName); } + /** + * Query and return cm handles that match the given query parameters. + * + * @param cmHandleQueryParameters the cm handle query parameters + * @return collection of cm handle ids + */ + @Override + public Set queryCmHandles(final CmHandleQueryParameters cmHandleQueryParameters) { + + if (cmHandleQueryParameters.getPublicProperties().entrySet().isEmpty()) { + return getAllCmHandles(); + } + + final Collection amalgamatedQueryResult = new ArrayList<>(); + int queryConditionCounter = 0; + for (final Map.Entry entry : cmHandleQueryParameters.getPublicProperties().entrySet()) { + final StringBuilder cmHandlePath = new StringBuilder(); + cmHandlePath.append("//public-properties[@name='").append(entry.getKey()).append("' "); + cmHandlePath.append("and @value='").append(entry.getValue()).append("']"); + cmHandlePath.append("/ancestor::cm-handles"); + + final Collection singleConditionQueryResult = + cpsDataPersistenceService.queryDataNodes("NCMP-Admin", + "ncmp-dmi-registry", String.valueOf(cmHandlePath), FetchDescendantsOption.OMIT_DESCENDANTS); + if (++queryConditionCounter == 1) { + amalgamatedQueryResult.addAll(singleConditionQueryResult); + } else { + amalgamatedQueryResult.retainAll(singleConditionQueryResult); + } + + if (amalgamatedQueryResult.isEmpty()) { + break; + } + } + + return extractCmHandleIds(amalgamatedQueryResult); + } + + private Set getAllCmHandles() { + final Collection cmHandles = cpsDataPersistenceService.queryDataNodes("NCMP-Admin", + "ncmp-dmi-registry", "//public-properties/ancestor::cm-handles", + FetchDescendantsOption.OMIT_DESCENDANTS); + return extractCmHandleIds(cmHandles); + } + + private Set extractCmHandleIds(final Collection cmHandles) { + return cmHandles.stream().map(cmHandle -> cmHandle.getLeaves().get("id").toString()) + .collect(Collectors.toSet()); + } + private void createTemporaryTable(final String tempTableName) { final StringBuilder sqlStringBuilder = new StringBuilder("CREATE TEMPORARY TABLE " + tempTableName + "("); sqlStringBuilder.append(" id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,"); @@ -95,7 +156,7 @@ public class ModuleReferenceRepositoryImpl implements ModuleReferenceQuery { + " WHERE yang_resource.module_name IS NULL;", tempTableName); final List resultsAsObjects = - entityManager.createNativeQuery(sql).getResultList(); + (List) entityManager.createNativeQuery(sql).getResultList(); final List resultsAsModuleReferences = new ArrayList<>(resultsAsObjects.size()); for (final Object[] row : resultsAsObjects) { diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy index 063bd5b5a..f486cb76d 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021 Nordix Foundation + * Copyright (C) 2021-2022 Nordix Foundation * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ @@ -22,6 +22,7 @@ package org.onap.cps.spi.impl +import org.mockito.Mock import org.onap.cps.spi.CpsAdminPersistenceService import org.onap.cps.spi.exceptions.AlreadyDefinedException import org.onap.cps.spi.exceptions.AnchorNotFoundException @@ -30,15 +31,21 @@ import org.onap.cps.spi.exceptions.DataspaceNotFoundException import org.onap.cps.spi.exceptions.SchemaSetNotFoundException import org.onap.cps.spi.exceptions.ModuleNamesNotFoundException import org.onap.cps.spi.model.Anchor +import org.onap.cps.spi.model.CmHandleQueryParameters import org.springframework.beans.factory.annotation.Autowired import org.springframework.test.context.jdbc.Sql +import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase { @Autowired CpsAdminPersistenceService objectUnderTest + @Mock + ObjectMapper objectMapper + static final String SET_DATA = '/data/anchor.sql' + static final String SET_FRAGMENT_DATA = '/data/fragment.sql' static final String SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES = '/data/anchors-schemaset-modules.sql' static final String DATASPACE_WITH_NO_DATA = 'DATASPACE-002-NO-DATA' static final Integer DELETED_ANCHOR_ID = 3002 @@ -219,4 +226,20 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase { 'dataspace contains schemasets' | 'DATASPACE-003' || DataspaceInUseException | 'contains 1 schemaset(s)' } + @Sql([CLEAR_DATA, SET_FRAGMENT_DATA]) + def 'Retrieve cm handle ids when #scenario.'() { + when: 'the service is invoked' + def cmHandleQueryParameters = new CmHandleQueryParameters() + cmHandleQueryParameters.setPublicProperties(publicProperties) + def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters) + then: 'the correct expected cm handles are returned' + returnedCmHandles == expectedCmHandleIds + where: 'the following data is used' + scenario | publicProperties || expectedCmHandleIds + 'single matching property' | ['Contact' : 'newemailforstore@bookstore.com'] || ['PNFDemo2', 'PNFDemo', 'PNFDemo4'] as Set + 'public property dont match' | ['wont_match' : 'wont_match'] || [] as Set + '2 properties, only one match (and)' | ['Contact' : 'newemailforstore@bookstore.com', 'Contact2': 'newemailforstore2@bookstore.com'] || ['PNFDemo4'] as Set + '2 properties, no match (and)' | ['Contact' : 'newemailforstore@bookstore.com', 'Contact2': ''] || [] as Set + 'No public properties - return all cm handles' | [ : ] || ['PNFDemo3', 'PNFDemo', 'PNFDemo2', 'PNFDemo4'] as Set + } } diff --git a/cps-ri/src/test/resources/data/fragment.sql b/cps-ri/src/test/resources/data/fragment.sql index a27bb5fde..fb4a5f77c 100755 --- a/cps-ri/src/test/resources/data/fragment.sql +++ b/cps-ri/src/test/resources/data/fragment.sql @@ -1,6 +1,6 @@ /* ============LICENSE_START======================================================= - Copyright (C) 2021 Nordix Foundation. + Copyright (C) 2021-2022 Nordix Foundation. Modifications Copyright (C) 2021 Pantheon.tech Modifications Copyright (C) 2021-2022 Bell Canada. ================================================================================ @@ -21,14 +21,16 @@ */ INSERT INTO DATASPACE (ID, NAME) VALUES - (1001, 'DATASPACE-001'); + (1001, 'DATASPACE-001'), + (1002, 'NCMP-Admin'); INSERT INTO SCHEMA_SET (ID, NAME, DATASPACE_ID) VALUES (2001, 'SCHEMA-SET-001', 1001); INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES (3001, 'ANCHOR-001', 1001, 2001), - (3003, 'ANCHOR-003', 1001, 2001); + (3003, 'ANCHOR-003', 1001, 2001), + (3004, 'ncmp-dmi-registry', 1002, 2001); INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH) VALUES (4001, 1001, 3001, null, '/parent-1'), @@ -67,4 +69,15 @@ INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) (4230, 1001, 3003, 4227, '/parent-206/child-206/grand-child-206[@key="X"]', '{"key": "X"}'), (4231, 1001, 3003, null, '/parent-206[@key="A"]', '{"key": "A"}'), (4232, 1001, 3003, 4231, '/parent-206[@key="A"]/child-206', '{}'), - (4233, 1001, 3003, null, '/parent-206[@key="B"]', '{"key": "B"}'); \ No newline at end of file + (4233, 1001, 3003, null, '/parent-206[@key="B"]', '{"key": "B"}'); + +INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES + (5000, 1002, 3004, null, '/dmi-registry/cm-handles[@id="PNFDemo"]', '{"id": "PNFDemo", "dmi-service-name": "http://172.21.235.14:8783", "dmi-data-service-name": "", "dmi-model-service-name": ""}'), + (5001, 1002, 3004, null, '/dmi-registry/cm-handles[@id="PNFDemo2"]', '{"id": "PNFDemo2", "dmi-service-name": "http://172.26.46.68:8783", "dmi-data-service-name": "", "dmi-model-service-name": ""}'), + (5002, 1002, 3004, null, '/dmi-registry/cm-handles[@id="PNFDemo3"]', '{"id": "PNFDemo3", "dmi-service-name": "http://172.26.46.68:8783", "dmi-data-service-name": "", "dmi-model-service-name": ""}'), + (5003, 1002, 3004, null, '/dmi-registry/cm-handles[@id="PNFDemo4"]', '{"id": "PNFDemo4", "dmi-service-name": "http://172.26.46.68:8783", "dmi-data-service-name": "", "dmi-model-service-name": ""}'), + (5004, 1002, 3004, 5000, '/dmi-registry/cm-handles[@id="PNFDemo"]/public-properties[@name="Contact"]', '{"name": "Contact", "value": "newemailforstore@bookstore.com"}'), + (5005, 1002, 3004, 5001, '/dmi-registry/cm-handles[@id="PNFDemo2"]/public-properties[@name="Contact"]', '{"name": "Contact", "value": "newemailforstore@bookstore.com"}'), + (5006, 1002, 3004, 5002, '/dmi-registry/cm-handles[@id="PNFDemo3"]/public-properties[@name="Contact"]', '{"name": "Contact3", "value": "PNF3@bookstore.com"}'), + (5007, 1002, 3004, 5003, '/dmi-registry/cm-handles[@id="PNFDemo4"]/public-properties[@name="Contact"]', '{"name": "Contact", "value": "newemailforstore@bookstore.com"}'), + (5008, 1002, 3004, 5004, '/dmi-registry/cm-handles[@id="PNFDemo4"]/public-properties[@name="Contact2"]', '{"name": "Contact2", "value": "newemailforstore2@bookstore.com"}'); \ No newline at end of file -- cgit 1.2.3-korg