Merge "CPS-508: Create anchor/schemaset from new modules and existing modules"
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
index 535cbe2..1c7828f 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
@@ -30,6 +30,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
@@ -145,6 +146,22 @@
 
     @Override
     @Transactional
+    public void storeSchemaSetFromModules(final String dataspaceName, final String schemaSetName,
+                                          final Map<String, String> newYangResourcesModuleNameToContentMap,
+                                          final List<ModuleReference> moduleReferenceList) {
+        storeSchemaSet(dataspaceName, schemaSetName, newYangResourcesModuleNameToContentMap);
+        final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
+        final var schemaSetEntity =
+                schemaSetRepository.getByDataspaceAndName(dataspaceEntity, schemaSetName);
+        final List<Long> listOfYangResourceIds = new ArrayList<>();
+        moduleReferenceList.forEach(moduleReference ->
+                listOfYangResourceIds.add(yangResourceRepository.getIdByModuleNameAndRevision(
+                        moduleReference.getName(), moduleReference.getRevision())));
+        yangResourceRepository.insertSchemaSetIdYangResourceId(schemaSetEntity.getId(), listOfYangResourceIds);
+    }
+
+    @Override
+    @Transactional
     public void deleteSchemaSet(final String dataspaceName, final String schemaSetName,
         final CascadeDeleteAllowed cascadeDeleteAllowed) {
         final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetYangResourceRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetYangResourceRepository.java
new file mode 100644
index 0000000..0361749
--- /dev/null
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetYangResourceRepository.java
@@ -0,0 +1,29 @@
+/*-
+ * ============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.repository;
+
+import java.util.List;
+
+public interface SchemaSetYangResourceRepository {
+
+    void insertSchemaSetIdYangResourceId(final Integer schemaSetId, final List<Long> yangResourceId);
+
+}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetYangResourceRepositoryImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetYangResourceRepositoryImpl.java
new file mode 100644
index 0000000..04eaa45
--- /dev/null
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetYangResourceRepositoryImpl.java
@@ -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=========================================================
+ */
+
+package org.onap.cps.spi.repository;
+
+import java.util.List;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional
+public class SchemaSetYangResourceRepositoryImpl implements SchemaSetYangResourceRepository {
+
+    @PersistenceContext
+    private EntityManager entityManager;
+
+    @Override
+    public void insertSchemaSetIdYangResourceId(final Integer schemaSetId, final List<Long> yangResourceId) {
+        final var query = "INSERT INTO SCHEMA_SET_YANG_RESOURCES (SCHEMA_SET_ID, YANG_RESOURCE_ID) "
+                + "VALUES ( :schemaSetId, :yangResourceId)";
+        yangResourceId.forEach(id ->
+                entityManager.createNativeQuery(query)
+                        .setParameter("schemaSetId", schemaSetId)
+                        .setParameter("yangResourceId", id)
+                        .executeUpdate()
+        );
+    }
+}
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 fe8787f..0b48eaa 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
@@ -28,16 +28,21 @@
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
 import org.springframework.stereotype.Repository;
 
 @Repository
-public interface YangResourceRepository extends JpaRepository<YangResourceEntity, Long> {
+public interface YangResourceRepository extends JpaRepository<YangResourceEntity, Long>,
+        SchemaSetYangResourceRepository {
 
     List<YangResourceEntity> findAllByChecksumIn(@NotNull Set<String> checksum);
 
     @Query(value = "SELECT module_name, revision FROM yang_resource", nativeQuery = true)
     List<YangResourceModuleReference> findAllModuleNameAndRevision();
 
+    @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);
+
     @Modifying
     @Query(value = "DELETE FROM yang_resource yr WHERE NOT EXISTS "
         + "(SELECT 1 FROM schema_set_yang_resources ssyr WHERE ssyr.yang_resource_id = yr.id)", nativeQuery = true)
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 e41c71b..cff8d56 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
@@ -35,6 +35,7 @@
     @Autowired
     CpsAdminPersistenceService objectUnderTest
 
+
     static final String SET_DATA = '/data/anchor.sql'
     static final String EMPTY_DATASPACE_NAME = 'DATASPACE-002'
     static final Integer DELETED_ANCHOR_ID = 3001
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceIntegrationSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceIntegrationSpec.groovy
index f5d5fc6..7a16a97 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceIntegrationSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceIntegrationSpec.groovy
@@ -56,7 +56,6 @@
     static final String SCHEMA_SET_NAME_WITH_ANCHORS_AND_DATA = 'SCHEMA-SET-101'
     static final String SCHEMA_SET_NAME_NEW = 'SCHEMA-SET-NEW'
 
-    static final Long NEW_RESOURCE_ABSTRACT_ID = 0L
     static final String NEW_RESOURCE_NAME = 'some new resource'
     static final String NEW_RESOURCE_CONTENT = 'module stores {\n' +
             '    yang-version 1.1;\n' +
@@ -102,11 +101,28 @@
         when: 'a new schemaset is stored'
             objectUnderTest.storeSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_NEW, newYangResourcesNameToContentMap)
         then: 'the schema set is persisted correctly'
-            assertSchemaSetPersisted(DATASPACE_NAME, SCHEMA_SET_NAME_NEW, NEW_RESOURCE_ABSTRACT_ID, NEW_RESOURCE_NAME,
+            assertSchemaSetPersisted(DATASPACE_NAME, SCHEMA_SET_NAME_NEW, NEW_RESOURCE_NAME,
                     NEW_RESOURCE_CONTENT, NEW_RESOURCE_CHECKSUM, NEW_RESOURCE_MODULE_NAME, NEW_RESOURCE_REVISION)
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
+    def 'Store and retrieve new schema set from new modules and existing modules.'() {
+        given: 'map of new modules, a list of existing modules, module reference'
+            def mapOfNewModules = [newModule1: 'module newmodule { yang-version 1.1; revision "2021-10-12" { } }']
+            def moduleReferenceForExistingModule = new ModuleReference("test","test.org","2021-10-12")
+            def listOfExistingModulesModuleReference = [moduleReferenceForExistingModule]
+            def mapOfExistingModule = [test: 'module test { yang-version 1.1; revision "2021-10-12" { } }']
+            objectUnderTest.storeSchemaSet(DATASPACE_NAME, "someSchemaSetName", mapOfExistingModule)
+        when: 'a new schema set is created from these new modules and existing modules'
+            objectUnderTest.storeSchemaSetFromModules(DATASPACE_NAME, "newSchemaSetName" , mapOfNewModules, listOfExistingModulesModuleReference)
+        then: 'the schema set can be retrieved'
+            def expectedYangResourcesMapAfterSchemaSetHasBeenCreated = mapOfNewModules + mapOfExistingModule
+            def actualYangResourcesMapAfterSchemaSetHasBeenCreated =
+                    objectUnderTest.getYangSchemaResources(DATASPACE_NAME, "newSchemaSetName")
+        actualYangResourcesMapAfterSchemaSetHasBeenCreated == expectedYangResourcesMapAfterSchemaSetHasBeenCreated
+    }
+
+    @Sql([CLEAR_DATA, SET_DATA])
     def 'Retrieving schema set (resources) by anchor.'() {
         given: 'a new schema set is stored'
             objectUnderTest.storeSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_NEW, newYangResourcesNameToContentMap)
@@ -135,14 +151,13 @@
             def newYangResourcesNameToContentMap = [(NEW_RESOURCE_NAME):existingResourceContent]
         when: 'the schema set with duplicate resource is stored'
             objectUnderTest.storeSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_NEW, newYangResourcesNameToContentMap)
-        then: 'the schema persisted (re)uses the existing id, name and has the same checksum'
-            def existingResourceId = 9L
+        then: 'the schema persisted (re)uses the existing name and has the same checksum'
             def existingResourceName = 'module1@2020-02-02.yang'
             def existingResourceChecksum = 'bea1afcc3d1517e7bf8cae151b3b6bfbd46db77a81754acdcb776a50368efa0a'
             def existingResourceModelName = 'test'
             def existingResourceRevision = '2020-09-15'
-            assertSchemaSetPersisted(DATASPACE_NAME, SCHEMA_SET_NAME_NEW,
-                    existingResourceId, existingResourceName, existingResourceContent, existingResourceChecksum,
+            assertSchemaSetPersisted(DATASPACE_NAME, SCHEMA_SET_NAME_NEW, existingResourceName,
+                    existingResourceContent, existingResourceChecksum,
                     existingResourceModelName, existingResourceRevision)
     }
 
@@ -195,7 +210,6 @@
 
     def assertSchemaSetPersisted(expectedDataspaceName,
                                  expectedSchemaSetName,
-                                 expectedYangResourceId,
                                  expectedYangResourceName,
                                  expectedYangResourceContent,
                                  expectedYangResourceChecksum,
@@ -214,10 +228,6 @@
         // assert the attached yang resource content
         YangResourceEntity yangResourceEntity = yangResourceEntities.iterator().next()
         assert yangResourceEntity.id != null
-        if (expectedYangResourceId != NEW_RESOURCE_ABSTRACT_ID) {
-            // existing resource with known id
-            assert yangResourceEntity.id == expectedYangResourceId
-        }
         yangResourceEntity.name == expectedYangResourceName
         yangResourceEntity.content == expectedYangResourceContent
         yangResourceEntity.checksum == expectedYangResourceChecksum
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java b/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java
index fee4daa..d174085 100644
--- a/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java
@@ -46,6 +46,18 @@
                          @NonNull Map<String, String> yangResourcesNameToContentMap);
 
     /**
+     * Create a schema set from new modules and existing modules.
+     *
+     * @param dataspaceName                          Dataspace name
+     * @param schemaSetName                          schema set name
+     * @param newYangResourcesModuleNameToContentMap YANG resources map where key is a module name and value is content
+     * @param moduleReferenceList                    List of YANG resources module references
+     */
+    void createSchemaSetFromModules(@NonNull String dataspaceName, @NonNull String schemaSetName,
+                                    @NonNull Map<String, String> newYangResourcesModuleNameToContentMap,
+                                    @NonNull List<ModuleReference> moduleReferenceList);
+
+    /**
      * Read schema set in the given dataspace.
      *
      * @param dataspaceName dataspace name
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
index 34735f8..c65f827 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
@@ -51,6 +51,15 @@
     }
 
     @Override
+    public void createSchemaSetFromModules(final String dataspaceName, final String schemaSetName,
+                                           final Map<String, String> newYangResourcesModuleNameToContentMap,
+                                           final List<ModuleReference> moduleReferenceList) {
+        cpsModulePersistenceService.storeSchemaSetFromModules(dataspaceName, schemaSetName,
+                newYangResourcesModuleNameToContentMap, moduleReferenceList);
+
+    }
+
+    @Override
     public SchemaSet getSchemaSet(final String dataspaceName, final String schemaSetName) {
         final var yangTextSchemaSourceSet = yangTextSchemaSourceSetCache
             .get(dataspaceName, 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 f71ff0b..b05385f 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
@@ -49,7 +49,6 @@
      */
     void createAnchor(@NonNull String dataspaceName, @NonNull String schemaSetName, @NonNull String anchorName);
 
-
     /**
      * Read all anchors in the given a dataspace.
      *
diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java
index bc62a23..7ad109d 100755
--- a/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java
@@ -43,6 +43,18 @@
         @NonNull Map<String, String> yangResourcesNameToContentMap);
 
     /**
+     * Stores a schema set from new modules and existing modules.
+     *
+     * @param dataspaceName                          Dataspace name
+     * @param schemaSetName                          Schema set name
+     * @param newYangResourcesModuleNameToContentMap YANG resources map where key is a module name and value is content
+     * @param moduleReferenceList                    List of YANG resources module references
+     */
+    void storeSchemaSetFromModules(@NonNull String dataspaceName, @NonNull String schemaSetName,
+                                   @NonNull Map<String, String> newYangResourcesModuleNameToContentMap,
+                                   @NonNull List<ModuleReference> moduleReferenceList);
+
+    /**
      * Deletes Schema Set.
      *
      * @param dataspaceName        dataspace name
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
index b8bfd45..d719b3d 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
@@ -52,7 +52,7 @@
     @Autowired
     CpsModuleServiceImpl objectUnderTest
 
-    def 'Create schema set'() {
+    def 'Create schema set.'() {
         given: 'Valid yang resource as name-to-content map'
             def yangResourcesNameToContentMap = TestUtils.getYangResourcesAsMap('bookstore.yang')
         when: 'Create schema set method is invoked'
@@ -61,6 +61,17 @@
             1 * mockModuleStoreService.storeSchemaSet('someDataspace', 'someSchemaSet', yangResourcesNameToContentMap)
     }
 
+    def 'Create schema set from new modules and existing modules.'() {
+        given: 'a list of existing modules module reference'
+            def moduleReferenceForExistingModule = new ModuleReference("test", "test.org", "2021-10-12")
+            def listOfExistingModulesModuleReference = [moduleReferenceForExistingModule]
+        when: 'create schema set from modules method is invoked'
+            objectUnderTest.createSchemaSetFromModules("someDataspaceName", "someSchemaSetName", [newModule: "newContent"], listOfExistingModulesModuleReference)
+        then: 'processing is delegated to persistence service'
+            1 * mockModuleStoreService.storeSchemaSetFromModules("someDataspaceName", "someSchemaSetName", [newModule: "newContent"], listOfExistingModulesModuleReference)
+
+    }
+
     def 'Create schema set from invalid resources'() {
         given: 'Invalid yang resource as name-to-content map'
             def yangResourcesNameToContentMap = TestUtils.getYangResourcesAsMap('invalid.yang')