Merge "Fix SonarQube Violations"
authorJoseph Keenan <joseph.keenan@est.tech>
Tue, 18 Oct 2022 09:13:22 +0000 (09:13 +0000)
committerGerrit Code Review <gerrit@onap.org>
Tue, 18 Oct 2022 09:13:22 +0000 (09:13 +0000)
37 files changed:
checkstyle/pom.xml
cps-application/pom.xml
cps-application/src/main/resources/application.yml
cps-bom/pom.xml
cps-dependencies/pom.xml
cps-events/pom.xml
cps-ncmp-events/pom.xml
cps-ncmp-rest-stub/pom.xml
cps-ncmp-rest/pom.xml
cps-ncmp-service/pom.xml
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfig.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistenceImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/DataSyncWatchdog.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfigSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/DataSyncWatchdogSpec.groovy
cps-parent/pom.xml
cps-path-parser/pom.xml
cps-rest/pom.xml
cps-ri/pom.xml
cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
cps-ri/src/main/resources/changelog/db/changes/16-insert-cm-handle-state-forward.sql
cps-ri/src/main/resources/changelog/db/changes/16-insert-cm-handle-state-rollback.sql
cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsToDataNodePerfSpec.groovy [new file with mode: 0644]
cps-service/pom.xml
cps-service/src/main/java/org/onap/cps/spi/FetchDescendantsOption.java
cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy
cps-service/src/test/groovy/org/onap/cps/spi/FetchDescendantsOptionSpec.groovy [new file with mode: 0644]
docs/release-notes.rst
jacoco-report/pom.xml
pom.xml
spotbugs/pom.xml
version.properties

index 9a38968..dd308e2 100644 (file)
@@ -26,7 +26,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.onap.cps</groupId>
     <artifactId>checkstyle</artifactId>
-    <version>3.1.5-SNAPSHOT</version>
+    <version>3.2.0-SNAPSHOT</version>
 
     <profiles>
         <profile>
index 20bfb0d..a4d3cbd 100755 (executable)
@@ -27,7 +27,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.1.5-SNAPSHOT</version>
+        <version>3.2.0-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index 8b932f6..e3ffd04 100644 (file)
@@ -33,6 +33,7 @@ spring:
     application:\r
         name: "cps-application"\r
     jpa:\r
+        show-sql: false\r
         ddl-auto: create\r
         open-in-view: false\r
         properties:\r
index e80e6b4..004c31e 100644 (file)
@@ -25,7 +25,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.onap.cps</groupId>
     <artifactId>cps-bom</artifactId>
-    <version>3.1.5-SNAPSHOT</version>
+    <version>3.2.0-SNAPSHOT</version>
     <packaging>pom</packaging>
 
     <description>This artifact contains dependencyManagement declarations of all published CPS components.</description>
index a3d42dd..e04ff02 100755 (executable)
@@ -27,7 +27,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.onap.cps</groupId>
     <artifactId>cps-dependencies</artifactId>
-    <version>3.1.5-SNAPSHOT</version>
+    <version>3.2.0-SNAPSHOT</version>
     <packaging>pom</packaging>
 
     <name>${project.groupId}:${project.artifactId}</name>
index 39f8e49..6cbb7eb 100644 (file)
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.1.5-SNAPSHOT</version>
+        <version>3.2.0-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index 4658894..193f5d0 100644 (file)
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.1.5-SNAPSHOT</version>
+        <version>3.2.0-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index 2a4979a..a1711b5 100644 (file)
@@ -26,7 +26,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.1.5-SNAPSHOT</version>
+        <version>3.2.0-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index a4c44ba..8473674 100644 (file)
@@ -27,7 +27,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.1.5-SNAPSHOT</version>
+        <version>3.2.0-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index 6a9d948..0f5a234 100644 (file)
@@ -27,7 +27,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.1.5-SNAPSHOT</version>
+        <version>3.2.0-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index f8836e6..1674c52 100644 (file)
@@ -21,6 +21,7 @@
 package org.onap.cps.ncmp.api.impl;
 
 import static org.onap.cps.ncmp.api.impl.utils.YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle;
+import static org.onap.cps.spi.FetchDescendantsOption.FETCH_DIRECT_CHILDREN_ONLY;
 import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
 import static org.onap.cps.utils.CmHandleQueryRestParametersValidator.validateCpsPathConditionProperties;
 import static org.onap.cps.utils.CmHandleQueryRestParametersValidator.validateModuleNameConditionProperties;
@@ -68,14 +69,14 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm
      */
     @Override
     public Set<NcmpServiceCmHandle> queryCmHandles(
-        final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
+            final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
 
         if (cmHandleQueryServiceParameters.getCmHandleQueryParameters().isEmpty()) {
             return getAllCmHandles();
         }
 
         final Map<String, NcmpServiceCmHandle> combinedQueryResult = executeInventoryQueries(
-            cmHandleQueryServiceParameters);
+                cmHandleQueryServiceParameters);
 
         return new HashSet<>(combineWithModuleNameQuery(cmHandleQueryServiceParameters, combinedQueryResult).values());
     }
@@ -88,17 +89,17 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm
      */
     @Override
     public Set<String> queryCmHandleIds(
-        final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
+            final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
 
         if (cmHandleQueryServiceParameters.getCmHandleQueryParameters().isEmpty()) {
             return getAllCmHandleIds();
         }
 
         final Map<String, NcmpServiceCmHandle> combinedQueryResult = executeInventoryQueries(
-            cmHandleQueryServiceParameters);
+                cmHandleQueryServiceParameters);
 
         final Collection<String> moduleNamesForQuery =
-            getModuleNamesForQuery(cmHandleQueryServiceParameters.getCmHandleQueryParameters());
+                getModuleNamesForQuery(cmHandleQueryServiceParameters.getCmHandleQueryParameters());
         if (moduleNamesForQuery.isEmpty()) {
             return combinedQueryResult.keySet();
         }
@@ -113,10 +114,10 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm
     }
 
     private Map<String, NcmpServiceCmHandle> combineWithModuleNameQuery(
-        final CmHandleQueryServiceParameters cmHandleQueryServiceParameters,
-        final Map<String, NcmpServiceCmHandle> previousQueryResult) {
+            final CmHandleQueryServiceParameters cmHandleQueryServiceParameters,
+            final Map<String, NcmpServiceCmHandle> previousQueryResult) {
         final Collection<String> moduleNamesForQuery =
-            getModuleNamesForQuery(cmHandleQueryServiceParameters.getCmHandleQueryParameters());
+                getModuleNamesForQuery(cmHandleQueryServiceParameters.getCmHandleQueryParameters());
         if (moduleNamesForQuery.isEmpty()) {
             return previousQueryResult;
         }
@@ -138,7 +139,7 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm
     }
 
     private Map<String, NcmpServiceCmHandle> executeInventoryQueries(
-        final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
+            final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
         final Map<String, String> cpsPath = getCpsPath(cmHandleQueryServiceParameters.getCmHandleQueryParameters());
         if (!validateCpsPathConditionProperties(cpsPath)) {
             return Collections.emptyMap();
@@ -149,13 +150,13 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm
         } else {
             try {
                 cpsPathQueryResult = cmHandleQueries.queryCmHandleDataNodesByCpsPath(
-                    cpsPath.get("cpsPath"), INCLUDE_ALL_DESCENDANTS)
-                    .stream().map(this::createNcmpServiceCmHandle)
-                    .collect(Collectors.toMap(NcmpServiceCmHandle::getCmHandleId,
-                        Function.identity()));
+                                cpsPath.get("cpsPath"), INCLUDE_ALL_DESCENDANTS)
+                        .stream().map(this::createNcmpServiceCmHandle)
+                        .collect(Collectors.toMap(NcmpServiceCmHandle::getCmHandleId,
+                                Function.identity()));
             } catch (final PathParsingException pathParsingException) {
                 throw new DataValidationException(pathParsingException.getMessage(), pathParsingException.getDetails(),
-                    pathParsingException);
+                        pathParsingException);
             }
             if (cpsPathQueryResult.isEmpty()) {
                 return Collections.emptyMap();
@@ -163,9 +164,9 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm
         }
 
         final Map<String, String> publicPropertyQueryPairs =
-            getPublicPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters());
+                getPublicPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters());
         final Map<String, NcmpServiceCmHandle> propertiesQueryResult = publicPropertyQueryPairs.isEmpty()
-            ? NO_QUERY_TO_EXECUTE : cmHandleQueries.queryCmHandlePublicProperties(publicPropertyQueryPairs);
+                ? NO_QUERY_TO_EXECUTE : cmHandleQueries.queryCmHandlePublicProperties(publicPropertyQueryPairs);
 
         return cmHandleQueries.combineCmHandleQueries(cpsPathQueryResult, propertiesQueryResult);
     }
@@ -190,14 +191,14 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm
     private Map<String, String> getCpsPath(final List<ConditionProperties> conditionProperties) {
         final Map<String, String> result = new HashMap<>();
         getConditions(conditionProperties, ValidQueryProperties.WITH_CPS_PATH.getQueryProperty()).forEach(
-            result::putAll);
+                result::putAll);
         return result;
     }
 
     private Map<String, String> getPublicPropertyPairs(final List<ConditionProperties> conditionProperties) {
         final Map<String, String> result = new HashMap<>();
         getConditions(conditionProperties,
-            ValidQueryProperties.HAS_ALL_PROPERTIES.getQueryProperty()).forEach(result::putAll);
+                ValidQueryProperties.HAS_ALL_PROPERTIES.getQueryProperty()).forEach(result::putAll);
         return result;
     }
 
@@ -213,17 +214,17 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm
 
     private Set<NcmpServiceCmHandle> getAllCmHandles() {
         return inventoryPersistence.getDataNode("/dmi-registry")
-            .getChildDataNodes().stream().map(this::createNcmpServiceCmHandle).collect(Collectors.toSet());
+                .getChildDataNodes().stream().map(this::createNcmpServiceCmHandle).collect(Collectors.toSet());
     }
 
     private Set<String> getAllCmHandleIds() {
-        return inventoryPersistence.getDataNode("/dmi-registry")
-            .getChildDataNodes().stream().map(dataNode -> dataNode.getLeaves().get("id").toString())
-            .collect(Collectors.toSet());
+        return inventoryPersistence.getDataNode("/dmi-registry", FETCH_DIRECT_CHILDREN_ONLY)
+                .getChildDataNodes().stream().map(dataNode -> dataNode.getLeaves().get("id").toString())
+                .collect(Collectors.toSet());
     }
 
     private NcmpServiceCmHandle createNcmpServiceCmHandle(final DataNode dataNode) {
         return convertYangModelCmHandleToNcmpServiceCmHandle(YangDataConverter
-            .convertCmHandleToYangModel(dataNode, dataNode.getLeaves().get("id").toString()));
+                .convertCmHandleToYangModel(dataNode, dataNode.getLeaves().get("id").toString()));
     }
 }
index c89388b..5154be7 100644 (file)
@@ -28,7 +28,6 @@ import com.hazelcast.core.Hazelcast;
 import com.hazelcast.core.HazelcastInstance;
 import com.hazelcast.map.IMap;
 import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.TimeUnit;
 import org.onap.cps.spi.model.DataNode;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -39,11 +38,12 @@ import org.springframework.context.annotation.Configuration;
 @Configuration
 public class SynchronizationCacheConfig {
 
+    public static final int MODULE_SYNC_STARTED_TTL_SECS = 60;
+    public static final int DATA_SYNC_SEMAPHORE_TTL_SECS = 1800;
+
     private static final QueueConfig commonQueueConfig = createQueueConfig();
-    private static final MapConfig moduleSyncStartedConfig =
-        createMapConfig("moduleSyncStartedConfig", TimeUnit.MINUTES.toSeconds(1));
-    private static final MapConfig dataSyncSemaphoresConfig =
-        createMapConfig("dataSyncSemaphoresConfig", TimeUnit.MINUTES.toSeconds(30));
+    private static final MapConfig moduleSyncStartedConfig = createMapConfig("moduleSyncStartedConfig");
+    private static final MapConfig dataSyncSemaphoresConfig = createMapConfig("dataSyncSemaphoresConfig");
 
     /**
      * Module Sync Distributed Queue Instance.
@@ -102,11 +102,10 @@ public class SynchronizationCacheConfig {
         return commonQueueConfig;
     }
 
-    private static MapConfig createMapConfig(final String configName, final long timeToLiveSeconds) {
+    private static MapConfig createMapConfig(final String configName) {
         final MapConfig mapConfig = new MapConfig(configName);
         mapConfig.setBackupCount(3);
         mapConfig.setAsyncBackupCount(3);
-        mapConfig.setTimeToLiveSeconds((int) timeToLiveSeconds);
         return mapConfig;
     }
 
index bfc3a9a..b29825e 100644 (file)
@@ -23,6 +23,7 @@ package org.onap.cps.ncmp.api.inventory;
 import java.util.Collection;
 import java.util.Map;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.spi.FetchDescendantsOption;
 import org.onap.cps.spi.model.Anchor;
 import org.onap.cps.spi.model.DataNode;
 import org.onap.cps.spi.model.ModuleDefinition;
@@ -113,6 +114,15 @@ public interface InventoryPersistence {
      */
     DataNode getDataNode(String xpath);
 
+    /**
+     * Get data node via xpath.
+     *
+     * @param xpath xpath
+     * @param fetchDescendantsOption fetch descendants option
+     * @return data node
+     */
+    DataNode getDataNode(String xpath, FetchDescendantsOption fetchDescendantsOption);
+
     /**
      * Get data node of given cm handle.
      *
index 99edfdb..eed47ed 100644 (file)
@@ -76,18 +76,18 @@ public class InventoryPersistenceImpl implements InventoryPersistence {
     @Override
     public CompositeState getCmHandleState(final String cmHandleId) {
         final DataNode stateAsDataNode = cpsDataService.getDataNode(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
-            String.format(CM_HANDLE_XPATH_TEMPLATE, cmHandleId) + "/state",
-            FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
+                String.format(CM_HANDLE_XPATH_TEMPLATE, cmHandleId) + "/state",
+                FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
         return new CompositeStateBuilder().fromDataNode(stateAsDataNode).build();
     }
 
     @Override
     public void saveCmHandleState(final String cmHandleId, final CompositeState compositeState) {
         final String cmHandleJsonData = String.format("{\"state\":%s}",
-            jsonObjectMapper.asJsonString(compositeState));
+                jsonObjectMapper.asJsonString(compositeState));
         cpsDataService.updateDataNodeAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
-            String.format(CM_HANDLE_XPATH_TEMPLATE, cmHandleId),
-            cmHandleJsonData, OffsetDateTime.now());
+                String.format(CM_HANDLE_XPATH_TEMPLATE, cmHandleId),
+                cmHandleJsonData, OffsetDateTime.now());
     }
 
     @Override
@@ -153,8 +153,13 @@ public class InventoryPersistenceImpl implements InventoryPersistence {
 
     @Override
     public DataNode getDataNode(final String xpath) {
+        return getDataNode(xpath, INCLUDE_ALL_DESCENDANTS);
+    }
+
+    @Override
+    public DataNode getDataNode(final String xpath, final FetchDescendantsOption fetchDescendantsOption) {
         return cpsDataPersistenceService.getDataNode(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
-                xpath, INCLUDE_ALL_DESCENDANTS);
+                xpath, fetchDescendantsOption);
     }
 
     @Override
@@ -164,7 +169,7 @@ public class InventoryPersistenceImpl implements InventoryPersistence {
 
     @Override
     public Collection<Anchor> queryAnchors(final Collection<String> moduleNamesForQuery) {
-        return  cpsAdminPersistenceService.queryAnchors(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, moduleNamesForQuery);
+        return cpsAdminPersistenceService.queryAnchors(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, moduleNamesForQuery);
     }
 
     @Override
index 9336c3b..9fa75a0 100644 (file)
 
 package org.onap.cps.ncmp.api.inventory.sync;
 
+import com.hazelcast.map.IMap;
 import java.time.OffsetDateTime;
-import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.api.CpsDataService;
+import org.onap.cps.ncmp.api.impl.config.embeddedcache.SynchronizationCacheConfig;
 import org.onap.cps.ncmp.api.inventory.CompositeState;
 import org.onap.cps.ncmp.api.inventory.DataStoreSyncState;
 import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
@@ -46,7 +48,7 @@ public class DataSyncWatchdog {
 
     private final SyncUtils syncUtils;
 
-    private final Map<String, Boolean> dataSyncSemaphores;
+    private final IMap<String, Boolean> dataSyncSemaphores;
 
     /**
      * Execute Cm Handle poll which queries the cm handle state in 'READY' and Operational Datastore Sync State in
@@ -92,6 +94,7 @@ public class DataSyncWatchdog {
     }
 
     private boolean hasPushedIntoSemaphoreMap(final String cmHandleId) {
-        return dataSyncSemaphores.putIfAbsent(cmHandleId, DATA_SYNC_IN_PROGRESS) == null;
+        return dataSyncSemaphores.putIfAbsent(cmHandleId, DATA_SYNC_IN_PROGRESS,
+                SynchronizationCacheConfig.DATA_SYNC_SEMAPHORE_TTL_SECS, TimeUnit.SECONDS) == null;
     }
 }
index b96889f..f629b71 100644 (file)
@@ -31,6 +31,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.api.impl.config.embeddedcache.SynchronizationCacheConfig;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
 import org.onap.cps.ncmp.api.inventory.sync.executor.AsyncTaskExecutor;
 import org.onap.cps.spi.model.DataNode;
@@ -117,8 +118,9 @@ public class ModuleSyncWatchdog {
         log.debug("nextBatchCandidates size : {}", nextBatchCandidates.size());
         for (final DataNode batchCandidate : nextBatchCandidates) {
             final String cmHandleId = String.valueOf(batchCandidate.getLeaves().get("id"));
-            final boolean alreadyAddedToInProgressMap = VALUE_FOR_HAZELCAST_IN_PROGRESS_MAP
-                .equals(moduleSyncStartedOnCmHandles.putIfAbsent(cmHandleId, VALUE_FOR_HAZELCAST_IN_PROGRESS_MAP));
+            final boolean alreadyAddedToInProgressMap = VALUE_FOR_HAZELCAST_IN_PROGRESS_MAP.equals(
+                    moduleSyncStartedOnCmHandles.putIfAbsent(cmHandleId, VALUE_FOR_HAZELCAST_IN_PROGRESS_MAP,
+                            SynchronizationCacheConfig.MODULE_SYNC_STARTED_TTL_SECS, TimeUnit.SECONDS));
             if (alreadyAddedToInProgressMap) {
                 log.debug("module sync for {} already in progress by other instance", cmHandleId);
             } else {
index f76316f..eea53e8 100644 (file)
@@ -153,7 +153,9 @@ class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification {
     def 'Retrieve cm handles when the query is empty.'() {
         given: 'We use an empty query'
             def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
-        and: 'the inventory persistence returns the dmi registry datanode'
+        and: 'the inventory persistence returns the dmi registry datanode with just ids'
+            inventoryPersistence.getDataNode("/dmi-registry", FetchDescendantsOption.FETCH_DIRECT_CHILDREN_ONLY) >> dmiRegistry
+        and: 'the inventory persistence returns the dmi registry datanode with data'
             inventoryPersistence.getDataNode("/dmi-registry") >> dmiRegistry
         when: 'the query is executed for both cm handle ids and details'
             def returnedCmHandlesJustIds = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
index 4cfc02b..c16d6b6 100644 (file)
@@ -28,6 +28,7 @@ import org.springframework.boot.test.context.SpringBootTest
 import org.springframework.test.context.ContextConfiguration
 import spock.lang.Specification
 import java.util.concurrent.BlockingQueue
+import java.util.concurrent.TimeUnit
 
 @SpringBootTest
 @ContextConfiguration(classes = [SynchronizationCacheConfig])
@@ -40,7 +41,7 @@ class SynchronizationCacheConfigSpec extends Specification {
     private IMap<String, Object> moduleSyncStartedOnCmHandles
 
     @Autowired
-    private Map<String, Boolean> dataSyncSemaphores
+    private IMap<String, Boolean> dataSyncSemaphores
 
     def 'Embedded (hazelcast) Caches for Module and Data Sync.'() {
         expect: 'system is able to create an instance of the Module Sync Work Queue'
@@ -54,4 +55,36 @@ class SynchronizationCacheConfigSpec extends Specification {
         and: 'they have the correct names (in any order)'
             assert Hazelcast.allHazelcastInstances.name.containsAll('moduleSyncWorkQueue', 'moduleSyncStartedOnCmHandles', 'dataSyncSemaphores' )
     }
+
+    def 'Verify configs for Distributed objects'(){
+        given: 'the Module Sync Work Queue config'
+            def queueConfig =  Hazelcast.getHazelcastInstanceByName('moduleSyncWorkQueue').config.queueConfigs.get('defaultQueueConfig')
+        and: 'the Module Sync Started Cm Handle Map config'
+            def moduleSyncStartedOnCmHandlesConfig =  Hazelcast.getHazelcastInstanceByName('moduleSyncStartedOnCmHandles').config.mapConfigs.get('moduleSyncStartedConfig')
+        and: 'the Data Sync Semaphores Map config'
+            def dataSyncSemaphoresConfig =  Hazelcast.getHazelcastInstanceByName('dataSyncSemaphores').config.mapConfigs.get('dataSyncSemaphoresConfig')
+        expect: 'system created instance with correct config of Module Sync Work Queue'
+            assert queueConfig.backupCount == 3
+            assert queueConfig.asyncBackupCount == 3
+        and: 'Module Sync Started Cm Handle Map has the correct settings'
+            assert moduleSyncStartedOnCmHandlesConfig.backupCount == 3
+            assert moduleSyncStartedOnCmHandlesConfig.asyncBackupCount == 3
+        and: 'Data Sync Semaphore Map has the correct settings'
+            assert dataSyncSemaphoresConfig.backupCount == 3
+            assert dataSyncSemaphoresConfig.asyncBackupCount == 3
+    }
+
+    def 'Time to Live Verify for Module Sync and Data Sync Semaphore'() {
+        when: 'the keys are inserted with a TTL'
+            moduleSyncStartedOnCmHandles.put('testKeyModuleSync', 'toBeExpired' as Object, 1000, TimeUnit.MILLISECONDS)
+            dataSyncSemaphores.put('testKeyDataSync', Boolean.TRUE, 1000, TimeUnit.MILLISECONDS)
+        then: 'the entries are present in the map'
+            assert moduleSyncStartedOnCmHandles.get('testKeyModuleSync') != null
+            assert dataSyncSemaphores.get('testKeyDataSync') != null
+        and: 'we wait for the key expiration'
+            sleep(1500)
+        and: 'the keys should be expired as TTL elapsed'
+            assert moduleSyncStartedOnCmHandles.get('testKeyModuleSync') == null
+            assert dataSyncSemaphores.get('testKeyDataSync') == null
+    }
 }
index 6053819..707f3ea 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.onap.cps.ncmp.api.inventory.sync
 
+import com.hazelcast.map.IMap
 import org.onap.cps.api.CpsDataService
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
 import org.onap.cps.ncmp.api.inventory.CmHandleState
@@ -27,8 +28,6 @@ import org.onap.cps.ncmp.api.inventory.CompositeState
 import org.onap.cps.ncmp.api.inventory.InventoryPersistence
 import org.onap.cps.ncmp.api.inventory.DataStoreSyncState
 import spock.lang.Specification
-import java.util.concurrent.ConcurrentHashMap
-import java.util.concurrent.ConcurrentMap
 
 class DataSyncWatchdogSpec extends Specification {
 
@@ -38,11 +37,11 @@ class DataSyncWatchdogSpec extends Specification {
 
     def mockSyncUtils = Mock(SyncUtils)
 
-    def stubbedMap = Stub(ConcurrentMap)
+    def mockDataSyncSemaphoreMap = Mock(IMap<String,Boolean>)
 
     def jsonString = '{"stores:bookstore":{"categories":[{"code":"01"}]}}'
 
-    def objectUnderTest = new DataSyncWatchdog(mockInventoryPersistence, mockCpsDataService, mockSyncUtils, stubbedMap as ConcurrentHashMap)
+    def objectUnderTest = new DataSyncWatchdog(mockInventoryPersistence, mockCpsDataService, mockSyncUtils, mockDataSyncSemaphoreMap)
 
     def compositeState = getCompositeState()
 
index 8739e2c..a29d624 100755 (executable)
@@ -32,7 +32,7 @@
 
     <groupId>org.onap.cps</groupId>
     <artifactId>cps-parent</artifactId>
-    <version>3.1.5-SNAPSHOT</version>
+    <version>3.2.0-SNAPSHOT</version>
     <packaging>pom</packaging>
 
     <properties>
index ffac3b0..dce9ace 100644 (file)
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.1.5-SNAPSHOT</version>
+        <version>3.2.0-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index 37b3e46..f42aaaa 100755 (executable)
@@ -28,7 +28,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.1.5-SNAPSHOT</version>
+        <version>3.2.0-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index 5cdbf90..824a8d9 100644 (file)
@@ -26,7 +26,7 @@
     <parent>\r
         <groupId>org.onap.cps</groupId>\r
         <artifactId>cps-parent</artifactId>\r
-        <version>3.1.5-SNAPSHOT</version>\r
+        <version>3.2.0-SNAPSHOT</version>\r
         <relativePath>../cps-parent/pom.xml</relativePath>\r
     </parent>\r
 \r
index c13422d..ebc851a 100644 (file)
@@ -22,8 +22,6 @@
 
 package org.onap.cps.spi.impl;
 
-import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
-
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSet.Builder;
 import java.util.ArrayList;
@@ -102,7 +100,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
 
     @Override
     public void addMultipleLists(final String dataspaceName, final String anchorName, final String parentNodeXpath,
-            final Collection<Collection<DataNode>> newLists) {
+                                 final Collection<Collection<DataNode>> newLists) {
         final Collection<String> failedXpaths = new HashSet<>();
         newLists.forEach(newList -> {
             try {
@@ -119,7 +117,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     }
 
     private void addNewChildDataNode(final String dataspaceName, final String anchorName,
-            final String parentNodeXpath, final DataNode newChild) {
+                                     final String parentNodeXpath, final DataNode newChild) {
         final FragmentEntity parentFragmentEntity = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath);
         final FragmentEntity newChildAsFragmentEntity =
                 convertToFragmentWithAllDescendants(parentFragmentEntity.getDataspace(),
@@ -134,7 +132,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     }
 
     private void addChildrenDataNodes(final String dataspaceName, final String anchorName, final String parentNodeXpath,
-            final Collection<DataNode> newChildren) {
+                                      final Collection<DataNode> newChildren) {
         final FragmentEntity parentFragmentEntity = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath);
         final List<FragmentEntity> fragmentEntities = new ArrayList<>(newChildren.size());
         try {
@@ -154,7 +152,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     }
 
     private void retrySavingEachChildIndividually(final String dataspaceName, final String anchorName,
-            final String parentNodeXpath, final Collection<DataNode> newChildren) {
+                                                  final String parentNodeXpath,
+                                                  final Collection<DataNode> newChildren) {
         final Collection<String> failedXpaths = new HashSet<>();
         for (final DataNode newChild : newChildren) {
             try {
@@ -191,7 +190,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
      * @return a Fragment built from current DataNode
      */
     private FragmentEntity convertToFragmentWithAllDescendants(final DataspaceEntity dataspaceEntity,
-                             final AnchorEntity anchorEntity, final DataNode dataNodeToBeConverted) {
+                                                               final AnchorEntity anchorEntity,
+                                                               final DataNode dataNodeToBeConverted) {
         final FragmentEntity parentFragment = toFragmentEntity(dataspaceEntity, anchorEntity, dataNodeToBeConverted);
         final Builder<FragmentEntity> childFragmentsImmutableSetBuilder = ImmutableSet.builder();
         for (final DataNode childDataNode : dataNodeToBeConverted.getChildDataNodes()) {
@@ -226,7 +226,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
         final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
         final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
         if (isRootXpath(xpath)) {
-            return fragmentRepository.findFirstRootByDataspaceAndAnchor(dataspaceEntity, anchorEntity);
+            return fragmentRepository.findFirstRootByDataspaceAndAnchor(
+                    dataspaceEntity, anchorEntity);
         } else {
             final String normalizedXpath;
             try {
@@ -235,7 +236,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
                 throw new CpsPathException(e.getMessage());
             }
 
-            return fragmentRepository.getByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity, normalizedXpath);
+            return fragmentRepository.getByDataspaceAndAnchorAndXpath(
+                    dataspaceEntity, anchorEntity, normalizedXpath);
         }
     }
 
@@ -319,10 +321,10 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
 
     private List<DataNode> getChildDataNodes(final FragmentEntity fragmentEntity,
                                              final FetchDescendantsOption fetchDescendantsOption) {
-        if (fetchDescendantsOption == INCLUDE_ALL_DESCENDANTS) {
+        if (fetchDescendantsOption.hasNext()) {
             return fragmentEntity.getChildFragments().stream()
-                    .map(childFragmentEntity -> toDataNode(childFragmentEntity, fetchDescendantsOption))
-                    .collect(Collectors.toUnmodifiableList());
+                    .map(childFragmentEntity -> toDataNode(childFragmentEntity, fetchDescendantsOption.next()))
+                    .collect(Collectors.toList());
         }
         return Collections.emptyList();
     }
@@ -355,10 +357,11 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
                                               final List<DataNode> dataNodes) {
 
         final Map<DataNode, FragmentEntity> dataNodeFragmentEntityMap = dataNodes.stream()
-            .collect(Collectors.toMap(
-                dataNode -> dataNode, dataNode -> getFragmentByXpath(dataspaceName, anchorName, dataNode.getXpath())));
+                .collect(Collectors.toMap(
+                        dataNode -> dataNode,
+                        dataNode -> getFragmentByXpath(dataspaceName, anchorName, dataNode.getXpath())));
         dataNodeFragmentEntityMap.forEach(
-            (dataNode, fragmentEntity) -> updateFragmentEntityAndDescendantsWithDataNode(fragmentEntity, dataNode));
+                (dataNode, fragmentEntity) -> updateFragmentEntityAndDescendantsWithDataNode(fragmentEntity, dataNode));
         try {
             fragmentRepository.saveAll(dataNodeFragmentEntityMap.values());
         } catch (final StaleStateException staleStateException) {
@@ -367,7 +370,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     }
 
     private void retryUpdateDataNodesIndividually(final String dataspaceName, final String anchorName,
-            final Collection<FragmentEntity> fragmentEntities) {
+                                                  final Collection<FragmentEntity> fragmentEntities) {
         final Collection<String> failedXpaths = new HashSet<>();
 
         fragmentEntities.forEach(dataNodeFragment -> {
index 64b185f..01d441f 100644 (file)
@@ -1,3 +1,137 @@
-create view cmHandles as select * from fragment where xpath ~* '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]$';
-insert into fragment(xpath, attributes, anchor_id, parent_id, dataspace_id, schema_node_id) select concat(xpath, '/state'), to_jsonb(concat('{"cm-handle-state": "ADVISED", "last-update-time": "', to_char(now(), 'YYYY-MM-DD"T"HH24:MI:SS.MSTZHTZM'), '"}')::json), anchor_id, id, dataspace_id, schema_node_id from cmHandles;
-drop view cmHandles;
\ No newline at end of file
+INSERT INTO
+       fragment(
+               xpath,
+               attributes,
+               anchor_id,
+               parent_id,
+               dataspace_id,
+               schema_node_id
+       )
+SELECT
+       concat(cmHandles.xpath, '/state') AS xpath,
+       to_jsonb(
+               concat(
+                       '{"cm-handle-state": "READY", "last-update-time": "',
+                       to_char(
+                               now(),
+                               'YYYY-MM-DD"T"HH24:MI:SS.MSTZHTZM'
+                       ),
+                       '", "data-sync-enabled": false}'
+               ) :: json
+       ) AS attributes,
+       cmHandles.anchor_id,
+       cmHandles.id,
+       cmHandles.dataspace_id,
+       cmHandles.schema_node_id
+FROM
+       (
+               SELECT
+                       id,
+                       xpath,
+                       anchor_id,
+                       dataspace_id,
+                       schema_node_id
+               FROM
+                       fragment
+               WHERE
+                       xpath ~* '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]$'
+                       AND xpath NOT IN (
+                               SELECT
+                                       SUBSTRING(
+                                               xpath
+                                               FROM
+                                                       '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]'
+                                       )
+                               FROM
+                                       fragment
+                               WHERE
+                                       xpath ~* '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]/state$'
+                       )
+       ) AS cmHandles;
+INSERT INTO
+       fragment(
+               xpath,
+               attributes,
+               anchor_id,
+               parent_id,
+               dataspace_id,
+               schema_node_id
+       )
+SELECT
+       concat(cmHandlesStates.xpath, '/datastores'),
+       to_jsonb('{}' :: json),
+       cmHandlesStates.anchor_id,
+       cmHandlesStates.id,
+       cmHandlesStates.dataspace_id,
+       cmHandlesStates.schema_node_id
+FROM
+       (
+               SELECT
+                       id,
+                       xpath,
+                       anchor_id,
+                       dataspace_id,
+                       schema_node_id
+               FROM
+                       fragment
+               WHERE
+                       xpath ~* '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]/state$'
+                       AND xpath NOT IN (
+                               SELECT
+                                       SUBSTRING(
+                                               xpath
+                                               FROM
+                                                       '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]/state'
+                                       )
+                               FROM
+                                       fragment
+                               WHERE
+                                       xpath ~* '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]/state/datastores$'
+                       )
+       ) AS cmHandlesStates;
+INSERT INTO
+       fragment(
+               xpath,
+               attributes,
+               anchor_id,
+               parent_id,
+               dataspace_id,
+               schema_node_id
+       )
+SELECT
+       concat(
+               cmHandlesDatastores.xpath,
+               '/operational'
+       ),
+       to_jsonb(
+               concat('{"sync-state": "NONE_REQUESTED"}') :: json
+       ),
+       cmHandlesDatastores.anchor_id,
+       cmHandlesDatastores.id,
+       cmHandlesDatastores.dataspace_id,
+       cmHandlesDatastores.schema_node_id
+FROM
+       (
+               SELECT
+                       id,
+                       xpath,
+                       anchor_id,
+                       dataspace_id,
+                       schema_node_id
+               FROM
+                       fragment
+               WHERE
+                       xpath ~* '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]/state/datastores$'
+                       AND xpath NOT IN (
+                               SELECT
+                                       SUBSTRING(
+                                               xpath
+                                               FROM
+                                                       '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]/state/datastores'
+                                       )
+                               FROM
+                                       fragment
+                               WHERE
+                                       xpath ~* '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]/state/datastores/operational$'
+                       )
+       ) AS cmHandlesDatastores;
\ No newline at end of file
index aaf05a2..4b006ef 100644 (file)
@@ -1,4 +1,4 @@
-delete from fragment where xpath ~* '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]/state/lock-reason$';
-delete from fragment where xpath ~* '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]/state/datastores/operational$';
-delete from fragment where xpath ~* '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]/state/datastores$';
-delete from fragment where xpath ~* '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]/state$';
\ No newline at end of file
+DELETE FROM fragment WHERE xpath ~* '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]/state/lock-reason$';
+DELETE FROM fragment WHERE xpath ~* '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]/state/datastores/operational$';
+DELETE FROM fragment WHERE xpath ~* '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]/state/datastores$';
+DELETE FROM fragment WHERE xpath ~* '^/dmi-registry/cm-handles\[@id=''[\w\-]+''\]/state$';
\ No newline at end of file
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsToDataNodePerfSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsToDataNodePerfSpec.groovy
new file mode 100644 (file)
index 0000000..c36de9a
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.ri.performance
+
+import org.apache.commons.lang3.time.StopWatch
+import org.onap.cps.spi.CpsDataPersistenceService
+import org.onap.cps.spi.impl.CpsPersistenceSpecBase
+import org.onap.cps.spi.model.DataNode
+import org.onap.cps.spi.model.DataNodeBuilder
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.test.context.jdbc.Sql
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+
+class CpsToDataNodePerfSpec extends CpsPersistenceSpecBase {
+
+    @Autowired
+    CpsDataPersistenceService objectUnderTest
+
+    static final String SET_DATA = '/data/fragment.sql'
+    static final String  XPATH_DATA_NODE_WITH_DESCENDANTS = '/parent-1'
+
+    @Sql([CLEAR_DATA, SET_DATA])
+    def 'Get data node by xpath with all descendants with many children'() {
+        given: 'nodes and grandchildren have been persisted'
+            def setupStopWatch = new StopWatch()
+            setupStopWatch.start()
+            createLineage()
+            setupStopWatch.stop()
+            def setupDurationInMillis = setupStopWatch.getTime()
+        when: 'data node is requested with all descendants'
+            def readStopWatch = new StopWatch()
+            readStopWatch.start()
+            def result = objectUnderTest.getDataNode(
+                DATASPACE_NAME, ANCHOR_NAME1, XPATH_DATA_NODE_WITH_DESCENDANTS, INCLUDE_ALL_DESCENDANTS)
+            readStopWatch.stop()
+            def readDurationInMillis = readStopWatch.getTime()
+        then : 'setup duration is under 8 seconds'
+            assert setupDurationInMillis < 8000
+        and: 'read duration is under 3.5 seconds'
+            assert readDurationInMillis < 3500
+        and: 'data node is returned with all the descendants populated'
+            assert countDataNodes(result) == 1533
+    }
+
+    def createLineage() {
+        def numOfChildren = 30
+        def numOfGrandChildren = 50
+        (1..numOfChildren).each {
+            def childName = "perf-test-child-${it}".toString()
+            def newChild = goForthAndMultiply(XPATH_DATA_NODE_WITH_DESCENDANTS, childName, numOfGrandChildren)
+            objectUnderTest.addChildDataNode(DATASPACE_NAME, ANCHOR_NAME1, XPATH_DATA_NODE_WITH_DESCENDANTS, newChild)
+        }
+    }
+
+    def goForthAndMultiply(parentXpath, childName, numOfGrandChildren) {
+        def children = []
+        (1..numOfGrandChildren).each {
+            def child = new DataNodeBuilder().withXpath("${parentXpath}/${childName}/${it}-grand-child").build()
+            children.add(child)
+        }
+        return new DataNodeBuilder().withXpath("${parentXpath}/${childName}").withChildDataNodes(children).build()
+    }
+
+    def countDataNodes(DataNode dataNode) {
+        int nodeCount = 1
+        for (DataNode child : dataNode.childDataNodes) {
+            nodeCount = nodeCount + (countDataNodes(child))
+        }
+        return nodeCount
+    }
+}
\ No newline at end of file
index 51cf324..f47a963 100644 (file)
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.onap.cps</groupId>
     <artifactId>cps-parent</artifactId>
-    <version>3.1.5-SNAPSHOT</version>
+    <version>3.2.0-SNAPSHOT</version>
     <relativePath>../cps-parent/pom.xml</relativePath>
   </parent>
 
index 0c994d8..b80054a 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 Pantheon.tech
+ *  Copyright (C) 2022 Nordix Foundation
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
 
 package org.onap.cps.spi;
 
-public enum FetchDescendantsOption {
-    OMIT_DESCENDANTS,
-    INCLUDE_ALL_DESCENDANTS
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+public class FetchDescendantsOption {
+
+    public static final FetchDescendantsOption FETCH_DIRECT_CHILDREN_ONLY = new FetchDescendantsOption(1);
+    public static final FetchDescendantsOption OMIT_DESCENDANTS = new FetchDescendantsOption(0);
+    public static final FetchDescendantsOption INCLUDE_ALL_DESCENDANTS = new FetchDescendantsOption(-1);
+
+    private final int depth;
+
+    /**
+     * Has next depth.
+     *
+     * @return true if next level of depth is available
+     * @throws IllegalArgumentException when depth less than -1
+     */
+    public boolean hasNext() {
+        validateDepth(depth);
+        return depth > 0 || this.depth == INCLUDE_ALL_DESCENDANTS.depth;
+    }
+
+    /**
+     * Next fetch descendants option.
+     *
+     * @return the next fetch descendants option
+     * @throws IllegalArgumentException when depth less than -1 or 0
+     */
+    public FetchDescendantsOption next() {
+        if (depth == 0) {
+            throw new IllegalArgumentException("Do not use next() method with zero depth");
+        }
+        final FetchDescendantsOption nextDescendantsOption = this.depth == INCLUDE_ALL_DESCENDANTS.depth
+                ? INCLUDE_ALL_DESCENDANTS : new FetchDescendantsOption(depth - 1);
+        validateDepth(nextDescendantsOption.depth);
+        return nextDescendantsOption;
+    }
+
+    private static void validateDepth(final int depth) {
+        if (depth < -1) {
+            throw new IllegalArgumentException("A depth of less than minus one is not allowed");
+        }
+    }
+
 }
index 3f28f0a..a53706a 100644 (file)
@@ -188,7 +188,7 @@ class CpsDataServiceImplSpec extends Specification {
         expect: 'service returns same data if uses same parameters'
             objectUnderTest.getDataNode(dataspaceName, anchorName, xpath, fetchDescendantsOption) == dataNode
         where: 'all fetch options are supported'
-            fetchDescendantsOption << FetchDescendantsOption.values()
+            fetchDescendantsOption << [FetchDescendantsOption.OMIT_DESCENDANTS, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS]
     }
 
     def 'Get data node with option invalid #scenario.'() {
index 55a252c..b7fec85 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2021 Nordix Foundation
+ *  Copyright (C) 2021-2022 Nordix Foundation
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@ class CpsQueryServiceImplSpec extends Specification {
         then: 'the persistence service is called once with the correct parameters'
             1 * mockCpsDataPersistenceService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption)
         where: 'all fetch descendants options are supported'
-            fetchDescendantsOption << FetchDescendantsOption.values()
+            fetchDescendantsOption << [FetchDescendantsOption.OMIT_DESCENDANTS, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS]
     }
 
     def 'Query data nodes by cps path with invalid #scenario.'() {
diff --git a/cps-service/src/test/groovy/org/onap/cps/spi/FetchDescendantsOptionSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/spi/FetchDescendantsOptionSpec.groovy
new file mode 100644 (file)
index 0000000..6273835
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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
+
+
+import spock.lang.Specification
+
+class FetchDescendantsOptionSpec extends Specification {
+    def 'Check has next descendant for fetch descendant option: #scenario'() {
+        when: 'fetch descendant option with #depth depth'
+            def fetchDescendantsOption = new FetchDescendantsOption(depth)
+        then: 'next level descendants available: #expectedHasNext'
+            fetchDescendantsOption.hasNext() == expectedHasNext
+        where: 'following parameters are used'
+            scenario                  | depth || expectedHasNext
+            'omit descendants'        | 0     || false
+            'first child'             | 1     || true
+            'second child'            | 2     || true
+            'include all descendants' | -1    || true
+    }
+
+    def 'Check has next descendant for fetch descendant option: invalid depth'() {
+        given: 'fetch descendant option with -2 depth'
+            def fetchDescendantsOption = new FetchDescendantsOption(-2)
+        when: 'next level descendants not available'
+            fetchDescendantsOption.hasNext()
+        then: 'exception thrown'
+            thrown IllegalArgumentException
+    }
+
+    def 'Get next descendant for fetch descendant option: #scenario'() {
+        when: 'fetch descendant option with #depth depth'
+            def fetchDescendantsOption = new FetchDescendantsOption(depth)
+        then: 'the next level of depth is as expected'
+            fetchDescendantsOption.next().depth == depth - 1
+        where: 'following parameters are used'
+            scenario                  | depth
+            'first child'             | 1
+            'second child'            | 2
+    }
+
+    def 'Get next descendant for fetch descendant option: include all descendants'() {
+        when: 'fetch descendant option with -1 depth'
+            def fetchDescendantsOption = new FetchDescendantsOption(-1)
+        then: 'the next level of depth is as expected'
+            fetchDescendantsOption.next().depth == -1
+    }
+
+    def 'Get next descendant for fetch descendant option: omit descendants'() {
+        given: 'fetch descendant option with 0 depth'
+            def fetchDescendantsOption = new FetchDescendantsOption(0)
+        when: 'the next level of depth is not allowed'
+            fetchDescendantsOption.next()
+        then: 'exception thrown'
+            thrown IllegalArgumentException
+    }
+}
index 8c90a1f..aec3f3b 100755 (executable)
@@ -12,11 +12,11 @@ CPS Release Notes
     :depth: 2
 ..
 
-..      ====================
-..      * * *   KOHN   * * *
-..      ====================
+..      ======================
+..      * * *   LONDON   * * *
+..      ======================
 
-Version: 3.1.5 (not yet released)
+Version: 3.2.0 (not yet released)
 =================================
 
 Release Data
@@ -26,20 +26,34 @@ Release Data
 | **CPS Project**                      |                                                        |
 |                                      |                                                        |
 +--------------------------------------+--------------------------------------------------------+
-| **Docker images**                    | onap/cps-and-ncmp:3.1.5                                |
+| **Docker images**                    | onap/cps-and-ncmp:3.2.0                                |
 |                                      |                                                        |
 +--------------------------------------+--------------------------------------------------------+
-| **Release designation**              | 3.1.5 Kohn                                             |
+| **Release designation**              | 3.2.0 London                                           |
 |                                      |                                                        |
 +--------------------------------------+--------------------------------------------------------+
 | **Release date**                     | (not yet released)                                     |
 |                                      |                                                        |
 +--------------------------------------+--------------------------------------------------------+
+Features
+--------
+   - `CPS-1185 <https://jira.onap.org/browse/CPS-1185>`_  Get all dataspaces
+   - `CPS-1186 <https://jira.onap.org/browse/CPS-1186>`_  Get all schema sets for a dataspace
+   - `CPS-1187 <https://jira.onap.org/browse/CPS-1187>`_  Get single dataspace
+   - `CPS-1189 <https://jira.onap.org/browse/CPS-1189>`_  Various create endpoints should return 201 response with empty body
 
 Bug Fixes
 ---------
    - `CPS-1312 <https://jira.onap.org/browse/CPS-1312>`_  CPS(/NCMP) does not have version control
 
+Known Limitations, Issues and Workarounds
+-----------------------------------------
+
+*System Limitations*
+
+For upgrading, CPS uses Liquibase for database upgrades. CPS currently only supports upgrading from Liquibase changelog 11 to Liquibase changelog 16.
+This is from commit CPS-506: List all known modules and revision to CPS-1312: Default CMHandles to READY during upgrade or from ONAP release Honolulu to London.
+
 Version: 3.1.4
 ==============
 
index a783998..3e7af63 100644 (file)
@@ -5,7 +5,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.1.5-SNAPSHOT</version>
+        <version>3.2.0-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/pom.xml b/pom.xml
index 7ae1542..2f7c157 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -32,7 +32,7 @@
 \r
     <groupId>org.onap.cps</groupId>\r
     <artifactId>cps-aggregator</artifactId>\r
-    <version>3.1.5-SNAPSHOT</version>\r
+    <version>3.2.0-SNAPSHOT</version>\r
     <packaging>pom</packaging>\r
 \r
     <name>cps</name>\r
index c04f89f..306bdff 100644 (file)
@@ -25,7 +25,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.onap.cps</groupId>
     <artifactId>spotbugs</artifactId>
-    <version>3.1.5-SNAPSHOT</version>
+    <version>3.2.0-SNAPSHOT</version>
 
     <properties>
         <nexusproxy>https://nexus.onap.org</nexusproxy>
index 00839db..0a0cb6c 100755 (executable)
@@ -21,8 +21,8 @@
 # because they are used in Jenkins, whose plug-in doesn't support this
 
 major=3
-minor=1
-patch=5
+minor=2
+patch=0
 
 base_version=${major}.${minor}.${patch}