Add get cm handles by modules names - persistence layer 13/125213/11
authorniamhcore <niamh.core@est.tech>
Thu, 21 Oct 2021 14:19:04 +0000 (15:19 +0100)
committerniamhcore <niamh.core@est.tech>
Fri, 29 Oct 2021 08:20:39 +0000 (09:20 +0100)
- Add sql query to anchor repository
- Add sql query to yang resource repository

Issue-ID: CPS-644
Signed-off-by: niamhcore <niamh.core@est.tech>
Change-Id: I85ab1fcb343e6be77628695153d8d9f303dc3112

cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java
cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy
cps-ri/src/test/resources/data/anchors-schemaset-modules.sql [new file with mode: 0644]
cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java
cps-service/src/main/java/org/onap/cps/spi/exceptions/ModuleNamesNotFoundException.java [new file with mode: 0644]

index 2776c4d..2b63169 100755 (executable)
@@ -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<Anchor> getAnchors(final String dataspaceName, final Collection<String> inputModuleNames) {
+        validateDataspaceAndModuleNames(dataspaceName, inputModuleNames);
+        final Collection<AnchorEntity> 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<String> inputModuleNames) {
+        final Collection<String> 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<String> moduleNamesNotFound = inputModuleNames.stream()
+                .filter(moduleName -> !retrievedModuleNames.contains(moduleName))
+                .collect(Collectors.toList());
+            if (!moduleNamesNotFound.isEmpty()) {
+                throw new ModuleNamesNotFoundException(dataspaceName, moduleNamesNotFound);
+            }
+        }
+    }
 }
index 0305555..6d4cb3c 100755 (executable)
@@ -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<AnchorEntity, Integer> {
 
@@ -41,4 +44,17 @@ public interface AnchorRepository extends JpaRepository<AnchorEntity, Integer> {
     Collection<AnchorEntity> findAllByDataspace(@NotNull DataspaceEntity dataspaceEntity);
 
     Collection<AnchorEntity> 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<AnchorEntity> getAnchorsByDataspaceNameAndModuleNames(@Param("dataspaceName") String dataspaceName,
+        @Param("moduleNames") Collection<String> moduleNames);
 }
\ No newline at end of file
index 764e2df..3f5c43d 100644 (file)
@@ -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<YangResourceEntity
         + "yang_resource.module_name AS module_name,\n"
         + "yang_resource.revision AS revision\n"
         + "FROM\n"
-        + "dataspace dataspace\n"
-        + "JOIN schema_set schema_set ON schema_set.dataspace_id = dataspace.id\n"
-        + "JOIN schema_set_yang_resources schema_set_yang_resource ON schema_set_yang_resource.schema_set_id = "
+        + "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 yang_resource ON yang_resource.id = schema_set_yang_resource.yang_resource_id\n"
+        + "JOIN yang_resource ON yang_resource.id = schema_set_yang_resources.yang_resource_id\n"
         + "WHERE\n"
         + "dataspace.name = :dataspaceName", nativeQuery = true)
     Set<YangResourceModuleReference> findAllModuleReferences(@Param("dataspaceName") String dataspaceName);
@@ -54,18 +55,32 @@ public interface YangResourceRepository extends JpaRepository<YangResourceEntity
         + "yang_resource.module_Name AS module_name,\n"
         + "yang_resource.revision AS revision\n"
         + "FROM\n"
-        + "dataspace dataspace\n"
-        + "JOIN anchor anchor ON anchor.dataspace_id = dataspace.id\n"
-        + "JOIN schema_set schema_set ON schema_set.id = anchor.schema_set_id\n"
-        + "JOIN schema_set_yang_resources schema_set_yang_resource ON schema_set_yang_resource.schema_set_id = "
+        + "dataspace\n"
+        + "JOIN anchor ON anchor.dataspace_id = dataspace.id\n"
+        + "JOIN schema_set ON schema_set.id = anchor.schema_set_id\n"
+        + "JOIN schema_set_yang_resources ON schema_set_yang_resources.schema_set_id = "
         + "schema_set.id\n"
-        + "JOIN yang_resource yang_resource ON yang_resource.id = schema_set_yang_resource.yang_resource_id\n"
+        + "JOIN yang_resource ON yang_resource.id = schema_set_yang_resources.yang_resource_id\n"
         + "WHERE\n"
         + "dataspace.name = :dataspaceName AND\n"
         + "anchor.name =:anchorName", nativeQuery = true)
     Set<YangResourceModuleReference> 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<YangResourceModuleReference> findAllModuleReferences(@Param("dataspaceName") String dataspaceName,
+        @Param("moduleNames") Collection<String> 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);
 
index cff8d56..c376510 100644 (file)
@@ -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 (file)
index 0000000..d2b67f5
--- /dev/null
@@ -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);
index b05385f..f29735f 100755 (executable)
@@ -58,6 +58,15 @@ public interface CpsAdminPersistenceService {
     @NonNull
     Collection<Anchor> 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<Anchor> getAnchors(String dataspaceName, Collection<String> 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 (file)
index 0000000..ee4295e
--- /dev/null
@@ -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<String> moduleNames) {
+        super("Yang resource not found",
+            String.format("No yang resources found for %s in dataspace %s.",
+                    moduleNames, dataspaceName));
+    }
+}