Merge "CPS-Core : Expose a java interface to update schema set"
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 6f9f5a4..847a4a3 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
@@ -171,6 +171,18 @@
         anchorRepository.deleteAllByDataspaceAndNameIn(dataspaceEntity, anchorNames);
     }
 
+    @Transactional
+    @Override
+    public void updateAnchorSchemaSet(final String dataspaceName,
+                                         final String anchorName,
+                                         final String schemaSetName) {
+        final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
+        final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
+        final SchemaSetEntity schemaSetEntity = schemaSetRepository
+                .getByDataspaceAndName(dataspaceEntity, schemaSetName);
+        anchorRepository.updateAnchorSchemaSetId(schemaSetEntity.getId(), anchorEntity.getId());
+    }
+
     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/AnchorRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
index 5bb5857..b8503a7 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
@@ -99,4 +99,8 @@
         deleteAllByDataspaceIdAndNameIn(dataspaceEntity.getId(), anchorNames.toArray(new String[0]));
     }
 
+    @Modifying
+    @Query(value = "UPDATE anchor SET schema_set_id =:schemaSetId WHERE id = :anchorId ", nativeQuery = true)
+    void updateAnchorSchemaSetId(@Param("schemaSetId") int schemaSetId, @Param("anchorId") long anchorId);
+
 }
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java b/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java
index fcf3f54..edd052a 100755
--- a/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java
@@ -135,4 +135,13 @@
      *         given module names
      */
     Collection<String> queryAnchorNames(String dataspaceName, Collection<String> moduleNames);
+
+    /**
+     * Update schema set of an anchor.
+     *
+     * @param dataspaceName dataspace name
+     * @param anchorName    anchor name
+     * @param schemaSetName schema set name
+     */
+    void updateAnchorSchemaSet(String dataspaceName, String anchorName, String schemaSetName);
 }
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java
index e286eea..d83ee43 100755
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java
@@ -120,4 +120,11 @@
         final Collection<Anchor> anchors = cpsAdminPersistenceService.queryAnchors(dataspaceName, moduleNames);
         return anchors.stream().map(Anchor::getName).collect(Collectors.toList());
     }
+
+    @Override
+    public void updateAnchorSchemaSet(final String dataspaceName,
+                                         final String anchorName,
+                                         final String schemaSetName) {
+        cpsAdminPersistenceService.updateAnchorSchemaSet(dataspaceName, anchorName, schemaSetName);
+    }
 }
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 1c1e80a..5a1810f 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
@@ -133,4 +133,13 @@
      * @param anchorNames   anchor names
      */
     void deleteAnchors(String dataspaceName, Collection<String> anchorNames);
+
+    /**
+     * Delete anchors by name in given dataspace.
+     *
+     * @param dataspaceName dataspace name
+     * @param anchorName    anchor name
+     * @param schemaSetName schema set name
+     */
+    void updateAnchorSchemaSet(String dataspaceName, String anchorName, String schemaSetName);
 }
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy
index eb41e20..12564fb 100755
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy
@@ -178,4 +178,11 @@
         and: 'the CpsValidator is called on the dataspaceName'
             1 * mockCpsValidator.validateNameCharacters('someDataspace')
     }
+
+    def 'Update anchor schema set.'() {
+        when: 'update anchor is invoked'
+            objectUnderTest.updateAnchorSchemaSet('someDataspace', 'someAnchor', 'someSchemaSetName')
+        then: 'associated persistence service method is invoked with correct parameter'
+            1 * mockCpsAdminPersistenceService.updateAnchorSchemaSet('someDataspace', 'someAnchor', 'someSchemaSetName')
+    }
 }
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
index 4780e36..03ef9c2 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
@@ -108,7 +108,7 @@
     def dataspaceExists(dataspaceName) {
         try {
             cpsAdminService.getDataspace(dataspaceName)
-        } catch (DataspaceNotFoundException e) {
+        } catch (DataspaceNotFoundException dataspaceNotFoundException) {
             return false
         }
         return true
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAdminServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAdminServiceIntegrationSpec.groovy
index 92fbdaa..bdd894c 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAdminServiceIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAdminServiceIntegrationSpec.groovy
@@ -22,10 +22,12 @@
 
 import org.onap.cps.api.CpsAdminService
 import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.onap.cps.spi.FetchDescendantsOption
 import org.onap.cps.spi.exceptions.AlreadyDefinedException
 import org.onap.cps.spi.exceptions.AnchorNotFoundException
 import org.onap.cps.spi.exceptions.DataspaceInUseException
 import org.onap.cps.spi.exceptions.DataspaceNotFoundException
+import java.time.OffsetDateTime
 
 class CpsAdminServiceIntegrationSpec extends CpsIntegrationSpecBase {
 
@@ -44,8 +46,8 @@
             def thrown = null
             try {
                 objectUnderTest.getDataspace('newDataspace')
-            } catch(Exception e) {
-                thrown = e
+            } catch(Exception exception) {
+                thrown = exception
             }
            assert thrown instanceof DataspaceNotFoundException
     }
@@ -100,8 +102,8 @@
             def thrown = null
             try {
                 objectUnderTest.getAnchor(GENERAL_TEST_DATASPACE, 'newAnchor')
-            } catch(Exception e) {
-                thrown = e
+            } catch(Exception exception) {
+                thrown = exception
             }
             assert thrown instanceof AnchorNotFoundException
     }
@@ -151,4 +153,28 @@
            'just unknown module(s)' | GENERAL_TEST_DATASPACE
     }
 
+    def 'Update anchor schema set.'() {
+        when: 'a new schema set with tree yang model is created'
+            def newTreeYangModelAsString = readResourceDataFile('tree/new-test-tree.yang')
+            cpsModuleService.createSchemaSet(GENERAL_TEST_DATASPACE, 'newTreeSchemaSet', [tree: newTreeYangModelAsString])
+        then: 'an anchor with new schema set is created'
+            objectUnderTest.createAnchor(GENERAL_TEST_DATASPACE, 'newTreeSchemaSet', 'anchor4')
+        and: 'the new tree datanode is saved'
+            def treeJsonData = readResourceDataFile('tree/new-test-tree.json')
+            cpsDataService.saveData(GENERAL_TEST_DATASPACE, 'anchor4', treeJsonData, OffsetDateTime.now())
+        and: 'saved tree data node can be retrieved by its normalized xpath'
+            def branchName = cpsDataService.getDataNodes(GENERAL_TEST_DATASPACE, 'anchor4', "/test-tree/branch", FetchDescendantsOption.DIRECT_CHILDREN_ONLY)[0].leaves['name']
+            assert branchName == 'left'
+        and: 'a another schema set with updated tree yang model is created'
+            def updatedTreeYangModelAsString = readResourceDataFile('tree/updated-test-tree.yang')
+            cpsModuleService.createSchemaSet(GENERAL_TEST_DATASPACE, 'anotherTreeSchemaSet', [tree: updatedTreeYangModelAsString])
+        and: 'anchor4 schema set is updated with another schema set successfully'
+            objectUnderTest.updateAnchorSchemaSet(GENERAL_TEST_DATASPACE, 'anchor4', 'anotherTreeSchemaSet')
+        when: 'updated tree data node with new leaves'
+            def updatedTreeJsonData = readResourceDataFile('tree/updated-test-tree.json')
+            cpsDataService.updateNodeLeaves(GENERAL_TEST_DATASPACE, "anchor4", "/test-tree/branch[@name='left']", updatedTreeJsonData, OffsetDateTime.now())
+        then: 'updated tree data node can be retrieved by its normalized xpath'
+            def birdsName = cpsDataService.getDataNodes(GENERAL_TEST_DATASPACE, 'anchor4',"/test-tree/branch[@name='left']/nest", FetchDescendantsOption.DIRECT_CHILDREN_ONLY)[0].leaves['birds']
+            assert birdsName as String == '[Raven, Night Owl, Crow]'
+    }
 }
diff --git a/integration-test/src/test/resources/data/tree/new-test-tree.json b/integration-test/src/test/resources/data/tree/new-test-tree.json
new file mode 100644
index 0000000..f7aefc4
--- /dev/null
+++ b/integration-test/src/test/resources/data/tree/new-test-tree.json
@@ -0,0 +1,12 @@
+{
+  "test-tree": {
+    "branch": [
+      {
+        "name": "left",
+        "nest": {
+          "name": "small"
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/integration-test/src/test/resources/data/tree/new-test-tree.yang b/integration-test/src/test/resources/data/tree/new-test-tree.yang
new file mode 100644
index 0000000..1a08b92
--- /dev/null
+++ b/integration-test/src/test/resources/data/tree/new-test-tree.yang
@@ -0,0 +1,21 @@
+module test-tree {
+    yang-version 1.1;
+
+    namespace "org:onap:cps:test:test-tree";
+    prefix tree;
+    revision "2020-02-02";
+
+    container test-tree {
+        list branch {
+            key "name";
+            leaf name {
+                type string;
+            }
+            container nest {
+                leaf name {
+                    type string;
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/integration-test/src/test/resources/data/tree/updated-test-tree.json b/integration-test/src/test/resources/data/tree/updated-test-tree.json
new file mode 100644
index 0000000..2c2eea4
--- /dev/null
+++ b/integration-test/src/test/resources/data/tree/updated-test-tree.json
@@ -0,0 +1,10 @@
+{
+  "nest": {
+    "name": "small",
+    "birds": [
+      "Night Owl",
+      "Raven",
+      "Crow"
+    ]
+  }
+}
\ No newline at end of file
diff --git a/integration-test/src/test/resources/data/tree/updated-test-tree.yang b/integration-test/src/test/resources/data/tree/updated-test-tree.yang
new file mode 100644
index 0000000..bd883e8
--- /dev/null
+++ b/integration-test/src/test/resources/data/tree/updated-test-tree.yang
@@ -0,0 +1,33 @@
+module test-tree {
+    yang-version 1.1;
+
+    namespace "org:onap:cps:test:test-tree";
+    prefix tree;
+
+    revision "2023-08-17" {
+        description
+            "added list of birds to nest";
+    }
+
+    revision "2020-09-15" {
+        description
+            "Sample Model";
+    }
+
+    container test-tree {
+        list branch {
+            key "name";
+            leaf name {
+                type string;
+            }
+            container nest {
+                leaf name {
+                    type string;
+                }
+                leaf-list birds {
+                    type string;
+                }
+            }
+        }
+    }
+}
\ No newline at end of file