Merge "Merge 2 'query' end points in NCMP"
authorToine Siebelink <toine.siebelink@est.tech>
Wed, 8 Jun 2022 10:03:11 +0000 (10:03 +0000)
committerGerrit Code Review <gerrit@onap.org>
Wed, 8 Jun 2022 10:03:11 +0000 (10:03 +0000)
37 files changed:
cps-ncmp-rest/docs/openapi/components.yaml
cps-ncmp-rest/docs/openapi/ncmp.yml
cps-ncmp-rest/docs/openapi/openapi.yml
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DeprecationHelper.java [new file with mode: 0644]
cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy
cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/DeprecationHelperSpec.groovy [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyCmHandlerQueryService.java [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java [new file with mode: 0644]
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/models/CmHandleQueryApiParameters.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/ConditionApiProperties.java [new file with mode: 0644]
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy [new file with mode: 0644]
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java
cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java
cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy
cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java
cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java
cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java
cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java
cps-service/src/main/java/org/onap/cps/spi/model/CmHandleQueryParameters.java
cps-service/src/main/java/org/onap/cps/spi/model/ConditionProperties.java [new file with mode: 0644]
cps-service/src/main/java/org/onap/cps/spi/model/DataNodeIdentifier.java [new file with mode: 0644]
cps-service/src/main/java/org/onap/cps/utils/CmHandleQueryRestParametersValidator.java [new file with mode: 0644]
cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy
cps-service/src/test/groovy/org/onap/cps/utils/CmHandleQueryRestParametersValidatorSpec.groovy [new file with mode: 0644]
csit/plans/cps/testplan.txt
csit/tests/cm-handle-query/cm-handle-query.robot [moved from csit/tests/public-properties-query/public-properties-query.robot with 61% similarity]

index 5fe47e4..248b1da 100644 (file)
@@ -133,52 +133,7 @@ components:
             type: string
             example: my-property
 
-    Conditions:
-      type: object
-      properties:
-        conditions:
-          $ref: '#/components/schemas/ConditionsData'
-    ConditionsData:
-      type: array
-      items:
-        type: object
-        $ref: '#/components/schemas/ConditionProperties'
-    ConditionProperties:
-      properties:
-        name:
-          type: string
-          example: hasAllModules
-        conditionParameters:
-          $ref: '#/components/schemas/ModuleNamesAsJsonArray'
-    ModuleNamesAsJsonArray:
-      type: array
-      items:
-        type: object
-        $ref: '#/components/schemas/ModuleNameAsJsonObject'
-        example: [my-module-1, my-module-2, my-module-3]
-    ModuleNameAsJsonObject:
-        properties:
-          moduleName:
-            type: string
-            example: my-module
-
     #Response Schemas
-    CmHandles:
-      type: object
-      properties:
-        cmHandles:
-          $ref: '#/components/schemas/CmHandleProperties'
-    CmHandleProperties:
-      type: array
-      items:
-        type: object
-        $ref: '#/components/schemas/CmHandleProperty'
-    CmHandleProperty:
-      properties:
-        cmHandleId:
-          type: string
-          example: my-cm-handle-id
-
     RestModuleReference:
       type: object
       title: Module reference details
@@ -190,15 +145,59 @@ components:
           type: string
           example: my-module-revision
 
-    CmHandleQueryRestParameters:
+    CmHandleQueryParameters:
       type: object
       title: Cm Handle query parameters for executing cm handle search
       properties:
-        publicCmHandleProperties:
-          type: object
-          additionalProperties:
-            type: string
-            example: Book Type
+        cmHandleQueryParameters:
+          type: array
+          items:
+            type: object
+            $ref: '#/components/schemas/ConditionProperties'
+        conditions:
+          deprecated: true
+          type: array
+          items:
+            type: object
+            $ref: '#/components/schemas/OldConditionProperties'
+          description: not necessary, it is just for backward compatibility
+      example:
+        cmHandleQueryParameters:
+          - conditionName: hasAllModules
+            conditionParameters:
+              - { "moduleName": "my-module-1" }
+              - { "moduleName": "my-module-2" }
+              - { "moduleName": "my-module-3" }
+          - conditionName: hasAllProperties
+            conditionParameters:
+              - { "Color": "yellow" }
+              - { "Shape": "circle" }
+              - { "Size": "small" }
+    ConditionProperties:
+      properties:
+        conditionName:
+          type: string
+        conditionParameters:
+          type: array
+          items:
+            type: object
+            additionalProperties:
+              type: string
+    OldConditionProperties:
+      deprecated: true
+      properties:
+        name:
+          type: string
+        conditionParameters:
+          type: array
+          items:
+            type: object
+            $ref: '#/components/schemas/ModuleNameAsJsonObject'
+    ModuleNameAsJsonObject:
+      properties:
+        moduleName:
+          type: string
+          example: my-module
 
     RestOutputCmHandle:
       type: object
index 318e6e6..7a894f5 100755 (executable)
@@ -246,26 +246,28 @@ fetchModuleReferencesByCmHandle:
       500:
         $ref: 'components.yaml#/components/responses/InternalServerError'
 
-executeCmHandleSearch:
+searchCmHandles:
   post:
-    description: Execute cm handle searches using 'hasAllModules' condition to get all cm handles for the given module names
+    description: Execute cm handle query search, to be included in the result a cm-handle must fulfill ALL the conditions listed here
     tags:
       - network-cm-proxy
     summary: Execute cm handle search using the available conditions
-    operationId: executeCmHandleSearch
+    operationId: searchCmHandles
     requestBody:
       required: true
       content:
         application/json:
           schema:
-            $ref: 'components.yaml#/components/schemas/Conditions'
+            $ref: 'components.yaml#/components/schemas/CmHandleQueryParameters'
     responses:
       200:
         description: OK
         content:
           application/json:
             schema:
-              $ref: 'components.yaml#/components/schemas/CmHandles'
+              type: array
+              items:
+                $ref: 'components.yaml#/components/schemas/RestOutputCmHandle'
       400:
         $ref: 'components.yaml#/components/responses/BadRequest'
       401:
@@ -317,19 +319,19 @@ getCmHandlePropertiesById:
       500:
         $ref: 'components.yaml#/components/responses/InternalServerError'
 
-queryCmHandles:
+searchCmHandleIds:
   post:
-    description: Execute cm handle query search
+    description: Execute cm handle query search, to be included in the result a cm-handle must fulfill ALL the conditions listed here
     tags:
       - network-cm-proxy
     summary: Execute cm handle query upon a given set of query parameters
-    operationId: queryCmHandles
+    operationId: searchCmHandleIds
     requestBody:
       required: true
       content:
         application/json:
           schema:
-            $ref: 'components.yaml#/components/schemas/CmHandleQueryRestParameters'
+            $ref: 'components.yaml#/components/schemas/CmHandleQueryParameters'
     responses:
       200:
         description: OK
index b408291..81ebf05 100755 (executable)
@@ -36,7 +36,7 @@ paths:
     $ref: 'ncmp.yml#/fetchModuleReferencesByCmHandle'
 
   /v1/ch/searches:
-    $ref: 'ncmp.yml#/executeCmHandleSearch'
+    $ref: 'ncmp.yml#/searchCmHandles'
 
   /v1/ch/{cm-handle}:
     $ref: 'ncmp.yml#/retrieveCmHandleDetailsById'
@@ -44,5 +44,5 @@ paths:
   /v1/ch/{cm-handle}/properties:
     $ref: 'ncmp.yml#/getCmHandlePropertiesById'
 
-  /v1/data/ch/searches:
-    $ref: 'ncmp.yml#/queryCmHandles'
+  /v1/ch/id-searches:
+    $ref: 'ncmp.yml#/searchCmHandleIds'
index 11517bc..ccb1e9b 100755 (executable)
@@ -28,9 +28,6 @@ import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum
 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.PATCH;
 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.UPDATE;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -48,18 +45,12 @@ import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
 import org.onap.cps.ncmp.rest.api.NetworkCmProxyApi;
 import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor;
 import org.onap.cps.ncmp.rest.mapper.RestOutputCmHandleStateMapper;
-import org.onap.cps.ncmp.rest.model.CmHandleProperties;
-import org.onap.cps.ncmp.rest.model.CmHandleProperty;
 import org.onap.cps.ncmp.rest.model.CmHandlePublicProperties;
-import org.onap.cps.ncmp.rest.model.CmHandleQueryRestParameters;
-import org.onap.cps.ncmp.rest.model.CmHandles;
-import org.onap.cps.ncmp.rest.model.ConditionProperties;
-import org.onap.cps.ncmp.rest.model.Conditions;
-import org.onap.cps.ncmp.rest.model.ModuleNameAsJsonObject;
-import org.onap.cps.ncmp.rest.model.ModuleNamesAsJsonArray;
+import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters;
 import org.onap.cps.ncmp.rest.model.RestModuleReference;
 import org.onap.cps.ncmp.rest.model.RestOutputCmHandle;
 import org.onap.cps.ncmp.rest.model.RestOutputCmHandlePublicProperties;
+import org.onap.cps.ncmp.rest.util.DeprecationHelper;
 import org.onap.cps.utils.CpsValidator;
 import org.onap.cps.utils.JsonObjectMapper;
 import org.springframework.beans.factory.annotation.Value;
@@ -79,6 +70,8 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
     private static final String NO_TOPIC = null;
     private final NetworkCmProxyDataService networkCmProxyDataService;
     private final JsonObjectMapper jsonObjectMapper;
+
+    private final DeprecationHelper deprecationHelper;
     private final NcmpRestInputMapper ncmpRestInputMapper;
     private final RestOutputCmHandleStateMapper restOutputCmHandleStateMapper;
     private final CpsNcmpTaskExecutor cpsNcmpTaskExecutor;
@@ -212,30 +205,35 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
     }
 
     /**
-     * Execute cm handle search.
+     * Query and return cm handles that match the given query parameters.
      *
-     * @param conditions the conditions
-     * @return cm handles returned from search.
+     * @param cmHandleQueryParameters the cm handle query parameters
+     * @return collection of cm handles
      */
     @Override
-    public ResponseEntity<CmHandles> executeCmHandleSearch(final Conditions conditions) {
-        final List<ConditionProperties> conditionProperties =
-            conditions.getConditions().stream().collect(Collectors.toList());
-        final CmHandles cmHandles = new CmHandles();
-        cmHandles.setCmHandles(toCmHandleProperties(processConditions(conditionProperties)));
-        return ResponseEntity.ok(cmHandles);
+    public ResponseEntity<List<RestOutputCmHandle>> searchCmHandles(
+            final CmHandleQueryParameters cmHandleQueryParameters) {
+        final CmHandleQueryApiParameters cmHandleQueryApiParameters =
+                deprecationHelper.mapOldConditionProperties(cmHandleQueryParameters);
+        final Set<NcmpServiceCmHandle> cmHandles = networkCmProxyDataService
+                .executeCmHandleSearch(cmHandleQueryApiParameters);
+        final List<RestOutputCmHandle> outputCmHandles =
+                cmHandles.stream().map(this::toRestOutputCmHandle).collect(Collectors.toList());
+        return ResponseEntity.ok(outputCmHandles);
     }
 
     /**
-     * Query and return cm handles that match the given query parameters.
+     * Query and return cm handle ids that match the given query parameters.
      *
-     * @param cmHandleQueryRestParameters the cm handle query parameters
+     * @param cmHandleQueryParameters the cm handle query parameters
      * @return collection of cm handle ids
      */
-    public ResponseEntity<List<String>> queryCmHandles(
-        final CmHandleQueryRestParameters cmHandleQueryRestParameters) {
-        final Set<String> cmHandleIds = networkCmProxyDataService.queryCmHandles(
-            jsonObjectMapper.convertToValueType(cmHandleQueryRestParameters, CmHandleQueryApiParameters.class));
+    @Override
+    public ResponseEntity<List<String>> searchCmHandleIds(
+        final CmHandleQueryParameters cmHandleQueryParameters) {
+        final CmHandleQueryApiParameters cmHandleQueryApiParameters =
+                jsonObjectMapper.convertToValueType(cmHandleQueryParameters, CmHandleQueryApiParameters.class);
+        final Set<String> cmHandleIds = networkCmProxyDataService.executeCmHandleIdSearch(cmHandleQueryApiParameters);
         return ResponseEntity.ok(List.copyOf(cmHandleIds));
     }
 
@@ -281,41 +279,6 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
         return new ResponseEntity<>(restModuleReferences, HttpStatus.OK);
     }
 
-    private Collection<String> processConditions(final List<ConditionProperties> conditionProperties) {
-        for (final ConditionProperties conditionProperty : conditionProperties) {
-            if (conditionProperty.getName().equals("hasAllModules")) {
-                return executeCmHandleSearchesForModuleNames(conditionProperty);
-            } else {
-                log.warn("Unrecognized condition name {}.", conditionProperty.getName());
-            }
-        }
-        log.warn("No valid conditions found {}.", conditionProperties);
-        return Collections.emptyList();
-    }
-
-    private Collection<String> executeCmHandleSearchesForModuleNames(final ConditionProperties conditionProperties) {
-        return networkCmProxyDataService
-            .executeCmHandleHasAllModulesSearch(getModuleNames(conditionProperties.getConditionParameters()));
-    }
-
-    private Collection<String> getModuleNames(final ModuleNamesAsJsonArray moduleNamesAsJsonArray) {
-        final Collection<String> moduleNames = new ArrayList<>(moduleNamesAsJsonArray.size());
-        for (final ModuleNameAsJsonObject moduleNameAsJsonObject : moduleNamesAsJsonArray) {
-            moduleNames.add(moduleNameAsJsonObject.getModuleName());
-        }
-        return moduleNames;
-    }
-
-    private CmHandleProperties toCmHandleProperties(final Collection<String> cmHandleIdentifiers) {
-        final CmHandleProperties cmHandleProperties = new CmHandleProperties();
-        for (final String cmHandleIdentifier : cmHandleIdentifiers) {
-            final CmHandleProperty cmHandleProperty = new CmHandleProperty();
-            cmHandleProperty.setCmHandleId(cmHandleIdentifier);
-            cmHandleProperties.add(cmHandleProperty);
-        }
-        return cmHandleProperties;
-    }
-
     private RestOutputCmHandle toRestOutputCmHandle(final NcmpServiceCmHandle ncmpServiceCmHandle) {
         final RestOutputCmHandle restOutputCmHandle = new RestOutputCmHandle();
         final CmHandlePublicProperties cmHandlePublicProperties = new CmHandlePublicProperties();
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DeprecationHelper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DeprecationHelper.java
new file mode 100644 (file)
index 0000000..fc992da
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  ============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.ncmp.rest.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters;
+import org.onap.cps.ncmp.api.models.ConditionApiProperties;
+import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters;
+import org.onap.cps.utils.JsonObjectMapper;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class DeprecationHelper {
+
+    private final JsonObjectMapper jsonObjectMapper;
+
+    /**
+     * Convert the old condition properties to the new schema.
+     * !!! remove it after the old condition removed !!!
+     * it only works for module names
+     *
+     * @param cmHandleQueryParameters the original input parameter
+     */
+    @Deprecated //this method wil be removed in Release 12 (No Name know yet)
+    public CmHandleQueryApiParameters mapOldConditionProperties(
+                                           final CmHandleQueryParameters cmHandleQueryParameters) {
+        final CmHandleQueryApiParameters cmHandleQueryApiParameters =
+                jsonObjectMapper.convertToValueType(cmHandleQueryParameters, CmHandleQueryApiParameters.class);
+        if (cmHandleQueryParameters.getConditions() != null
+                && cmHandleQueryApiParameters.getCmHandleQueryParameters().isEmpty()) {
+            cmHandleQueryApiParameters.setCmHandleQueryParameters(new ArrayList<>());
+            cmHandleQueryParameters.getConditions().parallelStream().forEach(
+                oldConditionProperty -> {
+                    if (oldConditionProperty.getConditionParameters() != null
+                            && oldConditionProperty.getName() != null) {
+                        final ConditionApiProperties conditionApiProperties = new ConditionApiProperties();
+                        conditionApiProperties.setConditionName(oldConditionProperty.getName());
+                        conditionApiProperties.setConditionParameters(new ArrayList<>());
+                        oldConditionProperty.getConditionParameters().parallelStream().forEach(
+                            oldConditionParameter ->
+                                conditionApiProperties.getConditionParameters().add(Collections
+                                    .singletonMap("moduleName", oldConditionParameter.getModuleName()))
+                        );
+                        cmHandleQueryApiParameters.getCmHandleQueryParameters().add(conditionApiProperties);
+                    }
+                }
+            );
+        }
+
+        return cmHandleQueryApiParameters;
+    }
+}
index 60ea736..036928f 100644 (file)
@@ -29,6 +29,7 @@ import org.onap.cps.ncmp.api.inventory.CompositeState
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
 import org.onap.cps.ncmp.rest.mapper.RestOutputCmHandleStateMapper
 import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor
+import org.onap.cps.ncmp.rest.util.DeprecationHelper
 import spock.lang.Shared
 
 import java.time.OffsetDateTime
@@ -86,6 +87,9 @@ class NetworkCmProxyControllerSpec extends Specification {
     @SpringBean
     CpsNcmpTaskExecutor spiedCpsTaskExecutor = Spy()
 
+    @SpringBean
+    DeprecationHelper stubbedDeprecationHelper = Stub()
+
     @Value('${rest.api.ncmp-base-path}/v1')
     def ncmpBasePathV1
 
@@ -239,8 +243,14 @@ class NetworkCmProxyControllerSpec extends Specification {
         given: 'an endpoint and json data'
             def searchesEndpoint = "$ncmpBasePathV1/ch/searches"
             String jsonString = TestUtils.getResourceFileContent('cmhandle-search.json')
-        and: 'the service method is invoked with module names and returns two cm handle ids'
-            mockNetworkCmProxyDataService.executeCmHandleHasAllModulesSearch(['module1', 'module2']) >> ['some-cmhandle-id1', 'some-cmhandle-id2']
+        and: 'the service method is invoked with module names and returns two cm handles'
+            def cmHandle1 = new NcmpServiceCmHandle()
+            cmHandle1.cmHandleId = 'some-cmhandle-id1'
+            cmHandle1.publicProperties = [color:'yellow']
+            def cmHandle2 = new NcmpServiceCmHandle()
+            cmHandle2.cmHandleId = 'some-cmhandle-id2'
+            cmHandle2.publicProperties = [color:'green']
+            mockNetworkCmProxyDataService.executeCmHandleSearch(_) >> [cmHandle1, cmHandle2]
         when: 'the searches api is invoked'
             def response = mvc.perform(post(searchesEndpoint)
                     .contentType(MediaType.APPLICATION_JSON)
@@ -248,7 +258,7 @@ class NetworkCmProxyControllerSpec extends Specification {
         then: 'response status returns OK'
             response.status == HttpStatus.OK.value()
         and: 'the expected response content is returned'
-            response.contentAsString == '{"cmHandles":[{"cmHandleId":"some-cmhandle-id1"},{"cmHandleId":"some-cmhandle-id2"}]}'
+            response.contentAsString == '[{"cmHandle":"some-cmhandle-id1","publicCmHandleProperties":[{"color":"yellow"}],"state":null},{"cmHandle":"some-cmhandle-id2","publicCmHandleProperties":[{"color":"green"}],"state":null}]'
     }
 
     def 'Get Cm Handle details by Cm Handle id.'() {
@@ -290,31 +300,38 @@ class NetworkCmProxyControllerSpec extends Specification {
         given: 'an endpoint and json data'
             def searchesEndpoint = "$ncmpBasePathV1/ch/searches"
             String jsonString = TestUtils.getResourceFileContent('invalid-cmhandle-search.json')
+        and: 'the service method is invoked with module names and returns two cm handles'
+            def cmHandel1 = new NcmpServiceCmHandle()
+            cmHandel1.cmHandleId = 'some-cmhandle-id1'
+            cmHandel1.publicProperties = [color:'yellow']
+            def cmHandel2 = new NcmpServiceCmHandle()
+            cmHandel2.cmHandleId = 'some-cmhandle-id2'
+            cmHandel2.publicProperties = [color:'green']
+            mockNetworkCmProxyDataService.executeCmHandleSearch(_) >> [cmHandel1, cmHandel2]
         when: 'the searches api is invoked'
             def response = mvc.perform(post(searchesEndpoint)
                     .contentType(MediaType.APPLICATION_JSON)
                     .content(jsonString)).andReturn().response
         then: 'an empty cm handle identifier is returned'
-            response.contentAsString == '{"cmHandles":[]}'
+            response.contentAsString == '[{"cmHandle":"some-cmhandle-id1","publicCmHandleProperties":[{"color":"yellow"}],"state":null},{"cmHandle":"some-cmhandle-id2","publicCmHandleProperties":[{"color":"green"}],"state":null}]'
     }
 
     def 'Query for cm handles matching query parameters'() {
         given: 'an endpoint and json data'
-            def searchesEndpoint = "$ncmpBasePathV1/data/ch/searches"
-            String jsonString = '{"publicCmHandleProperties": {"name": "Contact", "value": "newemailforstore@bookstore.com"}}'
+            def searchesEndpoint = "$ncmpBasePathV1/ch/id-searches"
         and: 'the service method is invoked with module names and returns cm handle ids'
-            1 * mockNetworkCmProxyDataService.queryCmHandles(_) >> ['some-cmhandle-id1', 'some-cmhandle-id2']
+            1 * mockNetworkCmProxyDataService.executeCmHandleIdSearch(_) >> ['some-cmhandle-id1', 'some-cmhandle-id2']
         when: 'the searches api is invoked'
             def response = mvc.perform(post(searchesEndpoint)
                 .contentType(MediaType.APPLICATION_JSON)
-                .content(jsonString)).andReturn().response
+                .content('{}')).andReturn().response
         then: 'cm handle ids are returned'
             response.contentAsString == '["some-cmhandle-id1","some-cmhandle-id2"]'
     }
 
     def 'Query for cm handles with invalid request payload'() {
         when: 'the searches api is invoked'
-            def searchesEndpoint = "$ncmpBasePathV1/data/ch/searches"
+            def searchesEndpoint = "$ncmpBasePathV1/ch/id-searches"
             def invalidInputData = '{invalidJson}'
             def response = mvc.perform(post(searchesEndpoint)
                     .contentType(MediaType.APPLICATION_JSON)
index 45ed3d3..1563c75 100644 (file)
@@ -31,6 +31,7 @@ import org.onap.cps.ncmp.api.impl.exception.ServerNcmpException
 import org.onap.cps.ncmp.rest.controller.NcmpRestInputMapper
 import org.onap.cps.ncmp.rest.mapper.RestOutputCmHandleStateMapper
 import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor
+import org.onap.cps.ncmp.rest.util.DeprecationHelper
 import org.onap.cps.spi.exceptions.CpsException
 import org.onap.cps.spi.exceptions.DataNodeNotFoundException
 import org.onap.cps.spi.exceptions.DataValidationException
@@ -47,7 +48,6 @@ import spock.lang.Specification
 
 import static org.onap.cps.ncmp.rest.exceptions.NetworkCmProxyRestExceptionHandlerSpec.ApiType.NCMP
 import static org.onap.cps.ncmp.rest.exceptions.NetworkCmProxyRestExceptionHandlerSpec.ApiType.NCMPINVENTORY
-import static org.springframework.http.HttpStatus.BAD_GATEWAY
 import static org.springframework.http.HttpStatus.BAD_REQUEST
 import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR
 import static org.springframework.http.HttpStatus.NOT_FOUND
@@ -75,6 +75,9 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification {
     @SpringBean
     CpsNcmpTaskExecutor stubbedCpsTaskExecutor = Stub()
 
+    @SpringBean
+    DeprecationHelper stubbedDeprecationHelper = Stub()
+
     @Value('${rest.api.ncmp-base-path}')
     def basePathNcmp
 
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/DeprecationHelperSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/DeprecationHelperSpec.groovy
new file mode 100644 (file)
index 0000000..8c212d3
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *  ============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.ncmp.rest.util
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters
+import org.onap.cps.ncmp.api.models.ConditionApiProperties
+import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters
+import org.onap.cps.ncmp.rest.model.ConditionProperties
+import org.onap.cps.ncmp.rest.model.ModuleNameAsJsonObject
+import org.onap.cps.ncmp.rest.model.OldConditionProperties
+import org.onap.cps.utils.JsonObjectMapper
+import spock.lang.Specification
+
+class DeprecationHelperSpec extends Specification {
+
+    DeprecationHelper deprecationHelper = new DeprecationHelper(new JsonObjectMapper(new ObjectMapper()))
+
+    def 'Map deprecated condition properties - #scenario.'() {
+        given: 'a deprecated condition properties'
+            def cmHandleQueryParameters = new CmHandleQueryParameters()
+            cmHandleQueryParameters.conditions = oldConditionPropertiesArray
+            cmHandleQueryParameters.cmHandleQueryParameters = cmHandleQueryParametersArray
+        when: 'converted into the new format'
+            def result = deprecationHelper.mapOldConditionProperties(cmHandleQueryParameters)
+        then: 'result is the expected'
+            assert result == new CmHandleQueryApiParameters(cmHandleQueryParameters: expectedCmHandleQueryApiParametersArray)
+        where:
+            scenario                           | oldConditionPropertiesArray                                                                                                   | cmHandleQueryParametersArray                                                                           || expectedCmHandleQueryApiParametersArray
+            'mapping old query'                | [new OldConditionProperties(name: 'hasAllModule', conditionParameters: [new ModuleNameAsJsonObject(moduleName: 'module-1')])] | []                                                                                                     || [new ConditionApiProperties(conditionName: 'hasAllModule', conditionParameters: [[moduleName:'module-1']])]
+            'old condition is null'            | null                                                                                                                          | []                                                                                                     || []
+            'old condition parameters is null' | [new OldConditionProperties(name: 'hasAllModule', conditionParameters: null)]                                                 | []                                                                                                     || []
+            'old condition name is null'       | [new OldConditionProperties(name: null, conditionParameters: [new ModuleNameAsJsonObject(moduleName: 'module-1')])]           | []                                                                                                     || []
+            'new query parameters are filled'  | [new OldConditionProperties(name: 'hasAllModule', conditionParameters: [new ModuleNameAsJsonObject(moduleName: 'module-1')])] | [new ConditionProperties(conditionName: 'hasAllModule', conditionParameters: [[moduleName:'module-2']])] || [new ConditionApiProperties(conditionName: 'hasAllModule', conditionParameters: [[moduleName:'module-2']])]
+    }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyCmHandlerQueryService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyCmHandlerQueryService.java
new file mode 100644 (file)
index 0000000..f8d51fe
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *  ============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.ncmp.api;
+
+import java.util.Collection;
+import org.onap.cps.spi.model.CmHandleQueryParameters;
+import org.onap.cps.spi.model.DataNode;
+
+public interface NetworkCmProxyCmHandlerQueryService {
+    /**
+     * Query and return cm handles that match the given query parameters.
+     *
+     * @param cmHandleQueryParameters the cm handle query parameters
+     * @return collection of cm handles
+     */
+    Collection<DataNode> queryCmHandles(CmHandleQueryParameters cmHandleQueryParameters);
+}
index 7527ae5..ce850cc 100644 (file)
@@ -105,15 +105,6 @@ public interface NetworkCmProxyDataService {
      */
     Collection<ModuleReference> getYangResourcesModuleReferences(String cmHandleId);
 
-    /**
-     * Query cm handle identifiers for the given collection of module names.
-     *
-     * @param moduleNames module names.
-     * @return a collection of cm handle identifiers. The schema set for each cm handle must include all the
-     *         given module names
-     */
-    Collection<String> executeCmHandleHasAllModulesSearch(Collection<String> moduleNames);
-
     /**
      * Query cm handle details by cm handle's name.
      *
@@ -134,7 +125,15 @@ public interface NetworkCmProxyDataService {
      * Query and return cm handles that match the given query parameters.
      *
      * @param cmHandleQueryApiParameters the cm handle query parameters
+     * @return collection of cm handles
+     */
+    Set<NcmpServiceCmHandle> executeCmHandleSearch(CmHandleQueryApiParameters cmHandleQueryApiParameters);
+
+    /**
+     * Query and return cm handle ids that match the given query parameters.
+     *
+     * @param cmHandleQueryApiParameters the cm handle query parameters
      * @return collection of cm handle ids
      */
-    Set<String> queryCmHandles(CmHandleQueryApiParameters cmHandleQueryApiParameters);
+    Set<String> executeCmHandleIdSearch(CmHandleQueryApiParameters cmHandleQueryApiParameters);
 }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java
new file mode 100644 (file)
index 0000000..ef6e953
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ *  ============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.ncmp.api.impl;
+
+import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NCMP_DATASPACE_NAME;
+import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NCMP_DMI_REGISTRY_ANCHOR;
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
+import static org.onap.cps.utils.CmHandleQueryRestParametersValidator.validateModuleNameConditionProperties;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService;
+import org.onap.cps.spi.CpsAdminPersistenceService;
+import org.onap.cps.spi.CpsDataPersistenceService;
+import org.onap.cps.spi.model.Anchor;
+import org.onap.cps.spi.model.CmHandleQueryParameters;
+import org.onap.cps.spi.model.ConditionProperties;
+import org.onap.cps.spi.model.DataNode;
+import org.onap.cps.spi.model.DataNodeIdentifier;
+import org.onap.cps.utils.JsonObjectMapper;
+import org.springframework.stereotype.Service;
+
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCmHandlerQueryService {
+
+    private static final String PROPERTY_QUERY_NAME = "hasAllProperties";
+    private static final String MODULE_QUERY_NAME = "hasAllModules";
+    private final CpsDataPersistenceService cpsDataPersistenceService;
+    private final CpsAdminPersistenceService cpsAdminPersistenceService;
+    private final JsonObjectMapper jsonObjectMapper;
+
+    /**
+     * Query and return cm handles that match the given query parameters.
+     *
+     * @param cmHandleQueryParameters the cm handle query parameters
+     * @return collection of cm handles
+     */
+    @Override
+    public Collection<DataNode> queryCmHandles(final CmHandleQueryParameters cmHandleQueryParameters) {
+
+        if (cmHandleQueryParameters.getCmHandleQueryParameters().isEmpty()) {
+            return getAllCmHandles();
+        }
+
+        final Collection<DataNodeIdentifier> amalgamatedQueryResultIdentifiers = new ArrayList<>();
+        final Map<DataNodeIdentifier, DataNode> amalgamatedQueryResults = new HashMap<>();
+
+        final boolean firstQuery = moduleNameQuery(cmHandleQueryParameters,
+                amalgamatedQueryResultIdentifiers, amalgamatedQueryResults);
+
+        publicPropertyQuery(cmHandleQueryParameters, amalgamatedQueryResultIdentifiers,
+                amalgamatedQueryResults, firstQuery);
+
+        final Collection<DataNode> filteredDataNodes = new ArrayList<>();
+        amalgamatedQueryResultIdentifiers.forEach(amalgamatedQueryResultIdentifier ->
+            filteredDataNodes.add(amalgamatedQueryResults.get(amalgamatedQueryResultIdentifier))
+        );
+
+        return filteredDataNodes;
+    }
+
+    private void publicPropertyQuery(final CmHandleQueryParameters cmHandleQueryParameters,
+                                     final Collection<DataNodeIdentifier> amalgamatedQueryResultIdentifiers,
+                                     final Map<DataNodeIdentifier, DataNode> amalgamatedQueryResults,
+                                     boolean firstQuery) {
+        for (final Map.Entry<String, String> entry :
+                getPublicPropertyPairs(cmHandleQueryParameters.getCmHandleQueryParameters()).entrySet()) {
+            final String cmHandlePath = "//public-properties[@name='" + entry.getKey() + "' " + "and @value='"
+                    + entry.getValue() + "']" + "/ancestor::cm-handles";
+
+            final Collection<DataNode> dataNodes = getDataNodes(cmHandlePath);
+
+            if (firstQuery) {
+                firstQuery = false;
+                dataNodes.forEach(dataNode -> {
+                    final DataNodeIdentifier dataNodeIdentifier =
+                            jsonObjectMapper.convertToValueType(dataNode, DataNodeIdentifier.class);
+                    amalgamatedQueryResultIdentifiers.add(dataNodeIdentifier);
+                    amalgamatedQueryResults.put(dataNodeIdentifier, dataNode);
+                });
+            } else {
+                final Collection<DataNodeIdentifier> singleConditionQueryDataNodeIdentifiers = new ArrayList<>();
+                dataNodes.forEach(dataNode -> {
+                    final DataNodeIdentifier dataNodeIdentifier =
+                            jsonObjectMapper.convertToValueType(dataNode, DataNodeIdentifier.class);
+                    singleConditionQueryDataNodeIdentifiers.add(dataNodeIdentifier);
+                    amalgamatedQueryResults.put(dataNodeIdentifier, dataNode);
+                });
+                amalgamatedQueryResultIdentifiers.retainAll(singleConditionQueryDataNodeIdentifiers);
+            }
+
+            if (amalgamatedQueryResultIdentifiers.isEmpty()) {
+                break;
+            }
+        }
+    }
+
+    private boolean moduleNameQuery(final CmHandleQueryParameters cmHandleQueryParameters,
+                                    final Collection<DataNodeIdentifier> amalgamatedQueryResultIdentifiers,
+                                    final Map<DataNodeIdentifier, DataNode> amalgamatedQueryResults) {
+        boolean firstQuery = true;
+        if (!getModuleNames(cmHandleQueryParameters.getCmHandleQueryParameters()).isEmpty()) {
+            final Collection<Anchor> anchors = cpsAdminPersistenceService.queryAnchors("NFP-Operational",
+                    getModuleNames(cmHandleQueryParameters.getCmHandleQueryParameters()));
+            anchors.forEach(anchor -> {
+                final List<DataNode> dataNodes = getDataNodes("//cm-handles[@id='" + anchor.getName() + "']");
+                dataNodes.parallelStream().forEach(dataNode -> {
+                    final DataNodeIdentifier dataNodeIdentifier =
+                            jsonObjectMapper.convertToValueType(dataNode, DataNodeIdentifier.class);
+                    amalgamatedQueryResultIdentifiers.add(dataNodeIdentifier);
+                    amalgamatedQueryResults.put(dataNodeIdentifier, dataNode);
+                });
+            });
+            firstQuery = false;
+        }
+        return firstQuery;
+    }
+
+    private List<Map<String, String>> getConditions(final List<ConditionProperties> conditionProperties,
+                                                    final String name) {
+        for (final ConditionProperties conditionProperty : conditionProperties) {
+            if (conditionProperty.getConditionName().equals(name)) {
+                return conditionProperty.getConditionParameters();
+            }
+        }
+        return Collections.emptyList();
+    }
+
+    private List<String> getModuleNames(final List<ConditionProperties> conditionProperties) {
+        final List<String> result = new ArrayList<>();
+        getConditions(conditionProperties, MODULE_QUERY_NAME).parallelStream().forEach(
+                conditionProperty -> {
+                    validateModuleNameConditionProperties(conditionProperty);
+                    result.add(conditionProperty.get("moduleName"));
+                }
+        );
+        return result;
+    }
+
+    private Map<String, String> getPublicPropertyPairs(final List<ConditionProperties> conditionProperties) {
+        final Map<String, String> result = new HashMap<>();
+        getConditions(conditionProperties, PROPERTY_QUERY_NAME).forEach(result::putAll);
+        return result;
+    }
+
+    private Collection<DataNode> getAllCmHandles() {
+        return getDataNodes("//public-properties/ancestor::cm-handles");
+    }
+
+    private List<DataNode> getDataNodes(final String cmHandlePath) {
+        return cpsDataPersistenceService.queryDataNodes(
+                NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cmHandlePath, INCLUDE_ALL_DESCENDANTS);
+    }
+}
index 717cae5..6ba1043 100755 (executable)
@@ -30,12 +30,11 @@ import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NFP_OPER
 import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NO_TIMESTAMP;
 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum;
 import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED;
+import static org.onap.cps.utils.CmHandleQueryRestParametersValidator.validateCmHandleQueryParameters;
 
-import com.google.common.base.Strings;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -45,9 +44,11 @@ import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.api.CpsAdminService;
 import org.onap.cps.api.CpsDataService;
 import org.onap.cps.api.CpsModuleService;
+import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService;
 import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
 import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations;
 import org.onap.cps.ncmp.api.impl.operations.DmiOperations;
+import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
 import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.api.inventory.sync.ModuleSyncService;
@@ -61,6 +62,7 @@ import org.onap.cps.spi.exceptions.AlreadyDefinedException;
 import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
 import org.onap.cps.spi.exceptions.DataValidationException;
 import org.onap.cps.spi.exceptions.SchemaSetNotFoundException;
+import org.onap.cps.spi.model.CmHandleQueryParameters;
 import org.onap.cps.spi.model.ModuleReference;
 import org.onap.cps.utils.CpsValidator;
 import org.onap.cps.utils.JsonObjectMapper;
@@ -88,21 +90,23 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
 
     private final ModuleSyncService moduleSyncService;
 
+    private final NetworkCmProxyCmHandlerQueryService networkCmProxyCmHandlerQueryService;
+
     @Override
     public DmiPluginRegistrationResponse updateDmiRegistrationAndSyncModule(
-        final DmiPluginRegistration dmiPluginRegistration) {
+            final DmiPluginRegistration dmiPluginRegistration) {
         dmiPluginRegistration.validateDmiPluginRegistration();
         final DmiPluginRegistrationResponse dmiPluginRegistrationResponse = new DmiPluginRegistrationResponse();
         dmiPluginRegistrationResponse.setRemovedCmHandles(
-            parseAndRemoveCmHandlesInDmiRegistration(dmiPluginRegistration.getRemovedCmHandles()));
+                parseAndRemoveCmHandlesInDmiRegistration(dmiPluginRegistration.getRemovedCmHandles()));
         if (!dmiPluginRegistration.getCreatedCmHandles().isEmpty()) {
             dmiPluginRegistrationResponse.setCreatedCmHandles(
-                parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration));
+                    parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration));
         }
         if (!dmiPluginRegistration.getUpdatedCmHandles().isEmpty()) {
             dmiPluginRegistrationResponse.setUpdatedCmHandles(
-                networkCmProxyDataServicePropertyHandler
-                    .updateCmHandleProperties(dmiPluginRegistration.getUpdatedCmHandles()));
+                    networkCmProxyDataServicePropertyHandler
+                            .updateCmHandleProperties(dmiPluginRegistration.getUpdatedCmHandles()));
         }
         return dmiPluginRegistrationResponse;
     }
@@ -154,28 +158,35 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
     }
 
     /**
-     * Retrieve cm handle identifiers for the given list of module names.
+     * Retrieve cm handles with details for the given query parameters.
      *
-     * @param moduleNames module names.
-     * @return a collection of anchor identifiers
+     * @param cmHandleQueryApiParameters cm handle query parameters
+     * @return cm handles with details
      */
     @Override
-    public Collection<String> executeCmHandleHasAllModulesSearch(final Collection<String> moduleNames) {
-        return cpsAdminService.queryAnchorNames(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, moduleNames);
-    }
+    public Set<NcmpServiceCmHandle> executeCmHandleSearch(final CmHandleQueryApiParameters cmHandleQueryApiParameters) {
 
-    @Override
-    public Set<String> queryCmHandles(final CmHandleQueryApiParameters cmHandleQueryApiParameters) {
+        final CmHandleQueryParameters cmHandleQueryParameters = jsonObjectMapper.convertToValueType(
+                cmHandleQueryApiParameters, CmHandleQueryParameters.class);
 
-        cmHandleQueryApiParameters.getPublicProperties().forEach((key, value) -> {
-            if (Strings.isNullOrEmpty(key)) {
-                throw new DataValidationException("Invalid Query Parameter.",
-                    "Missing property name - please supply a valid name.");
-            }
-        });
+        validateCmHandleQueryParameters(cmHandleQueryParameters);
+
+        return networkCmProxyCmHandlerQueryService.queryCmHandles(cmHandleQueryParameters).stream()
+                .map(dataNode -> YangDataConverter
+                        .convertCmHandleToYangModel(dataNode, dataNode.getLeaves().get("id").toString()))
+                .map(YangDataConverter::convertYangModelCmHandleToNcmpServiceCmHandle).collect(Collectors.toSet());
+    }
 
-        return cpsAdminService.queryCmHandles(jsonObjectMapper.convertToValueType(cmHandleQueryApiParameters,
-            org.onap.cps.spi.model.CmHandleQueryParameters.class));
+    /**
+     * Retrieve cm handle ids for the given query parameters.
+     *
+     * @param cmHandleQueryApiParameters cm handle query parameters
+     * @return cm handle ids
+     */
+    @Override
+    public Set<String> executeCmHandleIdSearch(final CmHandleQueryApiParameters cmHandleQueryApiParameters) {
+        return executeCmHandleSearch(cmHandleQueryApiParameters).stream().map(NcmpServiceCmHandle::getCmHandleId)
+                .collect(Collectors.toSet());
     }
 
     /**
@@ -187,16 +198,8 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
     @Override
     public NcmpServiceCmHandle getNcmpServiceCmHandle(final String cmHandleId) {
         CpsValidator.validateNameCharacters(cmHandleId);
-        final NcmpServiceCmHandle ncmpServiceCmHandle = new NcmpServiceCmHandle();
-        final YangModelCmHandle yangModelCmHandle =
-            inventoryPersistence.getYangModelCmHandle(cmHandleId);
-        final List<YangModelCmHandle.Property> dmiProperties = yangModelCmHandle.getDmiProperties();
-        final List<YangModelCmHandle.Property> publicProperties = yangModelCmHandle.getPublicProperties();
-        ncmpServiceCmHandle.setCmHandleId(yangModelCmHandle.getId());
-        ncmpServiceCmHandle.setCompositeState(yangModelCmHandle.getCompositeState());
-        setDmiProperties(dmiProperties, ncmpServiceCmHandle);
-        setPublicProperties(publicProperties, ncmpServiceCmHandle);
-        return ncmpServiceCmHandle;
+        return YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(
+                inventoryPersistence.getYangModelCmHandle(cmHandleId));
     }
 
     /**
@@ -212,7 +215,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
             inventoryPersistence.getYangModelCmHandle(cmHandleId);
         final List<YangModelCmHandle.Property> yangModelPublicProperties = yangModelCmHandle.getPublicProperties();
         final Map<String, String> cmHandlePublicProperties = new HashMap<>();
-        asPropertiesMap(yangModelPublicProperties, cmHandlePublicProperties);
+        YangDataConverter.asPropertiesMap(yangModelPublicProperties, cmHandlePublicProperties);
         return cmHandlePublicProperties;
     }
 
@@ -223,23 +226,23 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
      * @return cm-handle registration response for create cm-handle requests.
      */
     public List<CmHandleRegistrationResponse> parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(
-        final DmiPluginRegistration dmiPluginRegistration) {
+            final DmiPluginRegistration dmiPluginRegistration) {
         List<CmHandleRegistrationResponse> cmHandleRegistrationResponses = new ArrayList<>();
         try {
             cmHandleRegistrationResponses = dmiPluginRegistration.getCreatedCmHandles().stream()
-                .map(cmHandle ->
-                    YangModelCmHandle.toYangModelCmHandle(
-                        dmiPluginRegistration.getDmiPlugin(),
-                        dmiPluginRegistration.getDmiDataPlugin(),
-                        dmiPluginRegistration.getDmiModelPlugin(), cmHandle)
-                )
-                .map(this::registerAndSyncNewCmHandle)
-                .collect(Collectors.toList());
+                    .map(cmHandle ->
+                            YangModelCmHandle.toYangModelCmHandle(
+                                    dmiPluginRegistration.getDmiPlugin(),
+                                    dmiPluginRegistration.getDmiDataPlugin(),
+                                    dmiPluginRegistration.getDmiModelPlugin(), cmHandle)
+                    )
+                    .map(this::registerAndSyncNewCmHandle)
+                    .collect(Collectors.toList());
         } catch (final DataValidationException dataValidationException) {
             cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createFailureResponse(dmiPluginRegistration
-                    .getCreatedCmHandles().stream()
-                    .map(NcmpServiceCmHandle::getCmHandleId).findFirst().orElse(null),
-                RegistrationError.CM_HANDLE_INVALID_ID));
+                            .getCreatedCmHandles().stream()
+                            .map(NcmpServiceCmHandle::getCmHandleId).findFirst().orElse(null),
+                    RegistrationError.CM_HANDLE_INVALID_ID));
         }
         return cmHandleRegistrationResponses;
     }
@@ -252,31 +255,31 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
     }
 
     protected List<CmHandleRegistrationResponse> parseAndRemoveCmHandlesInDmiRegistration(
-        final List<String> tobeRemovedCmHandles) {
+            final List<String> tobeRemovedCmHandles) {
         final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses =
-            new ArrayList<>(tobeRemovedCmHandles.size());
+                new ArrayList<>(tobeRemovedCmHandles.size());
         for (final String cmHandle : tobeRemovedCmHandles) {
             try {
                 CpsValidator.validateNameCharacters(cmHandle);
                 deleteSchemaSetWithCascade(cmHandle);
                 cpsDataService.deleteListOrListElement(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
-                    "/dmi-registry/cm-handles[@id='" + cmHandle + "']", NO_TIMESTAMP);
+                        "/dmi-registry/cm-handles[@id='" + cmHandle + "']", NO_TIMESTAMP);
                 cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandle));
             } catch (final DataNodeNotFoundException dataNodeNotFoundException) {
                 log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}",
-                    cmHandle, dataNodeNotFoundException.getMessage());
+                        cmHandle, dataNodeNotFoundException.getMessage());
                 cmHandleRegistrationResponses.add(CmHandleRegistrationResponse
-                    .createFailureResponse(cmHandle, RegistrationError.CM_HANDLE_DOES_NOT_EXIST));
+                        .createFailureResponse(cmHandle, RegistrationError.CM_HANDLE_DOES_NOT_EXIST));
             } catch (final DataValidationException dataValidationException) {
                 log.error("Unable to de-register cm-handle id: {}, caused by: {}",
-                    cmHandle, dataValidationException.getMessage());
+                        cmHandle, dataValidationException.getMessage());
                 cmHandleRegistrationResponses.add(CmHandleRegistrationResponse
-                    .createFailureResponse(cmHandle, RegistrationError.CM_HANDLE_INVALID_ID));
+                        .createFailureResponse(cmHandle, RegistrationError.CM_HANDLE_INVALID_ID));
             } catch (final Exception exception) {
                 log.error("Unable to de-register cm-handle id : {} , caused by : {}",
-                    cmHandle, exception.getMessage());
+                        cmHandle, exception.getMessage());
                 cmHandleRegistrationResponses.add(
-                    CmHandleRegistrationResponse.createFailureResponse(cmHandle, exception));
+                        CmHandleRegistrationResponse.createFailureResponse(cmHandle, exception));
             }
         }
         return cmHandleRegistrationResponses;
@@ -285,47 +288,25 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
     private void deleteSchemaSetWithCascade(final String schemaSetName) {
         try {
             cpsModuleService.deleteSchemaSet(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetName,
-                CASCADE_DELETE_ALLOWED);
+                    CASCADE_DELETE_ALLOWED);
         } catch (final SchemaSetNotFoundException schemaSetNotFoundException) {
             log.warn("Schema set {} does not exist or already deleted", schemaSetName);
         }
     }
 
-    private void setDmiProperties(final List<YangModelCmHandle.Property> dmiProperties,
-                                  final NcmpServiceCmHandle ncmpServiceCmHandle) {
-        final Map<String, String> dmiPropertiesMap = new LinkedHashMap<>(dmiProperties.size());
-        asPropertiesMap(dmiProperties, dmiPropertiesMap);
-        ncmpServiceCmHandle.setDmiProperties(dmiPropertiesMap);
-    }
-
-    private void setPublicProperties(final List<YangModelCmHandle.Property> publicProperties,
-                                     final NcmpServiceCmHandle ncmpServiceCmHandle) {
-        final Map<String, String> publicPropertiesMap = new LinkedHashMap<>();
-        asPropertiesMap(publicProperties, publicPropertiesMap);
-        ncmpServiceCmHandle.setPublicProperties(publicPropertiesMap);
-    }
-
-    private void asPropertiesMap(final List<YangModelCmHandle.Property> properties,
-                                 final Map<String, String> propertiesMap) {
-        for (final YangModelCmHandle.Property property: properties) {
-            propertiesMap.put(property.getName(), property.getValue());
-        }
-    }
-
     private CmHandleRegistrationResponse registerAndSyncNewCmHandle(final YangModelCmHandle yangModelCmHandle) {
         try {
             final String cmHandleJsonData = String.format("{\"cm-handles\":[%s]}",
-                jsonObjectMapper.asJsonString(yangModelCmHandle));
+                    jsonObjectMapper.asJsonString(yangModelCmHandle));
             cpsDataService.saveListElements(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT,
-                cmHandleJsonData, NO_TIMESTAMP);
+                    cmHandleJsonData, NO_TIMESTAMP);
             syncModulesAndCreateAnchor(yangModelCmHandle);
             return CmHandleRegistrationResponse.createSuccessResponse(yangModelCmHandle.getId());
         } catch (final AlreadyDefinedException alreadyDefinedException) {
             return CmHandleRegistrationResponse.createFailureResponse(
-                yangModelCmHandle.getId(), RegistrationError.CM_HANDLE_ALREADY_EXIST);
+                    yangModelCmHandle.getId(), RegistrationError.CM_HANDLE_ALREADY_EXIST);
         } catch (final Exception exception) {
             return CmHandleRegistrationResponse.createFailureResponse(yangModelCmHandle.getId(), exception);
         }
     }
-
 }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java
new file mode 100644 (file)
index 0000000..1df7bba
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *  ============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.ncmp.api.impl.utils;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.ncmp.api.inventory.CompositeState;
+import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder;
+import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
+import org.onap.cps.spi.model.DataNode;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class YangDataConverter {
+
+    /**
+     * This method convert yang model cm handle to ncmp service cm handle.
+     * @param yangModelCmHandle the yang model of the cm handle
+     * @return ncmp service cm handle
+     */
+    public static NcmpServiceCmHandle convertYangModelCmHandleToNcmpServiceCmHandle(
+            final YangModelCmHandle yangModelCmHandle) {
+        final NcmpServiceCmHandle ncmpServiceCmHandle = new NcmpServiceCmHandle();
+        final List<YangModelCmHandle.Property> dmiProperties = yangModelCmHandle.getDmiProperties();
+        final List<YangModelCmHandle.Property> publicProperties = yangModelCmHandle.getPublicProperties();
+        ncmpServiceCmHandle.setCmHandleId(yangModelCmHandle.getId());
+        ncmpServiceCmHandle.setCompositeState(yangModelCmHandle.getCompositeState());
+        setDmiProperties(dmiProperties, ncmpServiceCmHandle);
+        setPublicProperties(publicProperties, ncmpServiceCmHandle);
+        return ncmpServiceCmHandle;
+    }
+
+    /**
+     * This method convert yang model cm handle properties to simple map.
+     * @param properties the yang model cm handle properties
+     * @param propertiesMap the String, String map for the results
+     */
+    public static void asPropertiesMap(final List<YangModelCmHandle.Property> properties,
+                                       final Map<String, String> propertiesMap) {
+        for (final YangModelCmHandle.Property property : properties) {
+            propertiesMap.put(property.getName(), property.getValue());
+        }
+    }
+
+    /**
+     * This method convert cm handle data node to yang model cm handle.
+     * @param cmHandleDataNode the datanode of the cm handle
+     * @param cmHandleId the id of the cm handle
+     * @return yang model cm handle
+     */
+    public static YangModelCmHandle convertCmHandleToYangModel(final DataNode cmHandleDataNode,
+                                                               final String cmHandleId) {
+        final NcmpServiceCmHandle ncmpServiceCmHandle = new NcmpServiceCmHandle();
+        ncmpServiceCmHandle.setCmHandleId(cmHandleId);
+        populateCmHandleDetails(cmHandleDataNode, ncmpServiceCmHandle);
+        return YangModelCmHandle.toYangModelCmHandle(
+                (String) cmHandleDataNode.getLeaves().get("dmi-service-name"),
+                (String) cmHandleDataNode.getLeaves().get("dmi-data-service-name"),
+                (String) cmHandleDataNode.getLeaves().get("dmi-model-service-name"),
+                ncmpServiceCmHandle
+        );
+    }
+
+    private static void populateCmHandleDetails(final DataNode cmHandleDataNode,
+                                                final NcmpServiceCmHandle ncmpServiceCmHandle) {
+        final Map<String, String> dmiProperties = new LinkedHashMap<>();
+        final Map<String, String> publicProperties = new LinkedHashMap<>();
+        final CompositeStateBuilder compositeStateBuilder = new CompositeStateBuilder();
+        CompositeState compositeState = compositeStateBuilder.build();
+        for (final DataNode childDataNode: cmHandleDataNode.getChildDataNodes()) {
+            if (childDataNode.getXpath().contains("/additional-properties[@name=")) {
+                addProperty(childDataNode, dmiProperties);
+            } else if (childDataNode.getXpath().contains("/public-properties[@name=")) {
+                addProperty(childDataNode, publicProperties);
+            } else if (childDataNode.getXpath().endsWith("/state")) {
+                compositeState = compositeStateBuilder.fromDataNode(childDataNode).build();
+            }
+        }
+        ncmpServiceCmHandle.setDmiProperties(dmiProperties);
+        ncmpServiceCmHandle.setPublicProperties(publicProperties);
+        ncmpServiceCmHandle.setCompositeState(compositeState);
+    }
+
+    private static void addProperty(final DataNode propertyDataNode, final Map<String, String> propertiesAsMap) {
+        propertiesAsMap.put(String.valueOf(propertyDataNode.getLeaves().get("name")),
+                String.valueOf(propertyDataNode.getLeaves().get("value")));
+    }
+
+    private static void setDmiProperties(final List<YangModelCmHandle.Property> dmiProperties,
+                                  final NcmpServiceCmHandle ncmpServiceCmHandle) {
+        final Map<String, String> dmiPropertiesMap = new LinkedHashMap<>(dmiProperties.size());
+        asPropertiesMap(dmiProperties, dmiPropertiesMap);
+        ncmpServiceCmHandle.setDmiProperties(dmiPropertiesMap);
+    }
+
+    private static void setPublicProperties(final List<YangModelCmHandle.Property> publicProperties,
+                                     final NcmpServiceCmHandle ncmpServiceCmHandle) {
+        final Map<String, String> publicPropertiesMap = new LinkedHashMap<>();
+        asPropertiesMap(publicProperties, publicPropertiesMap);
+        ncmpServiceCmHandle.setPublicProperties(publicPropertiesMap);
+    }
+}
index 873a449..c880ec7 100644 (file)
 package org.onap.cps.ncmp.api.inventory;
 
 import java.time.OffsetDateTime;
-import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
 import lombok.RequiredArgsConstructor;
 import org.onap.cps.api.CpsDataService;
+import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
 import org.onap.cps.spi.CpsDataPersistenceService;
 import org.onap.cps.spi.FetchDescendantsOption;
 import org.onap.cps.spi.model.DataNode;
@@ -98,16 +96,7 @@ public class InventoryPersistence {
      */
     public YangModelCmHandle getYangModelCmHandle(final String cmHandleId) {
         CpsValidator.validateNameCharacters(cmHandleId);
-        final DataNode cmHandleDataNode = getCmHandleDataNode(cmHandleId);
-        final NcmpServiceCmHandle ncmpServiceCmHandle = new NcmpServiceCmHandle();
-        ncmpServiceCmHandle.setCmHandleId(cmHandleId);
-        populateCmHandleDetails(cmHandleDataNode, ncmpServiceCmHandle);
-        return YangModelCmHandle.toYangModelCmHandle(
-            (String) cmHandleDataNode.getLeaves().get("dmi-service-name"),
-            (String) cmHandleDataNode.getLeaves().get("dmi-data-service-name"),
-            (String) cmHandleDataNode.getLeaves().get("dmi-model-service-name"),
-            ncmpServiceCmHandle
-        );
+        return YangDataConverter.convertCmHandleToYangModel(getCmHandleDataNode(cmHandleId), cmHandleId);
     }
 
     private DataNode getCmHandleDataNode(final String cmHandle) {
@@ -118,29 +107,4 @@ public class InventoryPersistence {
             FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
     }
 
-    private static void populateCmHandleDetails(final DataNode cmHandleDataNode,
-                                                final NcmpServiceCmHandle ncmpServiceCmHandle) {
-        final Map<String, String> dmiProperties = new LinkedHashMap<>();
-        final Map<String, String> publicProperties = new LinkedHashMap<>();
-        final CompositeStateBuilder compositeStateBuilder = new CompositeStateBuilder();
-        CompositeState compositeState = compositeStateBuilder.build();
-        for (final DataNode childDataNode: cmHandleDataNode.getChildDataNodes()) {
-            if (childDataNode.getXpath().contains("/additional-properties[@name=")) {
-                addProperty(childDataNode, dmiProperties);
-            } else if (childDataNode.getXpath().contains("/public-properties[@name=")) {
-                addProperty(childDataNode, publicProperties);
-            } else if (childDataNode.getXpath().endsWith("/state")) {
-                compositeState = compositeStateBuilder.fromDataNode(childDataNode).build();
-            }
-        }
-        ncmpServiceCmHandle.setDmiProperties(dmiProperties);
-        ncmpServiceCmHandle.setPublicProperties(publicProperties);
-        ncmpServiceCmHandle.setCompositeState(compositeState);
-    }
-
-    private static void addProperty(final DataNode propertyDataNode, final Map<String, String> propertiesAsMap) {
-        propertiesAsMap.put(String.valueOf(propertyDataNode.getLeaves().get("name")),
-            String.valueOf(propertyDataNode.getLeaves().get("value")));
-    }
-
 }
index 3f584ed..bf6600d 100644 (file)
 
 package org.onap.cps.ncmp.api.models;
 
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import java.util.Collections;
-import java.util.Map;
+import java.util.List;
 import javax.validation.Valid;
+import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.Setter;
 
-@Setter
 @Getter
-@JsonInclude(Include.NON_NULL)
+@Setter
+@EqualsAndHashCode
+@JsonInclude(Include.NON_EMPTY)
+@JsonIgnoreProperties(ignoreUnknown = true)
 public class CmHandleQueryApiParameters {
-
-    @JsonProperty("publicCmHandleProperties")
+    @JsonProperty("cmHandleQueryParameters")
     @Valid
-    private Map<String, String> publicProperties = Collections.emptyMap();
-
+    private List<ConditionApiProperties> cmHandleQueryParameters = Collections.emptyList();
 }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/ConditionApiProperties.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/ConditionApiProperties.java
new file mode 100644 (file)
index 0000000..9f6d64e
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *  ============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.ncmp.api.models;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import javax.validation.Valid;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+@EqualsAndHashCode
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class ConditionApiProperties {
+    @JsonProperty("conditionName")
+    private String conditionName = "";
+
+    @JsonProperty("conditionParameters")
+    @Valid
+    private List<Map<String, String>> conditionParameters = Collections.emptyList();
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy
new file mode 100644 (file)
index 0000000..a1ad9af
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ *  ============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.ncmp.api.impl
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService
+import org.onap.cps.spi.CpsAdminPersistenceService
+import org.onap.cps.spi.CpsDataPersistenceService
+import org.onap.cps.spi.model.Anchor
+import org.onap.cps.spi.model.CmHandleQueryParameters
+import org.onap.cps.spi.model.ConditionProperties
+import org.onap.cps.spi.model.DataNode
+import org.onap.cps.utils.JsonObjectMapper
+import spock.lang.Specification
+
+import java.util.stream.Collectors
+
+class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification {
+
+    def cpsDataPersistenceService = Mock(CpsDataPersistenceService)
+    def cpsAdminPersistenceService = Mock(CpsAdminPersistenceService)
+
+    NetworkCmProxyCmHandlerQueryService objectUnderTest = new NetworkCmProxyCmHandlerQueryServiceImpl(
+        cpsDataPersistenceService, cpsAdminPersistenceService, new JsonObjectMapper(new ObjectMapper())
+    )
+
+    def 'Retrieve cm handles with public properties when #scenario.'() {
+        given: 'a condition property'
+            def cmHandleQueryParameters = new CmHandleQueryParameters()
+            def conditionProperties = new ConditionProperties()
+            conditionProperties.conditionName = 'hasAllProperties'
+            conditionProperties.conditionParameters = publicProperties
+            cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties])
+        and: 'mock services'
+            mockResponses()
+        when: 'the service is invoked'
+            def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
+        then: 'the correct expected cm handles are returned'
+            returnedCmHandles.stream().map(d -> d.leaves.get('id').toString()).collect(Collectors.toList()) == expectedCmHandleIds
+        where: 'the following data is used'
+            scenario                                       | publicProperties                                                                                  || expectedCmHandleIds
+            'single matching property'                     | [['Contact' : 'newemailforstore@bookstore.com']]                                                  || ['PNFDemo', 'PNFDemo2', 'PNFDemo4']
+            'public property dont match'                   | [['wont_match' : 'wont_match']]                                                                   || []
+            '2 properties, only one match (and)'           | [['Contact' : 'newemailforstore@bookstore.com'], ['Contact2': 'newemailforstore2@bookstore.com']] || ['PNFDemo4']
+            '2 properties, no match (and)'                 | [['Contact' : 'newemailforstore@bookstore.com'], ['Contact2': '']]                                || []
+    }
+
+    def 'Retrieve cm handles with module names when #scenario.'() {
+        given: 'a condition property'
+            def cmHandleQueryParameters = new CmHandleQueryParameters()
+            def conditionProperties = new ConditionProperties()
+            conditionProperties.conditionName = 'hasAllModules'
+            conditionProperties.conditionParameters = moduleNames
+            cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties])
+        and: 'mock services'
+            mockResponses()
+        when: 'the service is invoked'
+            def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
+        then: 'the correct expected cm handles are returned'
+            returnedCmHandles.stream().map(d -> d.leaves.get('id').toString()).collect(Collectors.toList()) == expectedCmHandleIds
+        where: 'the following data is used'
+            scenario                               | moduleNames                                                             || expectedCmHandleIds
+            'single matching module name'          | [['moduleName' : 'MODULE-NAME-001']]                                    || ['PNFDemo2', 'PNFDemo3', 'PNFDemo']
+            'module name dont match'               | [['moduleName' : 'MODULE-NAME-004']]                                    || []
+            '2 module names, only one match (and)' | [['moduleName' : 'MODULE-NAME-002'], ['moduleName': 'MODULE-NAME-003']] || ['PNFDemo4']
+            '2 module names, no match (and)'       | [['moduleName' : 'MODULE-NAME-002'], ['moduleName': 'MODULE-NAME-004']] || []
+    }
+
+    def 'Retrieve cm handles with combined queries when #scenario.'() {
+        given: 'condition properties'
+            def cmHandleQueryParameters = new CmHandleQueryParameters()
+            def conditionProperties1 = new ConditionProperties()
+            conditionProperties1.conditionName = 'hasAllProperties'
+            conditionProperties1.conditionParameters = publicProperties
+            def conditionProperties2 = new ConditionProperties()
+            conditionProperties2.conditionName = 'hasAllModules'
+            conditionProperties2.conditionParameters = moduleNames
+            cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties1,conditionProperties2])
+        and: 'mock services'
+            mockResponses()
+        when: 'the service is invoked'
+            def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
+        then: 'the correct expected cm handles are returned'
+            returnedCmHandles.stream().map(d -> d.leaves.get('id').toString()).collect(Collectors.toList()) == expectedCmHandleIds
+        where: 'the following data is used'
+            scenario                 | moduleNames                          | publicProperties                                   || expectedCmHandleIds
+            'particularly intersect' | [['moduleName' : 'MODULE-NAME-001']] | [['Contact' : 'newemailforstore@bookstore.com']]   || ['PNFDemo2', 'PNFDemo']
+            'empty intersect'        | [['moduleName' : 'MODULE-NAME-004']] | [['Contact' : 'newemailforstore@bookstore.com']]   || []
+            'total intersect'        | [['moduleName' : 'MODULE-NAME-002']] | [['Contact2' : 'newemailforstore2@bookstore.com']] || ['PNFDemo4']
+    }
+
+    def 'Retrieve cm handles when the query is empty.'() {
+        given: 'mock services'
+            mockResponses()
+        when: 'the service is invoked'
+            def cmHandleQueryParameters = new CmHandleQueryParameters()
+            def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
+        then: 'the correct expected cm handles are returned'
+            returnedCmHandles.stream().map(d -> d.leaves.get('id').toString()).collect(Collectors.toList()) == ['PNFDemo', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4']
+    }
+
+    void mockResponses() {
+        def pNFDemo = new DataNode(xpath: 'cmHandle/id[\'PNFDemo\']', leaves: ['id':'PNFDemo'])
+        def pNFDemo2 = new DataNode(xpath: 'cmHandle/id[\'PNFDemo2\']', leaves: ['id':'PNFDemo2'])
+        def pNFDemo3 = new DataNode(xpath: 'cmHandle/id[\'PNFDemo3\']', leaves: ['id':'PNFDemo3'])
+        def pNFDemo4 = new DataNode(xpath: 'cmHandle/id[\'PNFDemo4\']', leaves: ['id':'PNFDemo4'])
+
+        cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\'Contact\' and @value=\'newemailforstore@bookstore.com\']/ancestor::cm-handles', _)
+                >> [pNFDemo, pNFDemo2, pNFDemo4]
+        cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\'wont_match\' and @value=\'wont_match\']/ancestor::cm-handles', _)
+                >> []
+        cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\'Contact2\' and @value=\'newemailforstore2@bookstore.com\']/ancestor::cm-handles', _)
+                >> [pNFDemo4]
+        cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\'Contact2\' and @value=\'\']/ancestor::cm-handles', _)
+                >> []
+        cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties/ancestor::cm-handles', _)
+                >> [pNFDemo, pNFDemo2, pNFDemo3, pNFDemo4]
+        cpsDataPersistenceService.queryDataNodes(_, _, '//cm-handles[@id=\'PNFDemo\']', _) >> [pNFDemo]
+        cpsDataPersistenceService.queryDataNodes(_, _, '//cm-handles[@id=\'PNFDemo2\']', _) >> [pNFDemo2]
+        cpsDataPersistenceService.queryDataNodes(_, _, '//cm-handles[@id=\'PNFDemo3\']', _) >> [pNFDemo3]
+        cpsDataPersistenceService.queryDataNodes(_, _, '//cm-handles[@id=\'PNFDemo4\']', _) >> [pNFDemo4]
+
+        cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-001']) >> [new Anchor(name: 'PNFDemo2'), new Anchor(name: 'PNFDemo3'), new Anchor(name: 'PNFDemo')]
+        cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-004']) >> []
+        cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-003', 'MODULE-NAME-002']) >> [new Anchor(name: 'PNFDemo4')]
+        cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-002', 'MODULE-NAME-003']) >> [new Anchor(name: 'PNFDemo4')]
+        cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-004', 'MODULE-NAME-002']) >> []
+        cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-002', 'MODULE-NAME-004']) >> []
+        cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-002']) >> [new Anchor(name: 'PNFDemo2'), new Anchor(name: 'PNFDemo4')]
+    }
+}
index f56aea7..6fbc4eb 100644 (file)
@@ -22,6 +22,7 @@
 package org.onap.cps.ncmp.api.impl
 
 import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
 import org.onap.cps.api.CpsAdminService
 import org.onap.cps.api.CpsDataService
@@ -64,6 +65,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
     def mockNetworkCmProxyDataServicePropertyHandler = Mock(NetworkCmProxyDataServicePropertyHandler)
     def mockInventoryPersistence = Mock(InventoryPersistence)
     def mockModuleSyncService = Mock(ModuleSyncService)
+    def stubbedNetworkCmProxyCmHandlerQueryService = Stub(NetworkCmProxyCmHandlerQueryService)
 
     def noTimestamp = null
     def objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
@@ -387,6 +389,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
 
     def getObjectUnderTest() {
         return Spy(new NetworkCmProxyDataServiceImpl(mockCpsDataService, spiedJsonObjectMapper, mockDmiDataOperations,
-            mockCpsModuleService, mockCpsAdminService, mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockModuleSyncService))
+            mockCpsModuleService, mockCpsAdminService, mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence,
+            mockModuleSyncService, stubbedNetworkCmProxyCmHandlerQueryService))
     }
 }
index 55a1a8d..cc183a3 100644 (file)
 
 package org.onap.cps.ncmp.api.impl
 
-import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException
+import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
 import org.onap.cps.ncmp.api.inventory.CmHandleState
 import org.onap.cps.ncmp.api.inventory.CompositeState
 import org.onap.cps.ncmp.api.inventory.InventoryPersistence
+import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters
+import org.onap.cps.ncmp.api.models.ConditionApiProperties
 import org.onap.cps.ncmp.api.models.DmiPluginRegistration
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
 import org.onap.cps.spi.exceptions.DataValidationException
 import org.onap.cps.ncmp.api.inventory.sync.ModuleSyncService
+import org.onap.cps.spi.model.CmHandleQueryParameters
+import org.onap.cps.spi.model.ConditionProperties
 import spock.lang.Shared
 
 import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_OPERATIONAL
@@ -61,6 +65,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
     def mockInventoryPersistence = Mock(InventoryPersistence)
     def mockModuleSyncService = Mock(ModuleSyncService)
     def mockDmiPluginRegistration = Mock(DmiPluginRegistration)
+    def mockCpsCmHandlerQueryService = Mock(NetworkCmProxyCmHandlerQueryService)
 
     def NO_TOPIC = null
     def NO_REQUEST_ID = null
@@ -70,7 +75,8 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
     def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id')
 
     def objectUnderTest = new NetworkCmProxyDataServiceImpl(mockCpsDataService, spiedJsonObjectMapper, mockDmiDataOperations,
-        mockCpsModuleService, mockCpsAdminService, nullNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockModuleSyncService)
+        mockCpsModuleService, mockCpsAdminService, nullNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence,
+        mockModuleSyncService, mockCpsCmHandlerQueryService)
 
     def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']"
 
@@ -160,13 +166,6 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
             0 * mockCpsModuleService.getYangResourcesModuleReferences(*_)
     }
 
-    def 'Get cm handle identifiers for the given module names.'() {
-        when: 'execute a cm handle search for the given module names'
-            objectUnderTest.executeCmHandleHasAllModulesSearch(['some-module-name'])
-        then: 'get anchor identifiers is invoked  with the expected parameters'
-            1 * mockCpsAdminService.queryAnchorNames('NFP-Operational', ['some-module-name'])
-    }
-
     def 'Get a cm handle.'() {
         given: 'the system returns a yang modelled cm handle'
             def dmiServiceName = 'some service name'
@@ -245,4 +244,25 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
             1 * mockCpsAdminService.createAnchor('NFP-Operational', null,
                 'some-cm-handle-id')
     }
+
+    def 'Execute cm handle id search'(){
+        given: 'valid CmHandleQueryApiParameters input'
+            def cmHandleQueryApiParameters = new CmHandleQueryApiParameters()
+            def conditionApiProperties = new ConditionApiProperties()
+            conditionApiProperties.conditionName = 'hasAllModules'
+            conditionApiProperties.conditionParameters = [[moduleName:'module-name-1']]
+            cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties]
+        and: 'valid CmHandleQueryParameters input'
+            def cmHandleQueryParameters = new CmHandleQueryParameters()
+            def conditionProperties = new ConditionProperties()
+            conditionProperties.conditionName = 'hasAllModules'
+            conditionProperties.conditionParameters = [[moduleName:'module-name-1']]
+            cmHandleQueryParameters.cmHandleQueryParameters = [conditionProperties]
+        and: 'query cm handle method return with a data node list'
+            mockCpsCmHandlerQueryService.queryCmHandles(cmHandleQueryParameters) >> [ new DataNode(leaves: [id:'cm-handle-id-1'] )]
+        when: 'execute cm handle search is called'
+            def result = objectUnderTest.executeCmHandleIdSearch(cmHandleQueryApiParameters)
+        then: 'result is the same collection as returned by the CPS Data Service'
+            assert result == ['cm-handle-id-1'] as Set
+    }
 }
index 2e7bb7e..047ec99 100755 (executable)
@@ -24,10 +24,9 @@ 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;
-import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
 import org.onap.cps.spi.CpsAdminPersistenceService;
 import org.onap.cps.spi.entities.AnchorEntity;
 import org.onap.cps.spi.entities.DataspaceEntity;
@@ -37,24 +36,21 @@ import org.onap.cps.spi.exceptions.AlreadyDefinedException;
 import org.onap.cps.spi.exceptions.DataspaceInUseException;
 import org.onap.cps.spi.exceptions.ModuleNamesNotFoundException;
 import org.onap.cps.spi.model.Anchor;
-import org.onap.cps.spi.model.CmHandleQueryParameters;
 import org.onap.cps.spi.repository.AnchorRepository;
 import org.onap.cps.spi.repository.DataspaceRepository;
-import org.onap.cps.spi.repository.ModuleReferenceRepository;
 import org.onap.cps.spi.repository.SchemaSetRepository;
 import org.onap.cps.spi.repository.YangResourceRepository;
 import org.springframework.dao.DataIntegrityViolationException;
 import org.springframework.stereotype.Component;
 
 @Component
-@AllArgsConstructor
+@RequiredArgsConstructor
 public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceService {
 
     private final DataspaceRepository dataspaceRepository;
     private final AnchorRepository anchorRepository;
     private final SchemaSetRepository schemaSetRepository;
     private final YangResourceRepository yangResourceRepository;
-    private final ModuleReferenceRepository moduleReferenceRepository;
 
     @Override
     public void createDataspace(final String dataspaceName) {
@@ -136,11 +132,6 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
         anchorRepository.delete(anchorEntity);
     }
 
-    @Override
-    public Set<String> queryCmHandles(final CmHandleQueryParameters cmHandleQueryParameters) {
-        return moduleReferenceRepository.queryCmHandles(cmHandleQueryParameters);
-    }
-
     private AnchorEntity getAnchorEntity(final String dataspaceName, final String anchorName) {
         final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
         return anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
index 4dbbfd2..117cb43 100644 (file)
@@ -89,33 +89,33 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     @Override
     @Transactional
     public void addChildDataNode(final String dataspaceName, final String anchorName, final String parentNodeXpath,
-        final DataNode newChildDataNode) {
-        addChildDataNodes(dataspaceName, anchorName, parentNodeXpath,  Collections.singleton(newChildDataNode));
+                                 final DataNode newChildDataNode) {
+        addChildDataNodes(dataspaceName, anchorName, parentNodeXpath, Collections.singleton(newChildDataNode));
     }
 
     @Override
     @Transactional
     public void addListElements(final String dataspaceName, final String anchorName, final String parentNodeXpath,
-        final Collection<DataNode> newListElements) {
+                                final Collection<DataNode> newListElements) {
         addChildDataNodes(dataspaceName, anchorName, parentNodeXpath, newListElements);
     }
 
     private void addChildDataNodes(final String dataspaceName, final String anchorName, final String parentNodeXpath,
-                                final Collection<DataNode> newChildren) {
+                                   final Collection<DataNode> newChildren) {
         final FragmentEntity parentFragmentEntity = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath);
         try {
             for (final DataNode newChildAsDataNode : newChildren) {
                 final FragmentEntity newChildAsFragmentEntity = convertToFragmentWithAllDescendants(
-                    parentFragmentEntity.getDataspace(),
-                    parentFragmentEntity.getAnchor(),
-                    newChildAsDataNode);
+                        parentFragmentEntity.getDataspace(),
+                        parentFragmentEntity.getAnchor(),
+                        newChildAsDataNode);
                 newChildAsFragmentEntity.setParentId(parentFragmentEntity.getId());
                 fragmentRepository.save(newChildAsFragmentEntity);
             }
         } catch (final DataIntegrityViolationException exception) {
             final List<String> conflictXpaths = newChildren.stream()
-                .map(DataNode::getXpath)
-                .collect(Collectors.toList());
+                    .map(DataNode::getXpath)
+                    .collect(Collectors.toList());
             throw AlreadyDefinedException.forDataNodes(conflictXpaths, anchorName, exception);
         }
     }
@@ -125,7 +125,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
         final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
         final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
         final FragmentEntity fragmentEntity = convertToFragmentWithAllDescendants(dataspaceEntity, anchorEntity,
-            dataNode);
+                dataNode);
         try {
             fragmentRepository.save(fragmentEntity);
         } catch (final DataIntegrityViolationException exception) {
@@ -143,13 +143,13 @@ 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()) {
             final FragmentEntity childFragment =
-                convertToFragmentWithAllDescendants(parentFragment.getDataspace(), parentFragment.getAnchor(),
-                    childDataNode);
+                    convertToFragmentWithAllDescendants(parentFragment.getDataspace(), parentFragment.getAnchor(),
+                            childDataNode);
             childFragmentsImmutableSetBuilder.add(childFragment);
         }
         parentFragment.setChildFragments(childFragmentsImmutableSetBuilder.build());
@@ -157,24 +157,24 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     }
 
     private FragmentEntity toFragmentEntity(final DataspaceEntity dataspaceEntity,
-        final AnchorEntity anchorEntity, final DataNode dataNode) {
+                                            final AnchorEntity anchorEntity, final DataNode dataNode) {
         return FragmentEntity.builder()
-            .dataspace(dataspaceEntity)
-            .anchor(anchorEntity)
-            .xpath(dataNode.getXpath())
-            .attributes(jsonObjectMapper.asJsonString(dataNode.getLeaves()))
-            .build();
+                .dataspace(dataspaceEntity)
+                .anchor(anchorEntity)
+                .xpath(dataNode.getXpath())
+                .attributes(jsonObjectMapper.asJsonString(dataNode.getLeaves()))
+                .build();
     }
 
     @Override
     public DataNode getDataNode(final String dataspaceName, final String anchorName, final String xpath,
-        final FetchDescendantsOption fetchDescendantsOption) {
+                                final FetchDescendantsOption fetchDescendantsOption) {
         final FragmentEntity fragmentEntity = getFragmentByXpath(dataspaceName, anchorName, xpath);
         return toDataNode(fragmentEntity, fetchDescendantsOption);
     }
 
     private FragmentEntity getFragmentByXpath(final String dataspaceName, final String anchorName,
-        final String xpath) {
+                                              final String xpath) {
         final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
         final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
         if (isRootXpath(xpath)) {
@@ -193,7 +193,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
 
     @Override
     public List<DataNode> queryDataNodes(final String dataspaceName, final String anchorName, final String cpsPath,
-        final FetchDescendantsOption fetchDescendantsOption) {
+                                         final FetchDescendantsOption fetchDescendantsOption) {
         final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
         final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
         final CpsPathQuery cpsPathQuery;
@@ -203,15 +203,15 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
             throw new CpsPathException(e.getMessage());
         }
         List<FragmentEntity> fragmentEntities =
-            fragmentRepository.findByAnchorAndCpsPath(anchorEntity.getId(), cpsPathQuery);
+                fragmentRepository.findByAnchorAndCpsPath(anchorEntity.getId(), cpsPathQuery);
         if (cpsPathQuery.hasAncestorAxis()) {
             final Set<String> ancestorXpaths = processAncestorXpath(fragmentEntities, cpsPathQuery);
-            fragmentEntities = ancestorXpaths.isEmpty()
-                ? Collections.emptyList() : fragmentRepository.findAllByAnchorAndXpathIn(anchorEntity, ancestorXpaths);
+            fragmentEntities = ancestorXpaths.isEmpty() ? Collections.emptyList()
+                    : fragmentRepository.findAllByAnchorAndXpathIn(anchorEntity, ancestorXpaths);
         }
         return fragmentEntities.stream()
-            .map(fragmentEntity -> toDataNode(fragmentEntity, fetchDescendantsOption))
-            .collect(Collectors.toUnmodifiableList());
+                .map(fragmentEntity -> toDataNode(fragmentEntity, fetchDescendantsOption))
+                .collect(Collectors.toUnmodifiableList());
     }
 
     @Override
@@ -226,16 +226,16 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
 
     @Override
     public void lockAnchor(final String sessionId, final String dataspaceName,
-                            final String anchorName, final Long timeoutInMilliseconds) {
+                           final String anchorName, final Long timeoutInMilliseconds) {
         sessionManager.lockAnchor(sessionId, dataspaceName, anchorName, timeoutInMilliseconds);
     }
 
     private static Set<String> processAncestorXpath(final List<FragmentEntity> fragmentEntities,
-        final CpsPathQuery cpsPathQuery) {
+                                                    final CpsPathQuery cpsPathQuery) {
         final Set<String> ancestorXpath = new HashSet<>();
         final Pattern pattern =
-            Pattern.compile("([\\s\\S]*\\/" + Pattern.quote(cpsPathQuery.getAncestorSchemaNodeIdentifier())
-                + REG_EX_FOR_OPTIONAL_LIST_INDEX + "\\/[\\s\\S]*");
+                Pattern.compile("([\\s\\S]*\\/" + Pattern.quote(cpsPathQuery.getAncestorSchemaNodeIdentifier())
+                        + REG_EX_FOR_OPTIONAL_LIST_INDEX + "\\/[\\s\\S]*");
         for (final FragmentEntity fragmentEntity : fragmentEntities) {
             final Matcher matcher = pattern.matcher(fragmentEntity.getXpath());
             if (matcher.matches()) {
@@ -270,18 +270,18 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     }
 
     private List<DataNode> getChildDataNodes(final FragmentEntity fragmentEntity,
-        final FetchDescendantsOption fetchDescendantsOption) {
+                                             final FetchDescendantsOption fetchDescendantsOption) {
         if (fetchDescendantsOption == INCLUDE_ALL_DESCENDANTS) {
             return fragmentEntity.getChildFragments().stream()
-                .map(childFragmentEntity -> toDataNode(childFragmentEntity, fetchDescendantsOption))
-                .collect(Collectors.toUnmodifiableList());
+                    .map(childFragmentEntity -> toDataNode(childFragmentEntity, fetchDescendantsOption))
+                    .collect(Collectors.toUnmodifiableList());
         }
         return Collections.emptyList();
     }
 
     @Override
     public void updateDataLeaves(final String dataspaceName, final String anchorName, final String xpath,
-        final Map<String, Object> leaves) {
+                                 final Map<String, Object> leaves) {
         final FragmentEntity fragmentEntity = getFragmentByXpath(dataspaceName, anchorName, xpath);
         fragmentEntity.setAttributes(jsonObjectMapper.asJsonString(leaves));
         fragmentRepository.save(fragmentEntity);
@@ -295,19 +295,19 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
             fragmentRepository.save(fragmentEntity);
         } catch (final StaleStateException staleStateException) {
             throw new ConcurrencyException("Concurrent Transactions",
-                String.format("dataspace :'%s', Anchor : '%s' and xpath: '%s' is updated by another transaction.",
-                    dataspaceName, anchorName, dataNode.getXpath()),
-                staleStateException);
+                    String.format("dataspace :'%s', Anchor : '%s' and xpath: '%s' is updated by another transaction.",
+                            dataspaceName, anchorName, dataNode.getXpath()),
+                    staleStateException);
         }
     }
 
     private void replaceDataNodeTree(final FragmentEntity existingFragmentEntity,
-                                            final DataNode newDataNode) {
+                                     final DataNode newDataNode) {
 
         existingFragmentEntity.setAttributes(jsonObjectMapper.asJsonString(newDataNode.getLeaves()));
 
-        final Map<String, FragmentEntity> existingChildrenByXpath = existingFragmentEntity.getChildFragments()
-            .stream().collect(Collectors.toMap(FragmentEntity::getXpath, childFragmentEntity -> childFragmentEntity));
+        final Map<String, FragmentEntity> existingChildrenByXpath = existingFragmentEntity.getChildFragments().stream()
+                .collect(Collectors.toMap(FragmentEntity::getXpath, childFragmentEntity -> childFragmentEntity));
 
         final Collection<FragmentEntity> updatedChildFragments = new HashSet<>();
 
@@ -315,7 +315,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
             final FragmentEntity childFragment;
             if (isNewDataNode(newDataNodeChild, existingChildrenByXpath)) {
                 childFragment = convertToFragmentWithAllDescendants(
-                    existingFragmentEntity.getDataspace(), existingFragmentEntity.getAnchor(), newDataNodeChild);
+                        existingFragmentEntity.getDataspace(), existingFragmentEntity.getAnchor(), newDataNodeChild);
             } else {
                 childFragment = existingChildrenByXpath.get(newDataNodeChild.getXpath());
                 replaceDataNodeTree(childFragment, newDataNodeChild);
@@ -333,14 +333,14 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
         final FragmentEntity parentEntity = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath);
         final String listElementXpathPrefix = getListElementXpathPrefix(newListElements);
         final Map<String, FragmentEntity> existingListElementFragmentEntitiesByXPath =
-            extractListElementFragmentEntitiesByXPath(parentEntity.getChildFragments(), listElementXpathPrefix);
+                extractListElementFragmentEntitiesByXPath(parentEntity.getChildFragments(), listElementXpathPrefix);
         deleteListElements(parentEntity.getChildFragments(), existingListElementFragmentEntitiesByXPath);
         final Set<FragmentEntity> updatedChildFragmentEntities = new HashSet<>();
         for (final DataNode newListElement : newListElements) {
             final FragmentEntity existingListElementEntity =
-                existingListElementFragmentEntitiesByXPath.get(newListElement.getXpath());
+                    existingListElementFragmentEntitiesByXPath.get(newListElement.getXpath());
             final FragmentEntity entityToBeAdded = getFragmentForReplacement(parentEntity, newListElement,
-                existingListElementEntity);
+                    existingListElementEntity);
 
             updatedChildFragmentEntities.add(entityToBeAdded);
         }
@@ -353,8 +353,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     public void deleteDataNodes(final String dataspaceName, final String anchorName) {
         final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
         anchorRepository.findByDataspaceAndName(dataspaceEntity, anchorName)
-            .ifPresent(
-                anchorEntity -> fragmentRepository.deleteByAnchorIn(Set.of(anchorEntity)));
+                .ifPresent(
+                        anchorEntity -> fragmentRepository.deleteByAnchorIn(Set.of(anchorEntity)));
     }
 
     @Override
@@ -371,7 +371,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     }
 
     private void deleteDataNode(final String dataspaceName, final String anchorName, final String targetXpath,
-        final boolean onlySupportListNodeDeletion) {
+                                final boolean onlySupportListNodeDeletion) {
         final String parentNodeXpath;
         FragmentEntity parentFragmentEntity = null;
         boolean targetDeleted = false;
@@ -387,7 +387,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
             parentFragmentEntity = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath);
             final String lastXpathElement = targetXpath.substring(targetXpath.lastIndexOf('/'));
             final boolean isListElement = REG_EX_PATTERN_FOR_LIST_ELEMENT_KEY_PREDICATE
-                .matcher(lastXpathElement).find();
+                    .matcher(lastXpathElement).find();
             if (isListElement) {
                 targetDeleted = deleteDataNode(parentFragmentEntity, targetXpath);
             } else {
@@ -400,9 +400,9 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
         }
         if (!targetDeleted) {
             final String additionalInformation = onlySupportListNodeDeletion
-                ? "The target is probably not a List." : "";
+                    ? "The target is probably not a List." : "";
             throw new DataNodeNotFoundException(parentFragmentEntity.getDataspace().getName(),
-                parentFragmentEntity.getAnchor().getName(), targetXpath, additionalInformation);
+                    parentFragmentEntity.getAnchor().getName(), targetXpath, additionalInformation);
         }
     }
 
@@ -413,7 +413,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
             return true;
         }
         if (parentFragmentEntity.getChildFragments()
-            .removeIf(fragment -> fragment.getXpath().equals(normalizedTargetXpath))) {
+                .removeIf(fragment -> fragment.getXpath().equals(normalizedTargetXpath))) {
             fragmentRepository.save(parentFragmentEntity);
             return true;
         }
@@ -424,7 +424,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
         final String normalizedListXpath = CpsPathUtil.getNormalizedXpath(listXpath);
         final String deleteTargetXpathPrefix = normalizedListXpath + "[";
         if (parentFragmentEntity.getChildFragments()
-            .removeIf(fragment -> fragment.getXpath().startsWith(deleteTargetXpathPrefix))) {
+                .removeIf(fragment -> fragment.getXpath().startsWith(deleteTargetXpathPrefix))) {
             fragmentRepository.save(parentFragmentEntity);
             return true;
         }
@@ -432,26 +432,26 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     }
 
     private static void deleteListElements(
-        final Collection<FragmentEntity> fragmentEntities,
-        final Map<String, FragmentEntity> existingListElementFragmentEntitiesByXPath) {
+            final Collection<FragmentEntity> fragmentEntities,
+            final Map<String, FragmentEntity> existingListElementFragmentEntitiesByXPath) {
         fragmentEntities.removeAll(existingListElementFragmentEntitiesByXPath.values());
     }
 
     private static String getListElementXpathPrefix(final Collection<DataNode> newListElements) {
         if (newListElements.isEmpty()) {
             throw new CpsAdminException("Invalid list replacement",
-                "Cannot replace list elements with empty collection");
+                    "Cannot replace list elements with empty collection");
         }
         final String firstChildNodeXpath = newListElements.iterator().next().getXpath();
         return firstChildNodeXpath.substring(0, firstChildNodeXpath.lastIndexOf('[') + 1);
     }
 
     private FragmentEntity getFragmentForReplacement(final FragmentEntity parentEntity,
-                                                            final DataNode newListElement,
-                                                            final FragmentEntity existingListElementEntity) {
+                                                     final DataNode newListElement,
+                                                     final FragmentEntity existingListElementEntity) {
         if (existingListElementEntity == null) {
             return convertToFragmentWithAllDescendants(
-                parentEntity.getDataspace(), parentEntity.getAnchor(), newListElement);
+                    parentEntity.getDataspace(), parentEntity.getAnchor(), newListElement);
         }
         if (newListElement.getChildDataNodes().isEmpty()) {
             copyAttributesFromNewListElement(existingListElementEntity, newListElement);
@@ -472,7 +472,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     }
 
     private void copyAttributesFromNewListElement(final FragmentEntity existingListElementEntity,
-                                                         final DataNode newListElement) {
+                                                  final DataNode newListElement) {
         final FragmentEntity replacementFragmentEntity =
                 FragmentEntity.builder().attributes(jsonObjectMapper.asJsonString(
                         newListElement.getLeaves())).build();
@@ -480,10 +480,10 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     }
 
     private static Map<String, FragmentEntity> extractListElementFragmentEntitiesByXPath(
-        final Set<FragmentEntity> childEntities, final String listElementXpathPrefix) {
+            final Set<FragmentEntity> childEntities, final String listElementXpathPrefix) {
         return childEntities.stream()
-            .filter(fragmentEntity -> fragmentEntity.getXpath().startsWith(listElementXpathPrefix))
-            .collect(Collectors.toMap(FragmentEntity::getXpath, fragmentEntity -> fragmentEntity));
+                .filter(fragmentEntity -> fragmentEntity.getXpath().startsWith(listElementXpathPrefix))
+                .collect(Collectors.toMap(FragmentEntity::getXpath, fragmentEntity -> fragmentEntity));
     }
 
     private static boolean isRootXpath(final String xpath) {
index 4bc9dd9..5e4de7f 100644 (file)
@@ -21,8 +21,6 @@
 package org.onap.cps.spi.repository;
 
 import java.util.Collection;
-import java.util.Set;
-import org.onap.cps.spi.model.CmHandleQueryParameters;
 import org.onap.cps.spi.model.ModuleReference;
 
 /**
@@ -32,13 +30,4 @@ public interface ModuleReferenceQuery {
 
     Collection<ModuleReference> identifyNewModuleReferences(
         final Collection<ModuleReference> moduleReferencesToCheck);
-
-    /**
-     * Query and return cm handles that match the given query parameters.
-     *
-     * @param cmHandleQueryParameters the cm handle query parameters
-     * @return collection of cm handle ids
-     */
-    Set<String> queryCmHandles(CmHandleQueryParameters cmHandleQueryParameters);
-
 }
index f85dea3..681bbcd 100644 (file)
@@ -24,19 +24,12 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
 import java.util.UUID;
-import java.util.stream.Collectors;
 import javax.persistence.EntityManager;
 import javax.persistence.PersistenceContext;
 import lombok.AllArgsConstructor;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.spi.CpsDataPersistenceService;
-import org.onap.cps.spi.FetchDescendantsOption;
-import org.onap.cps.spi.model.CmHandleQueryParameters;
-import org.onap.cps.spi.model.DataNode;
 import org.onap.cps.spi.model.ModuleReference;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -48,19 +41,17 @@ public class ModuleReferenceRepositoryImpl implements ModuleReferenceQuery {
     @PersistenceContext
     private EntityManager entityManager;
 
-    private final CpsDataPersistenceService cpsDataPersistenceService;
-
     @Override
     @SneakyThrows
     public Collection<ModuleReference> identifyNewModuleReferences(
-        final Collection<ModuleReference> moduleReferencesToCheck) {
+            final Collection<ModuleReference> moduleReferencesToCheck) {
 
         if (moduleReferencesToCheck == null || moduleReferencesToCheck.isEmpty()) {
             return Collections.emptyList();
         }
 
         final String tempTableName = "moduleReferencesToCheckTemp"
-            + UUID.randomUUID().toString().replace("-", "");
+                + UUID.randomUUID().toString().replace("-", "");
 
         createTemporaryTable(tempTableName);
         insertDataIntoTable(tempTableName, moduleReferencesToCheck);
@@ -68,56 +59,6 @@ public class ModuleReferenceRepositoryImpl implements ModuleReferenceQuery {
         return identifyNewModuleReferencesForCmHandle(tempTableName);
     }
 
-    /**
-     * Query and return cm handles that match the given query parameters.
-     *
-     * @param cmHandleQueryParameters the cm handle query parameters
-     * @return collection of cm handle ids
-     */
-    @Override
-    public Set<String> queryCmHandles(final CmHandleQueryParameters cmHandleQueryParameters) {
-
-        if (cmHandleQueryParameters.getPublicProperties().entrySet().isEmpty()) {
-            return getAllCmHandles();
-        }
-
-        final Collection<DataNode> amalgamatedQueryResult = new ArrayList<>();
-        int queryConditionCounter = 0;
-        for (final Map.Entry<String, String> entry : cmHandleQueryParameters.getPublicProperties().entrySet()) {
-            final StringBuilder cmHandlePath = new StringBuilder();
-            cmHandlePath.append("//public-properties[@name='").append(entry.getKey()).append("' ");
-            cmHandlePath.append("and @value='").append(entry.getValue()).append("']");
-            cmHandlePath.append("/ancestor::cm-handles");
-
-            final Collection<DataNode> singleConditionQueryResult =
-                cpsDataPersistenceService.queryDataNodes("NCMP-Admin",
-                "ncmp-dmi-registry", String.valueOf(cmHandlePath), FetchDescendantsOption.OMIT_DESCENDANTS);
-            if (++queryConditionCounter == 1) {
-                amalgamatedQueryResult.addAll(singleConditionQueryResult);
-            } else {
-                amalgamatedQueryResult.retainAll(singleConditionQueryResult);
-            }
-
-            if (amalgamatedQueryResult.isEmpty()) {
-                break;
-            }
-        }
-
-        return extractCmHandleIds(amalgamatedQueryResult);
-    }
-
-    private Set<String> getAllCmHandles() {
-        final Collection<DataNode> cmHandles = cpsDataPersistenceService.queryDataNodes("NCMP-Admin",
-            "ncmp-dmi-registry", "//public-properties/ancestor::cm-handles",
-            FetchDescendantsOption.OMIT_DESCENDANTS);
-        return extractCmHandleIds(cmHandles);
-    }
-
-    private Set<String> extractCmHandleIds(final Collection<DataNode> cmHandles) {
-        return cmHandles.stream().map(cmHandle -> cmHandle.getLeaves().get("id").toString())
-            .collect(Collectors.toSet());
-    }
-
     private void createTemporaryTable(final String tempTableName) {
         final StringBuilder sqlStringBuilder = new StringBuilder("CREATE TEMPORARY TABLE " + tempTableName + "(");
         sqlStringBuilder.append(" id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,");
@@ -149,11 +90,11 @@ public class ModuleReferenceRepositoryImpl implements ModuleReferenceQuery {
 
     private Collection<ModuleReference> identifyNewModuleReferencesForCmHandle(final String tempTableName) {
         final String sql = String.format(
-            "SELECT %1$s.module_name, %1$s.revision"
-                + " FROM %1$s LEFT JOIN yang_resource"
-                + " ON yang_resource.module_name=%1$s.module_name"
-                + " AND yang_resource.revision=%1$s.revision"
-                + " WHERE yang_resource.module_name IS NULL;", tempTableName);
+                "SELECT %1$s.module_name, %1$s.revision"
+                        + " FROM %1$s LEFT JOIN yang_resource"
+                        + " ON yang_resource.module_name=%1$s.module_name"
+                        + " AND yang_resource.revision=%1$s.revision"
+                        + " WHERE yang_resource.module_name IS NULL;", tempTableName);
 
         @SuppressWarnings("unchecked")
         final List<Object[]> resultsAsObjects = entityManager.createNativeQuery(sql).getResultList();
index 2de087f..ee478b8 100644 (file)
@@ -31,7 +31,6 @@ 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.onap.cps.spi.model.CmHandleQueryParameters
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.test.context.jdbc.Sql
 import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper
@@ -45,7 +44,6 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase {
     ObjectMapper objectMapper
 
     static final String SET_DATA = '/data/anchor.sql'
-    static final String SET_FRAGMENT_DATA = '/data/fragment.sql'
     static final String SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES = '/data/anchors-schemaset-modules.sql'
     static final String DATASPACE_WITH_NO_DATA = 'DATASPACE-002-NO-DATA'
     static final Integer DELETED_ANCHOR_ID = 3002
@@ -225,21 +223,4 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase {
             'dataspace contains an anchor'  | 'DATASPACE-001' || DataspaceInUseException    | 'contains 2 anchor(s)'
             'dataspace contains schemasets' | 'DATASPACE-003' || DataspaceInUseException    | 'contains 1 schemaset(s)'
     }
-
-    @Sql([CLEAR_DATA, SET_FRAGMENT_DATA])
-    def 'Retrieve cm handle ids when #scenario.'() {
-        when: 'the service is invoked'
-            def cmHandleQueryParameters = new CmHandleQueryParameters()
-            cmHandleQueryParameters.setPublicProperties(publicProperties)
-            def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
-        then: 'the correct expected cm handles are returned'
-            returnedCmHandles == expectedCmHandleIds
-        where: 'the following data is used'
-            scenario                                       | publicProperties                                                                              || expectedCmHandleIds
-            'single matching property'                     | ['Contact' : 'newemailforstore@bookstore.com']                                                || ['PNFDemo2', 'PNFDemo', 'PNFDemo4'] as Set
-            'public property dont match'                   | ['wont_match' : 'wont_match']                                                                 || [] as Set
-            '2 properties, only one match (and)'           | ['Contact' : 'newemailforstore@bookstore.com', 'Contact2': 'newemailforstore2@bookstore.com'] || ['PNFDemo4'] as Set
-            '2 properties, no match (and)'                 | ['Contact' : 'newemailforstore@bookstore.com', 'Contact2': '']                                || [] as Set
-            'No public properties - return all cm handles' | [ : ]                                                                                         || ['PNFDemo3', 'PNFDemo', 'PNFDemo2', 'PNFDemo4'] as Set
-    }
 }
index 2106f15..ab33732 100755 (executable)
 package org.onap.cps.api;
 
 import java.util.Collection;
-import java.util.Set;
 import org.onap.cps.spi.exceptions.AlreadyDefinedException;
 import org.onap.cps.spi.exceptions.CpsException;
 import org.onap.cps.spi.model.Anchor;
-import org.onap.cps.spi.model.CmHandleQueryParameters;
 
 /**
  * CPS Admin Service.
@@ -102,12 +100,4 @@ public interface CpsAdminService {
      *         given module names
      */
     Collection<String> queryAnchorNames(String dataspaceName, Collection<String> moduleNames);
-
-    /**
-     * Query and return cm handles that match the given query parameters.
-     *
-     * @param cmHandleQueryParameters the cm handle query parameters
-     * @return collection of cm handle ids
-     */
-    Set<String> queryCmHandles(CmHandleQueryParameters cmHandleQueryParameters);
 }
index 93c96ec..cde25a9 100644 (file)
@@ -210,5 +210,4 @@ public interface CpsDataService {
      * @param timeoutInMilliseconds lock attempt timeout in milliseconds
      */
     void lockAnchor(String sessionID, String dataspaceName, String anchorName, Long timeoutInMilliseconds);
-
 }
index 762754f..a67dfe5 100755 (executable)
@@ -24,20 +24,18 @@ package org.onap.cps.api.impl;
 
 import java.time.OffsetDateTime;
 import java.util.Collection;
-import java.util.Set;
 import java.util.stream.Collectors;
-import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
 import org.onap.cps.api.CpsAdminService;
 import org.onap.cps.api.CpsDataService;
 import org.onap.cps.spi.CpsAdminPersistenceService;
 import org.onap.cps.spi.model.Anchor;
-import org.onap.cps.spi.model.CmHandleQueryParameters;
 import org.onap.cps.utils.CpsValidator;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Component;
 
 @Component("CpsAdminServiceImpl")
-@AllArgsConstructor(onConstructor = @__(@Lazy))
+@RequiredArgsConstructor(onConstructor = @__(@Lazy))
 public class CpsAdminServiceImpl implements CpsAdminService {
 
     private final CpsAdminPersistenceService cpsAdminPersistenceService;
@@ -93,9 +91,4 @@ public class CpsAdminServiceImpl implements CpsAdminService {
         final Collection<Anchor> anchors = cpsAdminPersistenceService.queryAnchors(dataspaceName, moduleNames);
         return anchors.stream().map(Anchor::getName).collect(Collectors.toList());
     }
-
-    @Override
-    public Set<String> queryCmHandles(final CmHandleQueryParameters cmHandleQueryParameters) {
-        return cpsAdminPersistenceService.queryCmHandles(cmHandleQueryParameters);
-    }
 }
index 25167e8..b0d28ea 100755 (executable)
 package org.onap.cps.spi;
 
 import java.util.Collection;
-import java.util.Set;
 import org.onap.cps.spi.exceptions.AlreadyDefinedException;
 import org.onap.cps.spi.model.Anchor;
-import org.onap.cps.spi.model.CmHandleQueryParameters;
 
 /*
     Service for handling CPS admin data.
@@ -101,12 +99,4 @@ public interface CpsAdminPersistenceService {
      * @param anchorName anchor name
      */
     void deleteAnchor(String dataspaceName, String anchorName);
-
-    /**
-     * Query and return cm handles that match the given query parameters.
-     *
-     * @param cmHandleQueryParameters the cm handle query parameters
-     * @return collection of cm handle ids
-     */
-    Set<String> queryCmHandles(CmHandleQueryParameters cmHandleQueryParameters);
 }
index fd660e6..b27a297 100644 (file)
@@ -173,5 +173,4 @@ public interface CpsDataPersistenceService {
      * @param timeoutInMilliseconds lock attempt timeout in milliseconds
      */
     void lockAnchor(String sessionID, String dataspaceName, String anchorName, Long timeoutInMilliseconds);
-
 }
index ff4e627..cf364db 100644 (file)
@@ -24,18 +24,18 @@ import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import java.util.Collections;
-import java.util.Map;
+import java.util.List;
 import javax.validation.Valid;
+import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.Setter;
 
 @Setter
 @Getter
-@JsonInclude(Include.NON_NULL)
+@EqualsAndHashCode
+@JsonInclude(Include.NON_EMPTY)
 public class CmHandleQueryParameters {
-
-    @JsonProperty("publicCmHandleProperties")
+    @JsonProperty("cmHandleQueryParameters")
     @Valid
-    private Map<String, String> publicProperties = Collections.emptyMap();
-
+    private List<ConditionProperties> cmHandleQueryParameters = Collections.emptyList();
 }
diff --git a/cps-service/src/main/java/org/onap/cps/spi/model/ConditionProperties.java b/cps-service/src/main/java/org/onap/cps/spi/model/ConditionProperties.java
new file mode 100644 (file)
index 0000000..4eee7db
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *  ============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.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import javax.validation.Valid;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+@EqualsAndHashCode
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class ConditionProperties {
+    @JsonProperty("conditionName")
+    private String conditionName = "";
+
+    @JsonProperty("conditionParameters")
+    @Valid
+    private List<Map<String, String>> conditionParameters = Collections.emptyList();
+}
diff --git a/cps-service/src/main/java/org/onap/cps/spi/model/DataNodeIdentifier.java b/cps-service/src/main/java/org/onap/cps/spi/model/DataNodeIdentifier.java
new file mode 100644 (file)
index 0000000..2bd2b77
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * ============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.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+@EqualsAndHashCode
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class DataNodeIdentifier {
+    private String dataspace;
+    private String schemaSetName;
+    private String anchorName;
+    private String xpath;
+}
diff --git a/cps-service/src/main/java/org/onap/cps/utils/CmHandleQueryRestParametersValidator.java b/cps-service/src/main/java/org/onap/cps/utils/CmHandleQueryRestParametersValidator.java
new file mode 100644 (file)
index 0000000..c510a73
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *  ============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.utils;
+
+import com.google.common.base.Strings;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.onap.cps.spi.exceptions.DataValidationException;
+import org.onap.cps.spi.model.CmHandleQueryParameters;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class CmHandleQueryRestParametersValidator {
+
+    private static final List<String> VALID_PROPERTY_NAMES = Arrays.asList("hasAllProperties", "hasAllModules");
+
+    /**
+     * Validate cm handle query parameters.
+     * @param cmHandleQueryParameters name of data to be validated
+     */
+    public static void validateCmHandleQueryParameters(final CmHandleQueryParameters cmHandleQueryParameters) {
+        cmHandleQueryParameters.getCmHandleQueryParameters().forEach(
+                conditionApiProperty -> {
+                    if (Strings.isNullOrEmpty(conditionApiProperty.getConditionName())) {
+                        throwDataValidationException("Missing 'conditionName' - please supply a valid name.");
+                    }
+                    if (!VALID_PROPERTY_NAMES.contains(conditionApiProperty.getConditionName())) {
+                        throwDataValidationException(
+                                String.format("Wrong 'conditionName': %s - please supply a valid name.",
+                                conditionApiProperty.getConditionName()));
+                    }
+                    if (conditionApiProperty.getConditionParameters().isEmpty()) {
+                        throwDataValidationException(
+                                "Empty 'conditionsParameters' - please supply a valid condition parameter.");
+                    }
+                    conditionApiProperty.getConditionParameters().forEach(
+                            conditionParameter -> {
+                                if (conditionParameter.isEmpty()) {
+                                    throwDataValidationException(
+                                            "Empty 'conditionsParameter' - please supply a valid condition parameter.");
+                                }
+                                if (conditionParameter.size() > 1) {
+                                    throwDataValidationException("Too many name in one 'conditionsParameter' -"
+                                            + " please supply one name in one condition parameter.");
+                                }
+                                conditionParameter.forEach((key, value) -> {
+                                    if (Strings.isNullOrEmpty(key)) {
+                                        throwDataValidationException(
+                                                "Missing 'conditionsParameterName' - please supply a valid name.");
+                                    }
+                                });
+                            }
+                    );
+                }
+        );
+    }
+
+    /**
+     * Validate module name condition properties.
+     * @param conditionProperty name of data to be validated
+     */
+    public static void validateModuleNameConditionProperties(final Map<String, String> conditionProperty) {
+        if (conditionProperty.containsKey("moduleName") && !conditionProperty.get("moduleName").isEmpty()) {
+            return;
+        }
+        throwDataValidationException("Wrong module condition property. - please supply a valid condition property.");
+    }
+
+    private static void throwDataValidationException(final String details) {
+        throw new DataValidationException("Invalid Query Parameter.", details);
+    }
+
+}
index 33868cc..def99e2 100755 (executable)
@@ -177,15 +177,6 @@ class CpsAdminServiceImplSpec extends Specification {
             1 * mockCpsAdminPersistenceService.deleteDataspace('someDataspace')
     }
 
-    def 'Query CM Handles.'() {
-        given: 'a cm handle query'
-            def cmHandleQueryParameters = new CmHandleQueryParameters()
-        when: 'query cm handles is invoked'
-            objectUnderTest.queryCmHandles(cmHandleQueryParameters)
-        then: 'associated persistence service method is invoked with correct parameter'
-            1 * mockCpsAdminPersistenceService.queryCmHandles(cmHandleQueryParameters)
-    }
-
     def 'Delete dataspace with invalid dataspace id.'() {
         when: 'delete dataspace is invoked'
             objectUnderTest.deleteDataspace('some dataspace name')
@@ -194,5 +185,4 @@ class CpsAdminServiceImplSpec extends Specification {
         and: 'associated persistence service method is not invoked'
             0 * mockCpsAdminPersistenceService.deleteDataspace(_)
     }
-
 }
diff --git a/cps-service/src/test/groovy/org/onap/cps/utils/CmHandleQueryRestParametersValidatorSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/utils/CmHandleQueryRestParametersValidatorSpec.groovy
new file mode 100644 (file)
index 0000000..645829b
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *  ============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.utils
+
+import org.onap.cps.spi.exceptions.DataValidationException
+import org.onap.cps.spi.model.CmHandleQueryParameters
+import org.onap.cps.spi.model.ConditionProperties
+import spock.lang.Specification
+
+class CmHandleQueryRestParametersValidatorSpec extends Specification {
+    def 'CM Handle Query validation: empty query.'() {
+        given: 'a cm handle query'
+            def cmHandleQueryParameters = new CmHandleQueryParameters()
+        when: 'validator is invoked'
+            CmHandleQueryRestParametersValidator.validateCmHandleQueryParameters(cmHandleQueryParameters)
+        then: 'data validation exception is not thrown'
+            noExceptionThrown()
+    }
+
+    def 'CM Handle Query validation: normal query.'() {
+        given: 'a cm handle query'
+            def cmHandleQueryParameters = new CmHandleQueryParameters()
+            def condition = new ConditionProperties()
+            condition.conditionName = 'hasAllProperties'
+            condition.conditionParameters = [[key1:'value1'],[key2:'value2']]
+            cmHandleQueryParameters.cmHandleQueryParameters = [condition]
+        when: 'validator is invoked'
+            CmHandleQueryRestParametersValidator.validateCmHandleQueryParameters(cmHandleQueryParameters)
+        then: 'data validation exception is not thrown'
+            noExceptionThrown()
+    }
+
+    def 'CM Handle Query validation: #scenario.'() {
+        given: 'a cm handle query'
+            def cmHandleQueryParameters = new CmHandleQueryParameters()
+            def condition = new ConditionProperties()
+            condition.conditionName = conditionName
+            condition.conditionParameters = conditionParameters
+            cmHandleQueryParameters.cmHandleQueryParameters = [condition]
+        when: 'validator is invoked'
+            CmHandleQueryRestParametersValidator.validateCmHandleQueryParameters(cmHandleQueryParameters)
+        then: 'a data validation exception is thrown'
+            thrown(DataValidationException)
+        where:
+            scenario               | conditionName      | conditionParameters
+            'empty properties'     | 'hasAllProperties' | [[ : ]]
+            'empty conditions'     | 'hasAllProperties' | []
+            'wrong condition name' | 'wrong'            | []
+            'no condition name'    | ''                 | []
+            'too many properties'  | 'hasAllProperties' | [[key1:'value1', key2:'value2']]
+            'wrong properties'     | 'hasAllProperties' | [['':'wrong']]
+    }
+
+    def 'CM Handle Query validation: validate module name condition properties - valid query.'() {
+        given: 'a condition property'
+            def conditionProperty = [moduleName: 'value']
+        when: 'validator is invoked'
+            CmHandleQueryRestParametersValidator.validateModuleNameConditionProperties(conditionProperty)
+        then: 'data validation exception is not thrown'
+            noExceptionThrown()
+    }
+
+    def 'CM Handle Query validation: validate module name condition properties - #scenario.'() {
+        when: 'validator is invoked'
+            CmHandleQueryRestParametersValidator.validateModuleNameConditionProperties(conditionProperty)
+        then: 'a data validation exception is thrown'
+            thrown(DataValidationException)
+        where:
+            scenario        | conditionProperty
+            'invalid value' | [moduleName: '']
+            'invalid name'  | [wrongName: 'value']
+    }
+}
index d4615e7..c0cf451 100644 (file)
@@ -21,4 +21,4 @@ cps-admin
 cps-data
 cps-model-sync
 ncmp-passthrough
-public-properties-query
\ No newline at end of file
+cm-handle-query
\ No newline at end of file
@@ -32,20 +32,29 @@ Suite Setup           Create Session      CPS_URL    http://${CPS_CORE_HOST}:${C
 
 ${auth}                                     Basic Y3BzdXNlcjpjcHNyMGNrcyE=
 ${ncmpBasePath}                             /ncmp/v1
-${jsonMatchingQueryParameters}              {"publicCmHandleProperties": {"Contact" : "newemailforstore@bookstore.com", "Contact2" : "storeemail2@bookstore.com"}}
-${jsonMissingPropertyQueryParameters}       {"publicCmHandleProperties": { "" : "doesnt matter"}}
+${jsonModuleAndPropertyQueryParameters}     {"cmHandleQueryParameters": [{"conditionName": "hasAllModules", "conditionParameters": [ {"moduleName": "iana-crypt-hash"} ]}, {"conditionName": "hasAllProperties", "conditionParameters": [ {"Contact": "newemailforstore@bookstore.com"} ]}]}
+${jsonEmptyQueryParameters}                 {}
+${jsonMissingPropertyQueryParameters}       {"cmHandleQueryParameters": [{"conditionName": "hasAllProperties", "conditionParameters": [{"" : "doesnt matter"}]}]}
 
 *** Test Cases ***
-Retrieve CM Handles where query parameters Match
-    ${uri}=              Set Variable       ${ncmpBasePath}/data/ch/searches
+Retrieve CM Handle ids where query parameters Match (module and property query)
+    ${uri}=              Set Variable       ${ncmpBasePath}/ch/id-searches
     ${headers}=          Create Dictionary  Content-Type=application/json   Authorization=${auth}
-    ${response}=         POST On Session    CPS_URL   ${uri}   headers=${headers}   data=${jsonMatchingQueryParameters}
+    ${response}=         POST On Session    CPS_URL   ${uri}   headers=${headers}   data=${jsonModuleAndPropertyQueryParameters}
+    ${responseJson}=     Set Variable       ${response.json()}
+    Should Be Equal As Strings              ${response.status_code}   200
+    Should Contain       ${responseJson}    PNFDemo
+
+Retrieve CM Handle ids where query parameters Match (empty query)
+    ${uri}=              Set Variable       ${ncmpBasePath}/ch/id-searches
+    ${headers}=          Create Dictionary  Content-Type=application/json   Authorization=${auth}
+    ${response}=         POST On Session    CPS_URL   ${uri}   headers=${headers}   data=${jsonEmptyQueryParameters}
     ${responseJson}=     Set Variable       ${response.json()}
     Should Be Equal As Strings              ${response.status_code}   200
     Should Contain       ${responseJson}    PNFDemo
 
 Throw 400 when Structure of Request is Incorrect
-    ${uri}=              Set Variable       ${ncmpBasePath}/data/ch/searches
+    ${uri}=              Set Variable       ${ncmpBasePath}/ch/id-searches
     ${headers}=          Create Dictionary  Content-Type=application/json   Authorization=${auth}
     ${response}=         POST On Session    CPS_URL   ${uri}   headers=${headers}   data=${jsonMissingPropertyQueryParameters}    expected_status=400
     Should Be Equal As Strings              ${response}   <Response [400]>