From a1c6e6ac56f9e53f08b329ce7f5069514c62fc77 Mon Sep 17 00:00:00 2001 From: niamhcore Date: Thu, 21 Oct 2021 15:19:04 +0100 Subject: Add get cm handles by modules names - persistence layer - Add sql query to anchor repository - Add sql query to yang resource repository Issue-ID: CPS-644 Signed-off-by: niamhcore Change-Id: I85ab1fcb343e6be77628695153d8d9f303dc3112 --- .../spi/impl/CpsAdminPersistenceServiceImpl.java | 33 ++++++++++++++++ .../onap/cps/spi/repository/AnchorRepository.java | 16 ++++++++ .../cps/spi/repository/YangResourceRepository.java | 33 +++++++++++----- .../spi/impl/CpsAdminPersistenceServiceSpec.groovy | 35 +++++++++++++++++ .../resources/data/anchors-schemaset-modules.sql | 45 ++++++++++++++++++++++ .../onap/cps/spi/CpsAdminPersistenceService.java | 9 +++++ .../exceptions/ModuleNamesNotFoundException.java | 41 ++++++++++++++++++++ 7 files changed, 203 insertions(+), 9 deletions(-) create mode 100644 cps-ri/src/test/resources/data/anchors-schemaset-modules.sql create mode 100644 cps-service/src/main/java/org/onap/cps/spi/exceptions/ModuleNamesNotFoundException.java 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 2776c4d67d..2b63169d44 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 @@ -23,6 +23,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; @@ -30,11 +31,13 @@ import org.onap.cps.spi.CpsAdminPersistenceService; import org.onap.cps.spi.entities.AnchorEntity; import org.onap.cps.spi.entities.DataspaceEntity; import org.onap.cps.spi.exceptions.AlreadyDefinedException; +import org.onap.cps.spi.exceptions.ModuleNamesNotFoundException; import org.onap.cps.spi.model.Anchor; import org.onap.cps.spi.repository.AnchorRepository; import org.onap.cps.spi.repository.DataspaceRepository; import org.onap.cps.spi.repository.FragmentRepository; import org.onap.cps.spi.repository.SchemaSetRepository; +import org.onap.cps.spi.repository.YangResourceRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Component; @@ -54,6 +57,9 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic @Autowired private FragmentRepository fragmentRepository; + @Autowired + private YangResourceRepository yangResourceRepository; + @Override public void createDataspace(final String dataspaceName) { try { @@ -87,6 +93,14 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic return anchorEntities.stream().map(CpsAdminPersistenceServiceImpl::toAnchor).collect(Collectors.toList()); } + @Override + public Collection getAnchors(final String dataspaceName, final Collection inputModuleNames) { + validateDataspaceAndModuleNames(dataspaceName, inputModuleNames); + final Collection anchorEntities = + anchorRepository.getAnchorsByDataspaceNameAndModuleNames(dataspaceName, inputModuleNames); + return anchorEntities.stream().map(CpsAdminPersistenceServiceImpl::toAnchor).collect(Collectors.toSet()); + } + @Override public Anchor getAnchor(final String dataspaceName, final String anchorName) { return toAnchor(getAnchorEntity(dataspaceName, anchorName)); @@ -112,4 +126,23 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic .schemaSetName(anchorEntity.getSchemaSet().getName()) .build(); } + + private void validateDataspaceAndModuleNames(final String dataspaceName, + final Collection inputModuleNames) { + final Collection retrievedModuleNames = + yangResourceRepository.findAllModuleReferences(dataspaceName, inputModuleNames) + .stream().map(module -> module.getModuleName()) + .collect(Collectors.toList()); + if (retrievedModuleNames.isEmpty()) { + dataspaceRepository.getByName(dataspaceName); + } + if (inputModuleNames.size() > retrievedModuleNames.size()) { + final List moduleNamesNotFound = inputModuleNames.stream() + .filter(moduleName -> !retrievedModuleNames.contains(moduleName)) + .collect(Collectors.toList()); + if (!moduleNamesNotFound.isEmpty()) { + throw new ModuleNamesNotFoundException(dataspaceName, moduleNamesNotFound); + } + } + } } diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java index 0305555456..6d4cb3c716 100755 --- a/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2021 Pantheon.tech + * Modifications Copyright (C) 2021 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +28,8 @@ import org.onap.cps.spi.entities.DataspaceEntity; import org.onap.cps.spi.entities.SchemaSetEntity; import org.onap.cps.spi.exceptions.AnchorNotFoundException; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface AnchorRepository extends JpaRepository { @@ -41,4 +44,17 @@ public interface AnchorRepository extends JpaRepository { Collection findAllByDataspace(@NotNull DataspaceEntity dataspaceEntity); Collection findAllBySchemaSet(@NotNull SchemaSetEntity schemaSetEntity); + + @Query(value = "SELECT DISTINCT\n" + + "anchor.*\n" + + "FROM\n" + + "yang_resource\n" + + "JOIN schema_set_yang_resources ON " + + "schema_set_yang_resources.yang_resource_id = yang_resource.id\n" + + "JOIN schema_set ON schema_set.id = schema_set_yang_resources.schema_set_id\n" + + "JOIN anchor ON anchor.schema_set_id = schema_set.id\n" + + "JOIN dataspace ON dataspace.id = anchor.dataspace_id AND dataspace.name = :dataspaceName\n" + + "WHERE yang_resource.module_Name IN (:moduleNames)", nativeQuery = true) + Collection getAnchorsByDataspaceNameAndModuleNames(@Param("dataspaceName") String dataspaceName, + @Param("moduleNames") Collection moduleNames); } \ No newline at end of file diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java index 764e2dfc74..3f5c43decc 100644 --- a/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java @@ -20,6 +20,7 @@ package org.onap.cps.spi.repository; +import java.util.Collection; import java.util.List; import java.util.Set; import javax.validation.constraints.NotNull; @@ -41,11 +42,11 @@ public interface YangResourceRepository extends JpaRepository findAllModuleReferences(@Param("dataspaceName") String dataspaceName); @@ -54,18 +55,32 @@ public interface YangResourceRepository extends JpaRepository findAllModuleReferences( @Param("dataspaceName") String dataspaceName, @Param("anchorName") String anchorName); + @Query(value = "SELECT DISTINCT\n" + + "yang_resource.*\n" + + "FROM\n" + + "dataspace\n" + + "JOIN schema_set ON schema_set.dataspace_id = dataspace.id\n" + + "JOIN schema_set_yang_resources ON schema_set_yang_resources.schema_set_id = " + + "schema_set.id\n" + + "JOIN yang_resource ON yang_resource.id = schema_set_yang_resources.yang_resource_id\n" + + "WHERE\n" + + "dataspace.name = :dataspaceName and yang_resource.module_Name IN (:moduleNames)", nativeQuery = true) + Set findAllModuleReferences(@Param("dataspaceName") String dataspaceName, + @Param("moduleNames") Collection moduleNames); + + @Query(value = "SELECT id FROM yang_resource WHERE module_name=:name and revision=:revision", nativeQuery = true) Long getIdByModuleNameAndRevision(@Param("name") String moduleName, @Param("revision") String revision); 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 cff8d56321..c37651089f 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 @@ -26,6 +26,7 @@ import org.onap.cps.spi.exceptions.AlreadyDefinedException import org.onap.cps.spi.exceptions.AnchorNotFoundException 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.springframework.beans.factory.annotation.Autowired import org.springframework.test.context.jdbc.Sql @@ -37,6 +38,7 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase { static final String SET_DATA = '/data/anchor.sql' + static final String SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES = '/data/anchors-schemaset-modules.sql' static final String EMPTY_DATASPACE_NAME = 'DATASPACE-002' static final Integer DELETED_ANCHOR_ID = 3001 static final Long DELETED_FRAGMENT_ID = 4001 @@ -140,4 +142,37 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase { 'dataspace does not exist' | 'unknown' | 'not-relevant' || DataspaceNotFoundException 'anchor does not exists' | DATASPACE_NAME | 'unknown' || AnchorNotFoundException } + + @Sql([CLEAR_DATA, SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES]) + def 'Get anchors that have #scenario.'() { + when: 'all anchor are retrieved for the given dataspace name and module names' + def anchors = objectUnderTest.getAnchors('DATASPACE-001', inputModuleNames) + then: 'the expected anchors are returned' + anchors.size() == expectedAnchors.size() + anchors.containsAll(expectedAnchors) + where: 'the following data is used' + scenario | inputModuleNames || expectedAnchors + 'one module' | ['MODULE-NAME-001'] || [buildAnchor('ANCHOR1', 'DATASPACE-001', 'SCHEMA-SET-001')] + 'two modules' | ['MODULE-NAME-001', 'MODULE-NAME-002'] || [buildAnchor('ANCHOR1', 'DATASPACE-001', 'SCHEMA-SET-001'), buildAnchor('ANCHOR2', 'DATASPACE-001', 'SCHEMA-SET-002'), buildAnchor('ANCHOR3', 'DATASPACE-001', 'SCHEMA-SET-004')] + 'a module attached to multiple anchors' | ['MODULE-NAME-003'] || [buildAnchor('ANCHOR1', 'DATASPACE-001', 'SCHEMA-SET-001'), buildAnchor('ANCHOR2', 'DATASPACE-001', 'SCHEMA-SET-002')] + 'same module with different revisions' | ['MODULE-NAME-002'] || [buildAnchor('ANCHOR2', 'DATASPACE-001', 'SCHEMA-SET-002'), buildAnchor('ANCHOR3', 'DATASPACE-001', 'SCHEMA-SET-004')] + } + + @Sql([CLEAR_DATA, SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES]) + def 'Get all anchors for an #scenario.'() { + when: 'attempt to get anchors' + objectUnderTest.getAnchors(dataspaceName, moduleNames) + then: 'the correct exception is thrown with the relevant details' + def thrownException = thrown(expectedException) + thrownException.details.contains(expectedMessageDetails) + where: 'the following data is used' + scenario | dataspaceName | moduleNames || expectedException | expectedMessageDetails + 'existing module in an unknown dataspace' | 'db-does-not-exist' | ['does-not-matter'] || DataspaceNotFoundException | 'db-does-not-exist' + 'unknown module in an existing dataspace' | 'DATASPACE-001' | ['module-does-not-exist'] || ModuleNamesNotFoundException | 'module-does-not-exist' + 'unknown module and known module in an existing dataspace' | 'DATASPACE-001' | ['MODULE-NAME-001', 'module-does-not-exist'] || ModuleNamesNotFoundException | 'module-does-not-exist' + } + + def buildAnchor(def anchorName, def dataspaceName, def SchemaSetName) { + return Anchor.builder().name(anchorName).dataspaceName(dataspaceName).schemaSetName(SchemaSetName).build() + } } diff --git a/cps-ri/src/test/resources/data/anchors-schemaset-modules.sql b/cps-ri/src/test/resources/data/anchors-schemaset-modules.sql new file mode 100644 index 0000000000..d2b67f5aea --- /dev/null +++ b/cps-ri/src/test/resources/data/anchors-schemaset-modules.sql @@ -0,0 +1,45 @@ +/* + ============LICENSE_START======================================================= + Copyright (C) 2021 Nordix Foundation. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache-2.0 + ============LICENSE_END========================================================= +*/ + +INSERT INTO DATASPACE (ID, NAME) VALUES + (1001, 'DATASPACE-001'), (1002, 'DATASPACE-002'); + +INSERT INTO SCHEMA_SET (ID, NAME, DATASPACE_ID) VALUES + (2001, 'SCHEMA-SET-001', 1001), + (2002, 'SCHEMA-SET-002', 1002), + (2003, 'SCHEMA-SET-003', 1001), + (2004, 'SCHEMA-SET-004', 1001); + +INSERT INTO YANG_RESOURCE (ID, NAME, CONTENT, CHECKSUM, MODULE_NAME, REVISION) VALUES + (3001, 'module1@2020-02-02.yang', 'CONTENT-001', 'checksum1','MODULE-NAME-001',null), + (3002, 'module2@2020-02-02.yang', 'CONTENT-002', 'checksum2','MODULE-NAME-002','REVISION-002'), + (3003, 'module3@2020-02-02.yang', 'CONTENT-003', 'checksum3','MODULE-NAME-003','REVISION-003'), + (3004, 'module4@2020-02-02.yang', 'CONTENT-004', 'checksum4','MODULE-NAME-004','REVISION-004'), + (3005, 'module5@2020-03-02.yang', 'CONTENT-005', 'checksum5','MODULE-NAME-002','REVISION-003'); + +INSERT INTO SCHEMA_SET_YANG_RESOURCES (SCHEMA_SET_ID, YANG_RESOURCE_ID) VALUES + (2001, 3001), (2002, 3002), + (2001, 3003), (2002, 3003), + (2003, 3004), (2004, 3005); + +INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES + (6001, 'ANCHOR1', 1001, 2001), + (6002, 'ANCHOR2', 1001, 2002), + (6003, 'ANCHOR3', 1001, 2004); diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java index b05385fbf4..f29735fa01 100755 --- a/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java +++ b/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java @@ -58,6 +58,15 @@ public interface CpsAdminPersistenceService { @NonNull Collection getAnchors(@NonNull String dataspaceName); + /** + * Get anchors for the given dataspace name and collection of module names. + * + * @param dataspaceName dataspace name + * @param moduleNames a collection of module names + * @return a collection of anchors + */ + Collection getAnchors(String dataspaceName, Collection moduleNames); + /** * Get an anchor in the given dataspace using the anchor name. * diff --git a/cps-service/src/main/java/org/onap/cps/spi/exceptions/ModuleNamesNotFoundException.java b/cps-service/src/main/java/org/onap/cps/spi/exceptions/ModuleNamesNotFoundException.java new file mode 100644 index 0000000000..ee4295ea75 --- /dev/null +++ b/cps-service/src/main/java/org/onap/cps/spi/exceptions/ModuleNamesNotFoundException.java @@ -0,0 +1,41 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.spi.exceptions; + +import java.util.Collection; + +@SuppressWarnings("squid:S110") // Team agreed to accept 6 levels of inheritance for CPS Exceptions +public class ModuleNamesNotFoundException extends CpsAdminException { + + private static final long serialVersionUID = 3105694256583924137L; + + /** + * Constructor. + * + * @param dataspaceName dataspace name + * @param moduleNames module names + */ + public ModuleNamesNotFoundException(final String dataspaceName, final Collection moduleNames) { + super("Yang resource not found", + String.format("No yang resources found for %s in dataspace %s.", + moduleNames, dataspaceName)); + } +} -- cgit 1.2.3-korg