aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cps-application/src/main/java/org/onap/cps/Application.java2
-rw-r--r--cps-application/src/main/resources/application.yml3
-rw-r--r--cps-ncmp-rest/docs/openapi/components.yaml101
-rwxr-xr-xcps-ncmp-rest/docs/openapi/ncmp.yml20
-rwxr-xr-xcps-ncmp-rest/docs/openapi/openapi.yml6
-rwxr-xr-xcps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java85
-rw-r--r--cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/executor/CpsNcmpTaskExecutor.java6
-rw-r--r--cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DeprecationHelper.java73
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy35
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy5
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/DeprecationHelperSpec.groovy54
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyCmHandlerQueryService.java35
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java19
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java180
-rwxr-xr-xcps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java144
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsPublisher.java67
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java124
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java8
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java51
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncService.java22
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleQueryApiParameters.java16
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/ConditionApiProperties.java44
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy149
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy49
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy43
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy74
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsPublisherSpec.groovy84
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy4
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy25
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy6
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangModelCmHandleSpec.groovy6
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/DmiServiceUrlBuilderSpec.groovy4
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/MessagingSpec.groovy71
-rw-r--r--cps-ncmp-service/src/test/resources/expectedNcmpEvent.json21
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java25
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java149
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java10
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java11
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java73
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy44
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy106
-rw-r--r--cps-ri/src/test/resources/data/cps-path-query.sql22
-rwxr-xr-xcps-ri/src/test/resources/data/fragment.sql21
-rwxr-xr-xcps-service/src/main/java/org/onap/cps/api/CpsAdminService.java10
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/CpsDataService.java1
-rwxr-xr-xcps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java11
-rwxr-xr-xcps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java12
-rw-r--r--cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java1
-rw-r--r--cps-service/src/main/java/org/onap/cps/spi/model/CmHandleQueryParameters.java12
-rw-r--r--cps-service/src/main/java/org/onap/cps/spi/model/ConditionProperties.java44
-rw-r--r--cps-service/src/main/java/org/onap/cps/spi/model/DataNode.java1
-rw-r--r--cps-service/src/main/java/org/onap/cps/spi/model/DataNodeBuilder.java14
-rw-r--r--cps-service/src/main/java/org/onap/cps/spi/model/DataNodeIdentifier.java37
-rw-r--r--cps-service/src/main/java/org/onap/cps/utils/CmHandleQueryRestParametersValidator.java93
-rw-r--r--cps-service/src/main/java/org/onap/cps/utils/DataMapUtils.java11
-rwxr-xr-xcps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy10
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy17
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/utils/CmHandleQueryRestParametersValidatorSpec.groovy91
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy28
-rw-r--r--csit/plans/cps/testplan.txt2
-rw-r--r--csit/tests/cm-handle-query/cm-handle-query.robot (renamed from csit/tests/public-properties-query/public-properties-query.robot)21
-rw-r--r--csit/tests/cps-data/cps-data.robot3
-rwxr-xr-xdocker-compose/docker-compose.yml1
64 files changed, 1789 insertions, 730 deletions
diff --git a/cps-application/src/main/java/org/onap/cps/Application.java b/cps-application/src/main/java/org/onap/cps/Application.java
index ba707e964..79d5950f6 100644
--- a/cps-application/src/main/java/org/onap/cps/Application.java
+++ b/cps-application/src/main/java/org/onap/cps/Application.java
@@ -22,7 +22,9 @@ package org.onap.cps;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.retry.annotation.EnableRetry;
+@EnableRetry
@SpringBootApplication
public class Application {
diff --git a/cps-application/src/main/resources/application.yml b/cps-application/src/main/resources/application.yml
index af886a142..3f005c9f7 100644
--- a/cps-application/src/main/resources/application.yml
+++ b/cps-application/src/main/resources/application.yml
@@ -86,7 +86,8 @@ app:
ncmp:
async-m2m:
topic: ${NCMP_ASYNC_M2M_TOPIC:ncmp-async-m2m}
-
+ events:
+ topic: ${NCMP_EVENTS_TOPIC:ncmp-events}
notification:
data-updated:
enabled: false
diff --git a/cps-ncmp-rest/docs/openapi/components.yaml b/cps-ncmp-rest/docs/openapi/components.yaml
index 5fe47e4b0..248b1daa6 100644
--- a/cps-ncmp-rest/docs/openapi/components.yaml
+++ b/cps-ncmp-rest/docs/openapi/components.yaml
@@ -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
diff --git a/cps-ncmp-rest/docs/openapi/ncmp.yml b/cps-ncmp-rest/docs/openapi/ncmp.yml
index 318e6e66d..3259032f2 100755
--- a/cps-ncmp-rest/docs/openapi/ncmp.yml
+++ b/cps-ncmp-rest/docs/openapi/ncmp.yml
@@ -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, if one of the given module names does not exists, return with an empty collection.
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, if one of the given module names does not exists, return with an empty collection.
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
diff --git a/cps-ncmp-rest/docs/openapi/openapi.yml b/cps-ncmp-rest/docs/openapi/openapi.yml
index b4082918f..81ebf05ed 100755
--- a/cps-ncmp-rest/docs/openapi/openapi.yml
+++ b/cps-ncmp-rest/docs/openapi/openapi.yml
@@ -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'
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
index 11517bcc9..ccb1e9bbb 100755
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
@@ -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/executor/CpsNcmpTaskExecutor.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/executor/CpsNcmpTaskExecutor.java
index 93aa2858c..5adbb252a 100644
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/executor/CpsNcmpTaskExecutor.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/executor/CpsNcmpTaskExecutor.java
@@ -40,11 +40,7 @@ public class CpsNcmpTaskExecutor {
public void executeTask(final Supplier<Object> taskSupplier, final int timeOutInMillis) {
CompletableFuture.supplyAsync(taskSupplier::get)
.orTimeout(timeOutInMillis, MILLISECONDS)
- .whenCompleteAsync(
- (responseAsJson, throwable) -> {
- handleTaskCompletion(throwable);
- }
- );
+ .whenCompleteAsync((responseAsJson, throwable) -> handleTaskCompletion(throwable));
}
private void handleTaskCompletion(final Throwable throwable) {
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
index 000000000..fc992da41
--- /dev/null
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DeprecationHelper.java
@@ -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;
+ }
+}
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
index 60ea736d7..036928fe3 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
@@ -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)
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy
index 45ed3d307..1563c75b3 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy
@@ -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
index 000000000..8c212d353
--- /dev/null
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/DeprecationHelperSpec.groovy
@@ -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
index 000000000..f8d51feba
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyCmHandlerQueryService.java
@@ -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);
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
index 7527ae5c5..ce850cc82 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
@@ -106,15 +106,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.
*
* @param cmHandleId cm handle identifier
@@ -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
index 000000000..ef6e953e2
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java
@@ -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);
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
index 717cae565..d1f72a5ef 100755
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
@@ -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,10 +44,13 @@ 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.CmHandleState;
import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
import org.onap.cps.ncmp.api.inventory.sync.ModuleSyncService;
import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters;
@@ -61,6 +63,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 +91,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 +159,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 cpsAdminService.queryCmHandles(jsonObjectMapper.convertToValueType(cmHandleQueryApiParameters,
- org.onap.cps.spi.model.CmHandleQueryParameters.class));
+ return networkCmProxyCmHandlerQueryService.queryCmHandles(cmHandleQueryParameters).stream()
+ .map(dataNode -> YangDataConverter
+ .convertCmHandleToYangModel(dataNode, dataNode.getLeaves().get("id").toString()))
+ .map(YangDataConverter::convertYangModelCmHandleToNcmpServiceCmHandle).collect(Collectors.toSet());
+ }
+
+ /**
+ * 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 +199,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 +216,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,7 +227,7 @@ 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()
@@ -231,52 +235,47 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
YangModelCmHandle.toYangModelCmHandle(
dmiPluginRegistration.getDmiPlugin(),
dmiPluginRegistration.getDmiDataPlugin(),
- dmiPluginRegistration.getDmiModelPlugin(), cmHandle)
+ dmiPluginRegistration.getDmiModelPlugin(),
+ CmHandleState.ADVISED,
+ cmHandle)
)
- .map(this::registerAndSyncNewCmHandle)
+ .map(this::registerNewCmHandle)
.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;
}
- protected void syncModulesAndCreateAnchor(final YangModelCmHandle yangModelCmHandle) {
- final String schemaSetName = moduleSyncService.syncAndCreateSchemaSet(yangModelCmHandle);
- final String anchorName = yangModelCmHandle.getId();
- cpsAdminService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetName,
- anchorName);
- }
-
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 +284,24 @@ 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) {
+ private CmHandleRegistrationResponse registerNewCmHandle(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);
- syncModulesAndCreateAnchor(yangModelCmHandle);
+ cmHandleJsonData, NO_TIMESTAMP);
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/event/NcmpEventsPublisher.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsPublisher.java
new file mode 100644
index 000000000..52ac4685e
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsPublisher.java
@@ -0,0 +1,67 @@
+/*
+ * ============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.event;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.ncmp.cmhandle.lcm.event.NcmpEvent;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.kafka.support.SendResult;
+import org.springframework.stereotype.Service;
+import org.springframework.util.concurrent.ListenableFuture;
+import org.springframework.util.concurrent.ListenableFutureCallback;
+
+/**
+ * NcmpEventsPublisher to publish the NcmpEvents on event of CREATE, UPDATE and DELETE.
+ */
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class NcmpEventsPublisher {
+
+ private final KafkaTemplate<String, NcmpEvent> ncmpEventKafkaTemplate;
+
+ /**
+ * NCMP Event publisher.
+ *
+ * @param topicName valid topic name
+ * @param eventKey message key
+ * @param ncmpEvent message payload
+ */
+ public void publishEvent(final String topicName, final String eventKey, final NcmpEvent ncmpEvent) {
+ final ListenableFuture<SendResult<String, NcmpEvent>> ncmpEventFuture =
+ ncmpEventKafkaTemplate.send(topicName, eventKey, ncmpEvent);
+
+ ncmpEventFuture.addCallback(new ListenableFutureCallback<>() {
+ @Override
+ public void onFailure(final Throwable throwable) {
+ log.error("Unable to publish event to topic : {} due to {}", topicName, throwable.getMessage());
+ }
+
+ @Override
+ public void onSuccess(final SendResult<String, NcmpEvent> result) {
+ log.debug("Successfully published event to topic : {} , NcmpEvent : {}",
+ result.getRecordMetadata().topic(), result.getProducerRecord().value());
+ }
+ });
+ }
+}
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
index 000000000..82ea00eb3
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java
@@ -0,0 +1,124 @@
+/*
+ * ============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.getCompositeState().getCmHandleState(),
+ 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);
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java
index 65e03f1f9..5b719054a 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java
@@ -34,7 +34,9 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService;
+import org.onap.cps.ncmp.api.inventory.CmHandleState;
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.utils.CpsValidator;
@@ -68,6 +70,8 @@ public class YangModelCmHandle {
@JsonProperty("public-properties")
private List<Property> publicProperties;
+ private static final CompositeStateBuilder compositeStateBuilder = new CompositeStateBuilder();
+
/**
* Create a yangModelCmHandle.
*
@@ -80,6 +84,7 @@ public class YangModelCmHandle {
public static YangModelCmHandle toYangModelCmHandle(final String dmiServiceName,
final String dmiDataServiceName,
final String dmiModelServiceName,
+ final CmHandleState cmHandleState,
final NcmpServiceCmHandle ncmpServiceCmHandle) {
CpsValidator.validateNameCharacters(ncmpServiceCmHandle.getCmHandleId());
final YangModelCmHandle yangModelCmHandle = new YangModelCmHandle();
@@ -90,7 +95,8 @@ public class YangModelCmHandle {
yangModelCmHandle.setDmiProperties(asYangModelCmHandleProperties(ncmpServiceCmHandle.getDmiProperties()));
yangModelCmHandle.setPublicProperties(asYangModelCmHandleProperties(
ncmpServiceCmHandle.getPublicProperties()));
- yangModelCmHandle.setCompositeState(ncmpServiceCmHandle.getCompositeState());
+ compositeStateBuilder.withCmHandleState(cmHandleState);
+ yangModelCmHandle.setCompositeState(compositeStateBuilder.build());
return yangModelCmHandle;
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java
index 873a44913..2fc2dc5c1 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java
@@ -21,13 +21,11 @@
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;
@@ -43,6 +41,8 @@ public class InventoryPersistence {
private static final String NCMP_DMI_REGISTRY_ANCHOR = "ncmp-dmi-registry";
+ private static final String XPATH_TO_CM_HANDLE = "/dmi-registry/cm-handles[@id='" + "%s" + "']";
+
private final JsonObjectMapper jsonObjectMapper;
private final CpsDataService cpsDataService;
@@ -59,7 +59,7 @@ public class InventoryPersistence {
*/
public CompositeState getCmHandleState(final String cmHandleId) {
final DataNode stateAsDataNode = cpsDataService.getDataNode(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
- "/dmi-registry/cm-handles[@id='" + cmHandleId + "']/state",
+ String.format(XPATH_TO_CM_HANDLE, cmHandleId) + "/state",
FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
return compositeStateBuilder.fromDataNode(stateAsDataNode).build();
}
@@ -74,7 +74,7 @@ public class InventoryPersistence {
final String cmHandleJsonData = String.format("{\"state\":%s}",
jsonObjectMapper.asJsonString(compositeState));
cpsDataService.replaceNodeTree(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
- "/dmi-registry/cm-handles[@id='" + cmHandleId + "']",
+ String.format(XPATH_TO_CM_HANDLE, cmHandleId),
cmHandleJsonData, OffsetDateTime.now());
}
@@ -92,55 +92,20 @@ public class InventoryPersistence {
}
/**
- * This method retrieves DMI service name and DMI properties for a given cm handle.
+ * This method retrieves DMI service name, DMI properties and the state for a given cm handle.
* @param cmHandleId the id of the cm handle
* @return yang model cm handle
*/
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) {
- final String xpathForDmiRegistryToFetchCmHandle = "/dmi-registry/cm-handles[@id='" + cmHandle + "']";
return cpsDataService.getDataNode(NCMP_DATASPACE_NAME,
NCMP_DMI_REGISTRY_ANCHOR,
- xpathForDmiRegistryToFetchCmHandle,
+ String.format(XPATH_TO_CM_HANDLE, cmHandle),
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")));
- }
-
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncService.java
index 1d00f0dc6..58e2bf345 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncService.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncService.java
@@ -28,6 +28,7 @@ import java.util.Map;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.api.CpsAdminService;
import org.onap.cps.api.CpsModuleService;
import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations;
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
@@ -42,13 +43,14 @@ public class ModuleSyncService {
private final DmiModelOperations dmiModelOperations;
private final CpsModuleService cpsModuleService;
+ private final CpsAdminService cpsAdminService;
+
/**
* This method registers a cm handle and initiates modules sync.
*
* @param yangModelCmHandle the yang model of cm handle.
- * @return schemaSetName the name of the schema set (same as cm handle name).
*/
- public String syncAndCreateSchemaSet(final YangModelCmHandle yangModelCmHandle) {
+ public void syncAndCreateSchemaSetAndAnchor(final YangModelCmHandle yangModelCmHandle) {
final Collection<ModuleReference> moduleReferencesFromCmHandle =
dmiModelOperations.getModuleReferences(yangModelCmHandle);
@@ -68,17 +70,17 @@ public class ModuleSyncService {
newModuleNameToContentMap = dmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle,
identifiedNewModuleReferencesFromCmHandle);
}
- return createSchemaSet(yangModelCmHandle, existingModuleReferencesFromCmHandle, newModuleNameToContentMap);
+ createSchemaSetAndAnchor(yangModelCmHandle, newModuleNameToContentMap, existingModuleReferencesFromCmHandle);
}
- private String createSchemaSet(final YangModelCmHandle yangModelCmHandle,
- final Collection<ModuleReference> existingModuleReferencesFromCmHandle,
- final Map<String, String> newModuleNameToContentMap) {
- final String schemaSetName = yangModelCmHandle.getId();
- cpsModuleService
- .createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetName,
+ private void createSchemaSetAndAnchor(final YangModelCmHandle yangModelCmHandle,
+ final Map<String, String> newModuleNameToContentMap,
+ final Collection<ModuleReference> existingModuleReferencesFromCmHandle) {
+ final String schemaSetAndAnchorName = yangModelCmHandle.getId();
+ cpsModuleService.createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetAndAnchorName,
newModuleNameToContentMap, existingModuleReferencesFromCmHandle);
- return schemaSetName;
+ cpsAdminService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetAndAnchorName,
+ schemaSetAndAnchorName);
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java
index 2187ec61c..bcc7daa39 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java
@@ -51,7 +51,7 @@ public class ModuleSyncWatchdog {
final String cmHandleId = advisedCmHandle.getId();
final CompositeState compositeState = inventoryPersistence.getCmHandleState(cmHandleId);
try {
- moduleSyncService.syncAndCreateSchemaSet(advisedCmHandle);
+ moduleSyncService.syncAndCreateSchemaSetAndAnchor(advisedCmHandle);
compositeState.setCmHandleState(CmHandleState.READY);
} catch (final Exception e) {
compositeState.setCmHandleState(CmHandleState.LOCKED);
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleQueryApiParameters.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleQueryApiParameters.java
index 3f584ed15..bf6600d97 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleQueryApiParameters.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleQueryApiParameters.java
@@ -20,22 +20,24 @@
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
index 000000000..9f6d64e16
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/ConditionApiProperties.java
@@ -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
index 000000000..a1ad9af19
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy
@@ -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')]
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
index f56aea7f3..e9d02dfc7 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
@@ -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,9 +65,10 @@ 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()
+ def objectUnderTest = getObjectUnderTest()
def 'DMI Registration: Create, Update & Delete operations are processed in the right order'() {
given: 'a registration with operations of all three types'
@@ -164,20 +166,10 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
}
and: 'save list elements is invoked with the expected parameters'
interaction {
- def expectedJsonData = """{"cm-handles":[{"id":"cmhandle","dmi-service-name":"my-server","additional-properties":$expectedDmiProperties,"public-properties":$expectedPublicProperties}]}"""
+ def expectedJsonData = """{"cm-handles":[{"id":"cmhandle","dmi-service-name":"my-server","state":{"cm-handle-state":"ADVISED"},"additional-properties":$expectedDmiProperties,"public-properties":$expectedPublicProperties}]}"""
1 * mockCpsDataService.saveListElements('NCMP-Admin', 'ncmp-dmi-registry',
'/dmi-registry', expectedJsonData, noTimestamp)
}
- then: 'model sync is invoked with expected parameters'
- 1 * objectUnderTest.syncModulesAndCreateAnchor(_) >> { YangModelCmHandle yangModelCmHandle ->
- {
- assert yangModelCmHandle.id == 'cmhandle'
- assert yangModelCmHandle.dmiServiceName == 'my-server'
- assert spiedJsonObjectMapper.asJsonString(yangModelCmHandle.getPublicProperties()) == expectedPublicProperties
- assert spiedJsonObjectMapper.asJsonString(yangModelCmHandle.getDmiProperties()) == expectedDmiProperties
-
- }
- }
where:
scenario | dmiProperties | publicProperties || expectedDmiProperties | expectedPublicProperties
'with dmi & public properties' | ['dmi-key': 'dmi-value'] | ['public-key': 'public-value'] || '[{"name":"dmi-key","value":"dmi-value"}]' | '[{"name":"public-key","value":"public-value"}]'
@@ -233,8 +225,6 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
assert it.registrationError == expectedError
assert it.errorText == expectedErrorText
}
- and: 'model-sync is not invoked'
- 0 * objectUnderTest.syncModulesAndCreateAnchor(_)
where:
scenario | cmHandleId | exception || expectedError | expectedErrorText
'cm-handle already exist' | 'cmhandle' | new AlreadyDefinedException('', new RuntimeException()) || CM_HANDLE_ALREADY_EXIST | 'cm-handle already exists'
@@ -242,28 +232,6 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
'unknown exception while registering cm-handle' | 'cmhandle' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed'
}
- def 'Create CM-Handle Error Handling: Model Sync fails'() {
- given: 'objects under test without disabled model sync'
- def objectUnderTest = getObjectUnderTest()
- and: 'a registration without cm-handle properties'
- def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server')
- dmiPluginRegistration.createdCmHandles = [new NcmpServiceCmHandle(cmHandleId: 'cmhandle')]
- and: 'cm-handler models sync fails'
- objectUnderTest.syncModulesAndCreateAnchor(*_) >> { throw new RuntimeException('Model-Sync failed') }
- when: 'registration is updated'
- def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
- then: 'a failure response is received'
- response.getCreatedCmHandles().size() == 1
- with(response.getCreatedCmHandles().get(0)) {
- assert it.status == Status.FAILURE
- assert it.cmHandle == 'cmhandle'
- assert it.registrationError == UNKNOWN_ERROR
- assert it.errorText == 'Model-Sync failed'
- }
- and: 'cm-handle is registered'
- 1 * mockCpsDataService.saveListElements(*_)
- }
-
def 'Update CM-Handle: Update Operation Response is added to the response'() {
given: 'a registration to update CmHandles'
def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server',
@@ -379,14 +347,9 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
'an unexpected exception' | 'cmhandle' | new RuntimeException("Failed") || UNKNOWN_ERROR | 'Failed'
}
- def getObjectUnderTestWithModelSyncDisabled() {
- def objectUnderTest = getObjectUnderTest()
- objectUnderTest.syncModulesAndCreateAnchor(*_) >> null
- return objectUnderTest
- }
-
def getObjectUnderTest() {
return Spy(new NetworkCmProxyDataServiceImpl(mockCpsDataService, spiedJsonObjectMapper, mockDmiDataOperations,
- mockCpsModuleService, mockCpsAdminService, mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockModuleSyncService))
+ mockCpsModuleService, mockCpsAdminService, mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence,
+ mockModuleSyncService, stubbedNetworkCmProxyCmHandlerQueryService))
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
index 55a1a8d1f..6ba2a2c27 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
@@ -22,15 +22,19 @@
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'
@@ -241,8 +240,28 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
then: 'validate params for creating anchor and list elements'
1 * mockCpsDataService.saveListElements('NCMP-Admin', 'ncmp-dmi-registry',
'/dmi-registry', '{"cm-handles":[{"id":"some-cm-handle-id",' +
- '"additional-properties":[],"public-properties":[]}]}', null)
- 1 * mockCpsAdminService.createAnchor('NFP-Operational', null,
- 'some-cm-handle-id')
+ '"state":{"cm-handle-state":"ADVISED"},'
+ + '"additional-properties":[],"public-properties":[]}]}', null)
+ }
+
+ 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
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy
index aa6bf1a78..31f179ab2 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy
@@ -20,68 +20,26 @@
package org.onap.cps.ncmp.api.impl.async
-import org.apache.kafka.clients.consumer.ConsumerConfig
-import org.apache.kafka.clients.producer.ProducerConfig
-import org.apache.kafka.common.serialization.StringSerializer
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.apache.kafka.clients.consumer.KafkaConsumer
import org.mapstruct.factory.Mappers
+import org.onap.cps.ncmp.api.utils.MessagingSpec
import org.onap.cps.ncmp.event.model.DmiAsyncRequestResponseEvent
import org.onap.cps.ncmp.event.model.NcmpAsyncRequestResponseEvent
-import org.springframework.kafka.core.DefaultKafkaProducerFactory
-import org.springframework.kafka.core.KafkaTemplate
-import org.springframework.kafka.support.serializer.JsonSerializer
-import org.testcontainers.containers.KafkaContainer
-import org.testcontainers.spock.Testcontainers
-import org.testcontainers.utility.DockerImageName
-
-import java.time.Duration
-import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.ncmp.utils.TestUtils
import org.onap.cps.utils.JsonObjectMapper
-import org.apache.kafka.clients.consumer.KafkaConsumer
-import org.apache.kafka.common.serialization.StringDeserializer
-import org.onap.cps.ncmp.utils.TestUtils;
-import org.springframework.boot.test.context.SpringBootTest
import org.spockframework.spring.SpringBean
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.annotation.DirtiesContext
-import org.springframework.test.context.DynamicPropertyRegistry
-import org.springframework.test.context.DynamicPropertySource
-import spock.lang.Specification
+import org.testcontainers.spock.Testcontainers
+
+import java.time.Duration
-@SpringBootTest(classes = [NcmpAsyncRequestResponseEventProducer, NcmpAsyncRequestResponseEventConsumer])
+@SpringBootTest(classes = [NcmpAsyncRequestResponseEventProducer, NcmpAsyncRequestResponseEventConsumer, ObjectMapper, JsonObjectMapper])
@Testcontainers
@DirtiesContext
-class NcmpAsyncRequestResponseEventProducerIntegrationSpec extends Specification {
-
- static kafkaTestContainer = new KafkaContainer(
- DockerImageName.parse('confluentinc/cp-kafka:6.2.1')
- )
-
- static {
- Runtime.getRuntime().addShutdownHook(new Thread(kafkaTestContainer::stop))
- }
-
- def setupSpec() {
- kafkaTestContainer.start()
- }
-
- def producerConfigProperties = [
- (ProducerConfig.BOOTSTRAP_SERVERS_CONFIG) : kafkaTestContainer.getBootstrapServers().split(',')[0],
- (ProducerConfig.RETRIES_CONFIG) : 0,
- (ProducerConfig.BATCH_SIZE_CONFIG) : 16384,
- (ProducerConfig.LINGER_MS_CONFIG) : 1,
- (ProducerConfig.BUFFER_MEMORY_CONFIG) : 33554432,
- (ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG) : StringSerializer,
- (ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG) : JsonSerializer
- ]
-
- def consumerConfigProperties = [
- (ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG) : kafkaTestContainer.getBootstrapServers().split(',')[0],
- (ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG) : StringDeserializer,
- (ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG): StringDeserializer,
- (ConsumerConfig.AUTO_OFFSET_RESET_CONFIG) : 'earliest',
- (ConsumerConfig.GROUP_ID_CONFIG) : 'test'
- ]
-
- def kafkaTemplate = new KafkaTemplate<>(new DefaultKafkaProducerFactory<Integer, String>(producerConfigProperties))
+class NcmpAsyncRequestResponseEventProducerIntegrationSpec extends MessagingSpec {
@SpringBean
NcmpAsyncRequestResponseEventProducer cpsAsyncRequestResponseEventProducerService =
@@ -96,9 +54,10 @@ class NcmpAsyncRequestResponseEventProducerIntegrationSpec extends Specification
new NcmpAsyncRequestResponseEventConsumer(cpsAsyncRequestResponseEventProducerService,
ncmpAsyncRequestResponseEventMapper)
- def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
+ @Autowired
+ JsonObjectMapper jsonObjectMapper
- def kafkaConsumer = new KafkaConsumer<>(getConsumerConfigProperties())
+ def kafkaConsumer = new KafkaConsumer<>(consumerConfigProperties('test'))
def 'Consume and forward valid message'() {
given: 'consumer has a subscription'
@@ -118,9 +77,4 @@ class NcmpAsyncRequestResponseEventProducerIntegrationSpec extends Specification
NcmpAsyncRequestResponseEvent).getForwardedEvent().getEventId())
}
- @DynamicPropertySource
- static void registerKafkaProperties(DynamicPropertyRegistry dynamicPropertyRegistry) {
- dynamicPropertyRegistry.add('spring.kafka.bootstrap-servers', kafkaTestContainer::getBootstrapServers)
- }
-
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsPublisherSpec.groovy
new file mode 100644
index 000000000..774a46558
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsPublisherSpec.groovy
@@ -0,0 +1,84 @@
+/*
+ * ============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.event
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.apache.kafka.clients.consumer.KafkaConsumer
+import org.onap.cps.ncmp.api.utils.MessagingSpec
+import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.utils.JsonObjectMapper
+import org.onap.ncmp.cmhandle.lcm.event.Event
+import org.onap.ncmp.cmhandle.lcm.event.NcmpEvent
+import org.spockframework.spring.SpringBean
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.annotation.DirtiesContext
+import org.testcontainers.spock.Testcontainers
+
+import java.time.Duration
+
+@SpringBootTest(classes = [NcmpEventsPublisher, ObjectMapper, JsonObjectMapper])
+@Testcontainers
+@DirtiesContext
+class NcmpEventsPublisherSpec extends MessagingSpec {
+
+ def kafkaConsumer = new KafkaConsumer<>(consumerConfigProperties('ncmp-group'))
+
+ def testTopic = 'ncmp-events-test'
+
+ @SpringBean
+ NcmpEventsPublisher ncmpEventsPublisher = new NcmpEventsPublisher(kafkaTemplate)
+
+ @Autowired
+ JsonObjectMapper jsonObjectMapper
+
+
+ def 'Produce and Consume Ncmp Event'() {
+ given: 'event key and event data'
+ def eventKey = 'ncmp'
+ def eventData = new NcmpEvent(eventId: 'test-uuid',
+ eventCorrelationId: 'cmhandle-as-correlationid',
+ eventSchema: URI.create('org.onap.ncmp.cmhandle.lcm.event:v1'),
+ eventSource: URI.create('org.onap.ncmp'),
+ eventTime: '2022-12-31T20:30:40.000+0000',
+ eventType: 'org.onap.ncmp.cmhandle.lcm.event',
+ event: new Event(cmHandleId: 'cmhandle-test', cmhandleState: 'READY', operation: 'CREATE', cmhandleProperties: [['publicProperty1': 'value1'], ['publicProperty2': 'value2']]))
+ and: 'we have an expected NcmpEvent'
+ def expectedJsonString = TestUtils.getResourceFileContent('expectedNcmpEvent.json')
+ def expectedNcmpEvent = jsonObjectMapper.convertJsonString(expectedJsonString, NcmpEvent.class)
+ and: 'consumer has a subscription'
+ kafkaConsumer.subscribe([testTopic] as List<String>)
+ when: 'an event is published'
+ ncmpEventsPublisher.publishEvent(testTopic, eventKey, eventData)
+ and: 'topic is polled'
+ def records = kafkaConsumer.poll(Duration.ofMillis(1500))
+ then: 'no exception is thrown'
+ noExceptionThrown()
+ and: 'poll returns one record'
+ assert records.size() == 1
+ and: 'record key matches the expected event key'
+ def record = records.iterator().next()
+ assert eventKey == record.key
+ and: 'record matches the expected event'
+ assert expectedNcmpEvent == jsonObjectMapper.convertJsonString(record.value, NcmpEvent.class)
+
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy
index b638eecd4..a2ebcb5d8 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy
@@ -88,7 +88,7 @@ class InventoryPersistenceSpec extends Specification {
where: 'the following parameters are used'
scenario | childDataNodes || expectedDmiProperties || expectedPublicProperties || expectedCompositeState
'no properties' | [] || [] || [] || null
- 'DMI and public properties' | childDataNodesForCmHandleWithAllProperties || [new YangModelCmHandle.Property("name1", "value1")] || [new YangModelCmHandle.Property("name2", "value2")] || null
+ 'DMI and public properties' | childDataNodesForCmHandleWithAllProperties || [new YangModelCmHandle.Property("name1", "value1")] || [new YangModelCmHandle.Property("name2", "value2")] || null
'just DMI properties' | childDataNodesForCmHandleWithDMIProperties || [new YangModelCmHandle.Property("name1", "value1")] || [] || null
'just public properties' | childDataNodesForCmHandleWithPublicProperties || [] || [new YangModelCmHandle.Property("name2", "value2")] || null
'with state details' | childDataNodesForCmHandleWithState || [] || [] || CmHandleState.ADVISED
@@ -105,7 +105,7 @@ class InventoryPersistenceSpec extends Specification {
def "Handling missing service names as null CPS-1043."() {
given: 'the cps data service returns a data node from the DMI registry with empty child and leaf attributes'
- def dataNode = new DataNode(childDataNodes:[], leaves: [:])
+ def dataNode = new DataNode(childDataNodes:[], leaves: ["cm-handle-state":"ADVISED"])
mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry', xpath, INCLUDE_ALL_DESCENDANTS) >> dataNode
when: 'retrieving the yang modelled cm handle'
def result = objectUnderTest.getYangModelCmHandle(cmHandleId)
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy
index 37fdbeeb2..8050a571a 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy
@@ -20,9 +20,11 @@
package org.onap.cps.ncmp.api.inventory.sync
+import org.onap.cps.api.CpsAdminService
import org.onap.cps.api.CpsModuleService
import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
+import org.onap.cps.ncmp.api.inventory.CmHandleState
import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
import org.onap.cps.spi.model.ModuleReference
import spock.lang.Specification
@@ -32,8 +34,9 @@ class ModuleSyncServiceSpec extends Specification {
def mockCpsModuleService = Mock(CpsModuleService)
def mockDmiModelOperations = Mock(DmiModelOperations)
+ def mockCpsAdminService = Mock(CpsAdminService)
- def objectUnderTest = new ModuleSyncService(mockDmiModelOperations, mockCpsModuleService)
+ def objectUnderTest = new ModuleSyncService(mockDmiModelOperations, mockCpsModuleService, mockCpsAdminService)
def expectedDataspaceName = 'NFP-Operational'
@@ -42,7 +45,7 @@ class ModuleSyncServiceSpec extends Specification {
def ncmpServiceCmHandle = new NcmpServiceCmHandle()
def dmiServiceName = 'some service name'
ncmpServiceCmHandle.cmHandleId = 'cmHandleId-1'
- def yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, '' , '', ncmpServiceCmHandle)
+ def yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, '' , '', CmHandleState.ADVISED, ncmpServiceCmHandle)
and: 'DMI operations returns some module references'
def moduleReferences = [ new ModuleReference(moduleName:'module1',revision:'1'),
new ModuleReference(moduleName:'module2',revision:'2') ]
@@ -50,17 +53,19 @@ class ModuleSyncServiceSpec extends Specification {
and: 'CPS-Core returns list of existing module resources'
mockCpsModuleService.getYangResourceModuleReferences(expectedDataspaceName) >> toModuleReference(existingModuleResourcesInCps)
and: 'DMI-Plugin returns resource(s) for "new" module(s)'
- mockDmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle, [new ModuleReference('module1', '1')]) >> yangResourceToContentMap
+ mockDmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle, [new ModuleReference('module1', '1')]) >> newModuleNameContentToMap
when: 'module sync is triggered'
mockCpsModuleService.identifyNewModuleReferences(moduleReferences) >> toModuleReference(identifiedNewModuleReferences)
- def result = objectUnderTest.syncAndCreateSchemaSet(yangModelCmHandle)
- then: 'the resulting schema set name is the same as the cm handle id'
- assert result == 'cmHandleId-1'
+ objectUnderTest.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle)
+ then: 'create schema set from module is invoked with correct parameters'
+ 1 * mockCpsModuleService.createSchemaSetFromModules('NFP-Operational', 'cmHandleId-1', newModuleNameContentToMap, existingModuleReferencesInCps)
+ and: 'anchor is created with the correct parameters'
+ 1 * mockCpsAdminService.createAnchor('NFP-Operational', 'cmHandleId-1', 'cmHandleId-1')
where: 'the following parameters are used'
- scenario | existingModuleResourcesInCps | identifiedNewModuleReferences | yangResourceToContentMap
- 'one new module' | [['module2' : '2'], ['module3' : '3']] | [['module1' : '1']] | [module1: 'some yang source']
- 'no add. properties' | [['module2' : '2'], ['module3' : '3']] | [['module1' : '1']] | [module1: 'some yang source']
- 'no new module' | [['module1' : '1'], ['module2' : '2']] | [] | [:]
+ scenario | existingModuleResourcesInCps | identifiedNewModuleReferences | newModuleNameContentToMap | existingModuleReferencesInCps
+ 'one new module' | [['module2' : '2'], ['module3' : '3']] | [['module1' : '1']] | [module1: 'some yang source'] | [new ModuleReference(moduleName:'module2',revision:'2')]
+ 'no add. properties' | [['module2' : '2'], ['module3' : '3']] | [['module1' : '1']] | [module1: 'some yang source'] | [new ModuleReference(moduleName:'module2',revision:'2')]
+ 'no new module' | [['module1' : '1'], ['module2' : '2']] | [] | [:] | [new ModuleReference(moduleName:'module1',revision:'1'), new ModuleReference(moduleName:'module2',revision:'2')]
}
def toModuleReference(moduleReferenceAsMap) {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy
index bcfe47fd5..97bea096a 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy
@@ -52,7 +52,7 @@ class ModuleSyncSpec extends Specification {
then: 'the inventory persistence cm handle returns a composite state for the first cm handle'
1 * mockInventoryPersistence.getCmHandleState('some-cm-handle') >> compositeState1
and: 'module sync service syncs the first cm handle and creates a schema set'
- 1 * mockModuleSyncService.syncAndCreateSchemaSet(yangModelCmHandle1)
+ 1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle1)
and: 'the composite state cm handle state is now READY'
assert compositeState1.getCmHandleState() == CmHandleState.READY
and: 'the first cm handle state is updated'
@@ -60,7 +60,7 @@ class ModuleSyncSpec extends Specification {
then: 'the inventory persistence cm handle returns a composite state for the second cm handle'
mockInventoryPersistence.getCmHandleState('some-cm-handle-2') >> compositeState2
and: 'module sync service syncs the second cm handle and creates a schema set'
- 1 * mockModuleSyncService.syncAndCreateSchemaSet(yangModelCmHandle2)
+ 1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle2)
and: 'the composite state cm handle state is now READY'
assert compositeState2.getCmHandleState() == CmHandleState.READY
and: 'the second cm handle state is updated'
@@ -78,7 +78,7 @@ class ModuleSyncSpec extends Specification {
then: 'the inventory persistence cm handle returns a composite state for the cm handle'
1 * mockInventoryPersistence.getCmHandleState('some-cm-handle') >> compositeState
and: 'module sync service attempts to sync the cm handle and throws an exception'
- 1 * mockModuleSyncService.syncAndCreateSchemaSet(*_) >> { throw new Exception('some exception') }
+ 1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(*_) >> { throw new Exception('some exception') }
and: 'the composite state cm handle state is now LOCKED'
assert compositeState.getCmHandleState() == CmHandleState.LOCKED
and: 'update lock reason, details and attempts is invoked'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangModelCmHandleSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangModelCmHandleSpec.groovy
index 7bbc3d753..cdfcf59ef 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangModelCmHandleSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangModelCmHandleSpec.groovy
@@ -21,6 +21,8 @@
package org.onap.cps.ncmp.api.models
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
+import org.onap.cps.ncmp.api.inventory.CmHandleState
+import org.onap.ncmp.cmhandle.lcm.event.Event
import spock.lang.Specification
import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA
@@ -35,7 +37,7 @@ class YangModelCmHandleSpec extends Specification {
ncmpServiceCmHandle.dmiProperties = [myDmiProperty:'value1']
ncmpServiceCmHandle.publicProperties = [myPublicProperty:'value2']
when: 'it is converted to a yang model cm handle'
- def objectUnderTest = YangModelCmHandle.toYangModelCmHandle('','','', ncmpServiceCmHandle)
+ def objectUnderTest = YangModelCmHandle.toYangModelCmHandle('','','', CmHandleState.ADVISED, ncmpServiceCmHandle)
then: 'the result has the right size'
assert objectUnderTest.dmiProperties.size() == 1
and: 'the DMI property in the result has the correct name and value'
@@ -48,7 +50,7 @@ class YangModelCmHandleSpec extends Specification {
def 'Resolve DMI service name: #scenario and #requiredService service require.'() {
given: 'a yang model cm handle'
- def objectUnderTest = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, dmiDataServiceName, dmiModelServiceName, new NcmpServiceCmHandle(cmHandleId: 'cm-handle-id-1'))
+ def objectUnderTest = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, dmiDataServiceName, dmiModelServiceName, CmHandleState.ADVISED, new NcmpServiceCmHandle(cmHandleId: 'cm-handle-id-1'))
expect:
assert objectUnderTest.resolveDmiServiceName(requiredService) == expectedService
where:
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/DmiServiceUrlBuilderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/DmiServiceUrlBuilderSpec.groovy
index 964826be1..b3ea3b870 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/DmiServiceUrlBuilderSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/DmiServiceUrlBuilderSpec.groovy
@@ -20,6 +20,8 @@
package org.onap.cps.ncmp.api.utils
+import org.onap.cps.ncmp.api.inventory.CmHandleState
+
import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
@@ -33,7 +35,7 @@ class DmiServiceUrlBuilderSpec extends Specification {
@Shared
YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle('dmiServiceName',
- 'dmiDataServiceName', 'dmiModuleServiceName', new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id'))
+ 'dmiDataServiceName', 'dmiModuleServiceName', CmHandleState.ADVISED , new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id'))
NcmpConfiguration.DmiProperties dmiProperties = new NcmpConfiguration.DmiProperties()
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/MessagingSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/MessagingSpec.groovy
new file mode 100644
index 000000000..097834afc
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/MessagingSpec.groovy
@@ -0,0 +1,71 @@
+/*
+ * ============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.utils
+
+import org.apache.kafka.common.serialization.StringDeserializer
+import org.apache.kafka.common.serialization.StringSerializer
+import org.springframework.kafka.core.DefaultKafkaProducerFactory
+import org.springframework.kafka.core.KafkaTemplate
+import org.springframework.kafka.support.serializer.JsonSerializer
+import org.springframework.test.context.DynamicPropertyRegistry
+import org.springframework.test.context.DynamicPropertySource
+import org.testcontainers.containers.KafkaContainer
+import org.testcontainers.utility.DockerImageName
+import spock.lang.Specification
+
+class MessagingSpec extends Specification {
+
+ static {
+ Runtime.getRuntime().addShutdownHook(new Thread(kafkaTestContainer::stop))
+ }
+
+ def setupSpec() {
+ kafkaTestContainer.start()
+ }
+
+ static kafkaTestContainer = new KafkaContainer(DockerImageName.parse('confluentinc/cp-kafka:6.2.1'))
+
+ def producerConfigProperties() {
+ return [('bootstrap.servers'): kafkaTestContainer.getBootstrapServers().split(',')[0],
+ ('retries') : 0,
+ ('batch-size') : 16384,
+ ('linger.ms') : 1,
+ ('buffer.memory') : 33554432,
+ ('key.serializer') : StringSerializer,
+ ('value.serializer') : JsonSerializer]
+ }
+
+ def consumerConfigProperties(consumerGroupId) {
+ return [('bootstrap.servers') : kafkaTestContainer.getBootstrapServers().split(',')[0],
+ ('key.deserializer') : StringDeserializer,
+ ('value.deserializer'): StringDeserializer,
+ ('auto.offset.reset') : 'earliest',
+ ('group.id') : consumerGroupId
+ ]
+ }
+
+ def kafkaTemplate = new KafkaTemplate<>(new DefaultKafkaProducerFactory<Integer, String>(producerConfigProperties()))
+
+ @DynamicPropertySource
+ static void registerKafkaProperties(DynamicPropertyRegistry dynamicPropertyRegistry) {
+ dynamicPropertyRegistry.add('spring.kafka.bootstrap-servers', kafkaTestContainer::getBootstrapServers)
+ }
+}
diff --git a/cps-ncmp-service/src/test/resources/expectedNcmpEvent.json b/cps-ncmp-service/src/test/resources/expectedNcmpEvent.json
new file mode 100644
index 000000000..903bc3aab
--- /dev/null
+++ b/cps-ncmp-service/src/test/resources/expectedNcmpEvent.json
@@ -0,0 +1,21 @@
+{
+ "eventId": "test-uuid",
+ "eventCorrelationId": "cmhandle-as-correlationid",
+ "eventTime": "2022-12-31T20:30:40.000+0000",
+ "eventSource": "org.onap.ncmp",
+ "eventType": "org.onap.ncmp.cmhandle.lcm.event",
+ "eventSchema": "org.onap.ncmp.cmhandle.lcm.event:v1",
+ "event": {
+ "cmHandleId": "cmhandle-test",
+ "operation": "CREATE",
+ "cmhandle-state": "READY",
+ "cmhandle-properties": [
+ {
+ "publicProperty1": "value1"
+ },
+ {
+ "publicProperty2": "value2"
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
index 2e7bb7e96..20a39f98e 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
@@ -23,11 +23,12 @@
package org.onap.cps.spi.impl;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
-import java.util.Set;
import java.util.stream.Collectors;
import javax.transaction.Transactional;
-import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.onap.cps.spi.CpsAdminPersistenceService;
import org.onap.cps.spi.entities.AnchorEntity;
import org.onap.cps.spi.entities.DataspaceEntity;
@@ -35,26 +36,25 @@ import org.onap.cps.spi.entities.SchemaSetEntity;
import org.onap.cps.spi.entities.YangResourceModuleReference;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.spi.exceptions.DataspaceInUseException;
+import org.onap.cps.spi.exceptions.DataspaceNotFoundException;
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;
+@Slf4j
@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) {
@@ -117,7 +117,13 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
@Override
public Collection<Anchor> queryAnchors(final String dataspaceName, final Collection<String> inputModuleNames) {
- validateDataspaceAndModuleNames(dataspaceName, inputModuleNames);
+ try {
+ validateDataspaceAndModuleNames(dataspaceName, inputModuleNames);
+ } catch (DataspaceNotFoundException | ModuleNamesNotFoundException e) {
+ log.info("Module search encountered unknown dataspace or modulename, treating this as nothing found");
+ return Collections.emptySet();
+ }
+
final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
final Collection<AnchorEntity> anchorEntities = anchorRepository
.getAnchorsByDataspaceIdAndModuleNames(dataspaceEntity.getId(), inputModuleNames, inputModuleNames.size());
@@ -136,11 +142,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);
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
index ded234bb4..117cb43b4 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
@@ -48,6 +48,8 @@ import org.onap.cps.spi.FetchDescendantsOption;
import org.onap.cps.spi.entities.AnchorEntity;
import org.onap.cps.spi.entities.DataspaceEntity;
import org.onap.cps.spi.entities.FragmentEntity;
+import org.onap.cps.spi.entities.SchemaSetEntity;
+import org.onap.cps.spi.entities.YangResourceEntity;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.spi.exceptions.ConcurrencyException;
import org.onap.cps.spi.exceptions.CpsAdminException;
@@ -60,6 +62,8 @@ import org.onap.cps.spi.repository.DataspaceRepository;
import org.onap.cps.spi.repository.FragmentRepository;
import org.onap.cps.spi.utils.SessionManager;
import org.onap.cps.utils.JsonObjectMapper;
+import org.onap.cps.yang.YangTextSchemaSourceSetBuilder;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
@@ -85,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);
}
}
@@ -121,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) {
@@ -139,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());
@@ -153,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)) {
@@ -189,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;
@@ -199,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
@@ -222,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()) {
@@ -242,31 +246,42 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
}
private DataNode toDataNode(final FragmentEntity fragmentEntity,
- final FetchDescendantsOption fetchDescendantsOption) {
+ final FetchDescendantsOption fetchDescendantsOption) {
final List<DataNode> childDataNodes = getChildDataNodes(fragmentEntity, fetchDescendantsOption);
Map<String, Object> leaves = new HashMap<>();
if (fragmentEntity.getAttributes() != null) {
leaves = jsonObjectMapper.convertJsonString(fragmentEntity.getAttributes(), Map.class);
}
return new DataNodeBuilder()
- .withXpath(fragmentEntity.getXpath())
- .withLeaves(leaves)
- .withChildDataNodes(childDataNodes).build();
+ .withModuleNamePrefix(getFirstModuleName(fragmentEntity))
+ .withXpath(fragmentEntity.getXpath())
+ .withLeaves(leaves)
+ .withChildDataNodes(childDataNodes).build();
+ }
+
+ private String getFirstModuleName(final FragmentEntity fragmentEntity) {
+ final SchemaSetEntity schemaSetEntity = fragmentEntity.getAnchor().getSchemaSet();
+ final Map<String, String> yangResourceNameToContent =
+ schemaSetEntity.getYangResources().stream().collect(
+ Collectors.toMap(YangResourceEntity::getName, YangResourceEntity::getContent));
+ final SchemaContext schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent)
+ .getSchemaContext();
+ return schemaContext.getModules().iterator().next().getName();
}
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);
@@ -280,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<>();
@@ -300,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);
@@ -318,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);
}
@@ -338,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
@@ -356,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;
@@ -372,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 {
@@ -385,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);
}
}
@@ -398,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;
}
@@ -409,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;
}
@@ -417,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);
@@ -457,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();
@@ -465,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) {
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
index 3719256fc..cbeb1b76f 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
@@ -66,6 +66,7 @@ import org.opendaylight.yangtools.yang.parser.rfc7950.repo.YangModelDependencyIn
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
+import org.springframework.retry.support.RetrySynchronizationManager;
import org.springframework.stereotype.Component;
@Slf4j
@@ -219,9 +220,12 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ
convertToDuplicatedYangResourceException(
dataIntegrityViolationException, newYangResourceEntities);
convertedException.ifPresent(
- e -> log.warn(
- "Cannot persist duplicated yang resource. "
- + "System will attempt this method up to 5 times.", e));
+ e -> {
+ int retryCount = RetrySynchronizationManager.getContext() == null ? 0
+ : RetrySynchronizationManager.getContext().getRetryCount();
+ log.warn("Cannot persist duplicated yang resource. System will attempt this method "
+ + "up to 5 times. Current retry count : {}", ++retryCount, e);
+ });
throw convertedException.isPresent() ? convertedException.get() : dataIntegrityViolationException;
}
}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java
index 4bc9dd960..5e4de7fec 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java
@@ -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);
-
}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java
index f85dea3a7..681bbcdde 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java
@@ -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();
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy
index 2de087fc2..e03735003 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy
@@ -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
@@ -176,28 +174,17 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase {
@Sql([CLEAR_DATA, SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES])
def 'Query anchors that have #scenario.'() {
when: 'all anchor are retrieved for the given dataspace name and module names'
- def anchors = objectUnderTest.queryAnchors('dataspace-1', inputModuleNames)
+ def anchors = objectUnderTest.queryAnchors(inputDataspaceName, inputModuleNames)
then: 'the expected anchors are returned'
anchors.size() == expectedAnchors.size()
anchors.containsAll(expectedAnchors)
where: 'the following data is used'
- scenario | inputModuleNames || expectedAnchors
- 'one module' | ['module-name-1'] || [buildAnchor('anchor-2', 'dataspace-1', 'schema-set-2'), buildAnchor('anchor-1', 'dataspace-1', 'schema-set-1')]
- 'two modules' | ['module-name-1', 'module-name-2'] || [buildAnchor('anchor-2', 'dataspace-1', 'schema-set-2'), buildAnchor('anchor-1', 'dataspace-1', 'schema-set-1')]
- 'no anchors for all three modules' | ['module-name-1', 'module-name-2', 'module-name-3'] || []
- }
-
- @Sql([CLEAR_DATA, SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES])
- def 'Query all anchors for an #scenario.'() {
- when: 'attempt to query anchors'
- objectUnderTest.queryAnchors(dataspaceName, moduleNames)
- then: 'the correct exception is thrown with the relevant details'
- def thrownException = thrown(expectedException)
- thrownException.details.contains(expectedMessageDetails)
- where: 'the following data is used'
- scenario | dataspaceName | moduleNames || expectedException | expectedMessageDetails | messageDoesNotContain
- 'unknown dataspace' | 'db-does-not-exist' | ['does-not-matter'] || DataspaceNotFoundException | 'db-does-not-exist' | 'does-not-matter'
- 'unknown module and known module' | 'dataspace-1' | ['module-name-1', 'module-does-not-exist'] || ModuleNamesNotFoundException | 'module-does-not-exist' | 'module-name-1'
+ scenario | inputDataspaceName | inputModuleNames || expectedAnchors
+ 'one module' | 'dataspace-1' | ['module-name-1'] || [buildAnchor('anchor-2', 'dataspace-1', 'schema-set-2'), buildAnchor('anchor-1', 'dataspace-1', 'schema-set-1')]
+ 'two modules' | 'dataspace-1' | ['module-name-1', 'module-name-2'] || [buildAnchor('anchor-2', 'dataspace-1', 'schema-set-2'), buildAnchor('anchor-1', 'dataspace-1', 'schema-set-1')]
+ 'no anchors for all three modules' | 'dataspace-1' | ['module-name-1', 'module-name-2', 'module-name-3'] || []
+ 'unknown dataspace' | 'db-does-not-exist' | ['does-not-matter'] || []
+ 'unknown module and known module' | 'dataspace-1' | ['module-name-1', 'module-does-not-exist'] || []
}
def buildAnchor(def anchorName, def dataspaceName, def SchemaSetName) {
@@ -225,21 +212,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
- }
}
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy
index a96b6aff9..bb80199d0 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy
@@ -22,7 +22,11 @@ package org.onap.cps.spi.impl
import com.fasterxml.jackson.databind.ObjectMapper
import org.hibernate.StaleStateException
import org.onap.cps.spi.FetchDescendantsOption
+import org.onap.cps.spi.entities.AnchorEntity
+import org.onap.cps.spi.entities.DataspaceEntity
import org.onap.cps.spi.entities.FragmentEntity
+import org.onap.cps.spi.entities.SchemaSetEntity
+import org.onap.cps.spi.entities.YangResourceEntity
import org.onap.cps.spi.exceptions.ConcurrencyException
import org.onap.cps.spi.exceptions.DataValidationException
import org.onap.cps.spi.model.DataNodeBuilder
@@ -31,6 +35,10 @@ import org.onap.cps.spi.repository.DataspaceRepository
import org.onap.cps.spi.repository.FragmentRepository
import org.onap.cps.spi.utils.SessionManager
import org.onap.cps.utils.JsonObjectMapper
+import org.onap.cps.yang.YangTextSchemaSourceSet
+import org.onap.cps.yang.YangTextSchemaSourceSetBuilder
+import org.opendaylight.yangtools.yang.model.api.SchemaContext
+import spock.lang.Shared
import spock.lang.Specification
class CpsDataPersistenceServiceSpec extends Specification {
@@ -44,6 +52,25 @@ class CpsDataPersistenceServiceSpec extends Specification {
def objectUnderTest = new CpsDataPersistenceServiceImpl(
mockDataspaceRepository, mockAnchorRepository, mockFragmentRepository, jsonObjectMapper,mockSessionManager)
+ @Shared
+ def NEW_RESOURCE_CONTENT = 'module stores {\n' +
+ ' yang-version 1.1;\n' +
+ ' namespace "org:onap:ccsdk:sample";\n' +
+ '\n' +
+ ' prefix book-store;\n' +
+ '\n' +
+ ' revision "2020-09-15" {\n' +
+ ' description\n' +
+ ' "Sample Model";\n' +
+ ' }' +
+ '}'
+
+ @Shared
+ def yangResourceSet = [new YangResourceEntity(moduleName: 'moduleName', content: NEW_RESOURCE_CONTENT,
+ name: 'sampleYangResource'
+ )] as Set
+
+
def 'Handling of StaleStateException (caused by concurrent updates) during data node tree update.'() {
def parentXpath = '/parent-01'
@@ -51,67 +78,68 @@ class CpsDataPersistenceServiceSpec extends Specification {
def myAnchorName = 'my-anchor'
given: 'data node object'
- def submittedDataNode = new DataNodeBuilder()
- .withXpath(parentXpath)
- .withLeaves(['leaf-name': 'leaf-value'])
- .build()
+ def submittedDataNode = new DataNodeBuilder()
+ .withXpath(parentXpath)
+ .withLeaves(['leaf-name': 'leaf-value'])
+ .build()
and: 'fragment to be updated'
- mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, _) >> {
- def fragmentEntity = new FragmentEntity()
- fragmentEntity.setXpath(parentXpath)
- fragmentEntity.setChildFragments(Collections.emptySet())
- return fragmentEntity
- }
+ mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, _) >> {
+ def fragmentEntity = new FragmentEntity()
+ fragmentEntity.setXpath(parentXpath)
+ fragmentEntity.setChildFragments(Collections.emptySet())
+ return fragmentEntity
+ }
and: 'data node is concurrently updated by another transaction'
- mockFragmentRepository.save(_) >> { throw new StaleStateException("concurrent updates") }
+ mockFragmentRepository.save(_) >> { throw new StaleStateException("concurrent updates") }
when: 'attempt to update data node'
- objectUnderTest.replaceDataNodeTree(myDataspaceName, myAnchorName, submittedDataNode)
+ objectUnderTest.replaceDataNodeTree(myDataspaceName, myAnchorName, submittedDataNode)
then: 'concurrency exception is thrown'
- def concurrencyException = thrown(ConcurrencyException)
- assert concurrencyException.getDetails().contains(myDataspaceName)
- assert concurrencyException.getDetails().contains(myAnchorName)
- assert concurrencyException.getDetails().contains(parentXpath)
+ def concurrencyException = thrown(ConcurrencyException)
+ assert concurrencyException.getDetails().contains(myDataspaceName)
+ assert concurrencyException.getDetails().contains(myAnchorName)
+ assert concurrencyException.getDetails().contains(parentXpath)
}
def 'Retrieving a data node with a property JSON value of #scenario'() {
given: 'a fragment with a property JSON value of #scenario'
mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, _) >> {
new FragmentEntity(childFragments: Collections.emptySet(),
- attributes: "{\"some attribute\": ${dataString}}")
+ attributes: "{\"some attribute\": ${dataString}}",
+ anchor: new AnchorEntity(schemaSet: new SchemaSetEntity(yangResources: yangResourceSet )))
}
when: 'getting the data node represented by this fragment'
- def dataNode = objectUnderTest.getDataNode('my-dataspace', 'my-anchor',
- '/parent-01', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
+ def dataNode = objectUnderTest.getDataNode('my-dataspace', 'my-anchor',
+ '/parent-01', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
then: 'the leaf is of the correct value and data type'
- def attributeValue = dataNode.leaves.get('some attribute')
- assert attributeValue == expectedValue
- assert attributeValue.class == expectedDataClass
+ def attributeValue = dataNode.leaves.get('some attribute')
+ assert attributeValue == expectedValue
+ assert attributeValue.class == expectedDataClass
where: 'the following Data Type is passed'
- scenario | dataString || expectedValue | expectedDataClass
- 'just numbers' | '15174' || 15174 | Integer
- 'number with dot' | '15174.32' || 15174.32 | Double
- 'number with 0 value after dot' | '15174.0' || 15174.0 | Double
- 'number with 0 value before dot' | '0.32' || 0.32 | Double
- 'number higher than max int' | '2147483648' || 2147483648 | Long
- 'just text' | '"Test"' || 'Test' | String
- 'number with exponent' | '1.2345e5' || 1.2345e5 | Double
- 'number higher than max int with dot' | '123456789101112.0' || 123456789101112.0 | Double
- 'text and numbers' | '"String = \'1234\'"' || "String = '1234'" | String
- 'number as String' | '"12345"' || '12345' | String
+ scenario | dataString || expectedValue | expectedDataClass
+ 'just numbers' | '15174' || 15174 | Integer
+ 'number with dot' | '15174.32' || 15174.32 | Double
+ 'number with 0 value after dot' | '15174.0' || 15174.0 | Double
+ 'number with 0 value before dot' | '0.32' || 0.32 | Double
+ 'number higher than max int' | '2147483648' || 2147483648 | Long
+ 'just text' | '"Test"' || 'Test' | String
+ 'number with exponent' | '1.2345e5' || 1.2345e5 | Double
+ 'number higher than max int with dot' | '123456789101112.0' || 123456789101112.0 | Double
+ 'text and numbers' | '"String = \'1234\'"' || "String = '1234'" | String
+ 'number as String' | '"12345"' || '12345' | String
}
def 'Retrieving a data node with invalid JSON'() {
given: 'a fragment with invalid JSON'
- mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, _) >> {
- new FragmentEntity(childFragments: Collections.emptySet(), attributes: '{invalid json')
- }
+ mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, _) >> {
+ new FragmentEntity(childFragments: Collections.emptySet(), attributes: '{invalid json')
+ }
when: 'getting the data node represented by this fragment'
- def dataNode = objectUnderTest.getDataNode('my-dataspace', 'my-anchor',
- '/parent-01', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
+ def dataNode = objectUnderTest.getDataNode('my-dataspace', 'my-anchor',
+ '/parent-01', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
then: 'a data validation exception is thrown'
- thrown(DataValidationException)
+ thrown(DataValidationException)
}
def 'start session'() {
diff --git a/cps-ri/src/test/resources/data/cps-path-query.sql b/cps-ri/src/test/resources/data/cps-path-query.sql
index d1a62209e..c406203c8 100644
--- a/cps-ri/src/test/resources/data/cps-path-query.sql
+++ b/cps-ri/src/test/resources/data/cps-path-query.sql
@@ -25,6 +25,28 @@ INSERT INTO DATASPACE (ID, NAME) VALUES
INSERT INTO SCHEMA_SET (ID, NAME, DATASPACE_ID) VALUES
(2001, 'SCHEMA-SET-001', 1001);
+INSERT INTO YANG_RESOURCE (ID, NAME, CONTENT, CHECKSUM, MODULE_NAME, REVISION) VALUES
+ (4001, 'TEST','', 'SAMPLECHECKSUM','TESTMODULENAME', 'SAMPLEREVISION');
+
+UPDATE YANG_RESOURCE SET
+content = 'module stores {
+ yang-version 1.1;
+ namespace "org:onap:ccsdk:sample";
+
+ prefix book-store;
+
+ revision "2020-09-15" {
+ description
+ "Sample Model";
+ }
+ }
+'
+where ID = 4001;
+
+
+INSERT INTO SCHEMA_SET_YANG_RESOURCES (SCHEMA_SET_ID, YANG_RESOURCE_ID) VALUES
+ (2001, 4001);
+
INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES
(1003, 'ANCHOR-004', 1001, 2001);
diff --git a/cps-ri/src/test/resources/data/fragment.sql b/cps-ri/src/test/resources/data/fragment.sql
index 410654106..fd05900e2 100755
--- a/cps-ri/src/test/resources/data/fragment.sql
+++ b/cps-ri/src/test/resources/data/fragment.sql
@@ -27,6 +27,27 @@ INSERT INTO DATASPACE (ID, NAME) VALUES
INSERT INTO SCHEMA_SET (ID, NAME, DATASPACE_ID) VALUES
(2001, 'SCHEMA-SET-001', 1001);
+INSERT INTO YANG_RESOURCE (ID, NAME, CONTENT, CHECKSUM, MODULE_NAME, REVISION) VALUES
+ (4001, 'TEST','', 'SAMPLECHECKSUM','TESTMODULENAME', 'SAMPLEREVISION');
+
+UPDATE YANG_RESOURCE SET
+content = 'module stores {
+ yang-version 1.1;
+ namespace "org:onap:ccsdk:sample";
+
+ prefix book-store;
+
+ revision "2020-09-15" {
+ description
+ "Sample Model";
+ }
+ }
+'
+where ID = 4001;
+
+INSERT INTO SCHEMA_SET_YANG_RESOURCES (SCHEMA_SET_ID, YANG_RESOURCE_ID) VALUES
+ (2001, 4001);
+
INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES
(3001, 'ANCHOR-001', 1001, 2001),
(3003, 'ANCHOR-003', 1001, 2001),
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java b/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java
index 2106f1584..ab3373248 100755
--- a/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java
@@ -23,11 +23,9 @@
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);
}
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
index 93c96ec65..cde25a9f9 100644
--- a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
@@ -210,5 +210,4 @@ public interface CpsDataService {
* @param timeoutInMilliseconds lock attempt timeout in milliseconds
*/
void lockAnchor(String sessionID, String dataspaceName, String anchorName, Long timeoutInMilliseconds);
-
}
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java
index 762754f9a..a67dfe503 100755
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java
@@ -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);
- }
}
diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java
index 25167e844..db2d2b2d4 100755
--- a/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java
@@ -23,10 +23,8 @@
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.
@@ -76,7 +74,7 @@ public interface CpsAdminPersistenceService {
/**
* Query anchor names for the given module names in the provided dataspace.
- *
+ * If dataspace or one of the given module names does not exists, return with an empty collection.
*
* @param dataspaceName dataspace name
* @param moduleNames a collection of module names
@@ -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);
}
diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java
index fd660e675..b27a2976d 100644
--- a/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java
@@ -173,5 +173,4 @@ public interface CpsDataPersistenceService {
* @param timeoutInMilliseconds lock attempt timeout in milliseconds
*/
void lockAnchor(String sessionID, String dataspaceName, String anchorName, Long timeoutInMilliseconds);
-
}
diff --git a/cps-service/src/main/java/org/onap/cps/spi/model/CmHandleQueryParameters.java b/cps-service/src/main/java/org/onap/cps/spi/model/CmHandleQueryParameters.java
index ff4e62763..cf364db3a 100644
--- a/cps-service/src/main/java/org/onap/cps/spi/model/CmHandleQueryParameters.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/model/CmHandleQueryParameters.java
@@ -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
index 000000000..4eee7db13
--- /dev/null
+++ b/cps-service/src/main/java/org/onap/cps/spi/model/ConditionProperties.java
@@ -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/DataNode.java b/cps-service/src/main/java/org/onap/cps/spi/model/DataNode.java
index 43aa06b81..d80306bae 100644
--- a/cps-service/src/main/java/org/onap/cps/spi/model/DataNode.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/model/DataNode.java
@@ -42,6 +42,7 @@ public class DataNode {
private String anchorName;
private ModuleReference moduleReference;
private String xpath;
+ private String moduleNamePrefix;
private Map<String, Object> leaves = Collections.emptyMap();
private Collection<String> xpathsChildren;
private Collection<DataNode> childDataNodes = Collections.emptySet();
diff --git a/cps-service/src/main/java/org/onap/cps/spi/model/DataNodeBuilder.java b/cps-service/src/main/java/org/onap/cps/spi/model/DataNodeBuilder.java
index 4a9957deb..f2bde03a0 100644
--- a/cps-service/src/main/java/org/onap/cps/spi/model/DataNodeBuilder.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/model/DataNodeBuilder.java
@@ -2,6 +2,7 @@
* ============LICENSE_START=======================================================
* Copyright (C) 2021 Bell Canada. All rights reserved.
* Modifications Copyright (C) 2021 Pantheon.tech
+ * Modifications 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.
@@ -45,6 +46,7 @@ public class DataNodeBuilder {
private NormalizedNode<?, ?> normalizedNodeTree;
private String xpath;
+ private String moduleNamePrefix;
private String parentNodeXpath = "";
private Map<String, Object> leaves = Collections.emptyMap();
private Collection<DataNode> childDataNodes = Collections.emptySet();
@@ -84,6 +86,17 @@ public class DataNodeBuilder {
}
/**
+ * To use module name for prefix for creating {@link DataNode}.
+ *
+ * @param moduleNamePrefix module name as prefix
+ * @return DataNodeBuilder
+ */
+ public DataNodeBuilder withModuleNamePrefix(final String moduleNamePrefix) {
+ this.moduleNamePrefix = moduleNamePrefix;
+ return this;
+ }
+
+ /**
* To use attributes for creating {@link DataNode}.
*
* @param leaves for the data node
@@ -136,6 +149,7 @@ public class DataNodeBuilder {
private DataNode buildFromAttributes() {
final var dataNode = new DataNode();
dataNode.setXpath(xpath);
+ dataNode.setModuleNamePrefix(moduleNamePrefix);
dataNode.setLeaves(leaves);
dataNode.setChildDataNodes(childDataNodes);
return dataNode;
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
index 000000000..2bd2b774d
--- /dev/null
+++ b/cps-service/src/main/java/org/onap/cps/spi/model/DataNodeIdentifier.java
@@ -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
index 000000000..c510a73af
--- /dev/null
+++ b/cps-service/src/main/java/org/onap/cps/utils/CmHandleQueryRestParametersValidator.java
@@ -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);
+ }
+
+}
diff --git a/cps-service/src/main/java/org/onap/cps/utils/DataMapUtils.java b/cps-service/src/main/java/org/onap/cps/utils/DataMapUtils.java
index 42719d9b3..ff5204ff6 100644
--- a/cps-service/src/main/java/org/onap/cps/utils/DataMapUtils.java
+++ b/cps-service/src/main/java/org/onap/cps/utils/DataMapUtils.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021 Pantheon.tech
- * Modifications (C) 2021 Nordix Foundation
+ * Modifications (C) 2021-2022 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@ public class DataMapUtils {
*/
public static Map<String, Object> toDataMapWithIdentifier(final DataNode dataNode) {
return ImmutableMap.<String, Object>builder()
- .put(getNodeIdentifier(dataNode.getXpath()), toDataMap(dataNode))
+ .put(getNodeIdentifierWithPrefix(dataNode.getXpath(), dataNode.getModuleNamePrefix()), toDataMap(dataNode))
.build();
}
@@ -96,6 +96,13 @@ public class DataMapUtils {
return toIndex > 0 ? xpath.substring(fromIndex, toIndex) : xpath.substring(fromIndex);
}
+ private static String getNodeIdentifierWithPrefix(final String xpath, final String moduleNamePrefix) {
+ if (moduleNamePrefix != null) {
+ return moduleNamePrefix + ":" + getNodeIdentifier(xpath);
+ }
+ return getNodeIdentifier(xpath);
+ }
+
private static boolean isContainerNode(final String xpath) {
return !isListElement(xpath);
}
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy
index 33868ccf0..def99e21f 100755
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy
@@ -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/spi/model/DataNodeBuilderSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy
index ce54ead2a..16d4efc27 100644
--- a/cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy
@@ -22,6 +22,7 @@ package org.onap.cps.spi.model
import org.onap.cps.TestUtils
import org.onap.cps.spi.model.DataNodeBuilder
+import org.onap.cps.utils.DataMapUtils
import org.onap.cps.utils.YangUtils
import org.onap.cps.yang.YangTextSchemaSourceSetBuilder
import org.opendaylight.yangtools.yang.common.QName
@@ -172,6 +173,22 @@ class DataNodeBuilderSpec extends Specification {
'NormalizedNode is an unsupported type' | 'not supported' | Mock(NormalizedNode) | 0 | [ ]
}
+ def 'Use of adding the module name prefix attribute of data node.'() {
+ when: 'data node is built with a prefix'
+ def testDataNode = new DataNodeBuilder()
+ .withModuleNamePrefix('sampleModuleNamePrefix')
+ .withXpath(xPath)
+ .withLeaves(sampleLeaves)
+ .build()
+ then: 'the result when node request is a #scenario includes the correct prefix'
+ def result = new DataMapUtils().toDataMapWithIdentifier(testDataNode)
+ result.toString() == expectedResult
+ where: 'the following parameters are used'
+ scenario | xPath | sampleLeaves | expectedResult
+ 'list attribute' | '/test-tree/branch[@name=\'Right\']/nest' | [name: 'Big', birds: ['Owl']] | '{sampleModuleNamePrefix:nest={name=Big, birds=[Owl]}}'
+ 'container xpath' | '/test-tree/branch[@name=\'Left\']' | [name: 'Left'] | '{sampleModuleNamePrefix:branch={name=Left}}'
+ }
+
def static assertLeavesMaps(actualLeavesMap, expectedLeavesMap) {
expectedLeavesMap.each { key, value ->
{
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
index 000000000..645829b2a
--- /dev/null
+++ b/cps-service/src/test/groovy/org/onap/cps/utils/CmHandleQueryRestParametersValidatorSpec.groovy
@@ -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']
+ }
+}
diff --git a/cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy
index 90563c0c1..24e8061b5 100644
--- a/cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021 Pantheon.tech
- * Modifications Copyright (C) 2020 Nordix Foundation
+ * Modifications Copyright (C) 2020-2022 Nordix Foundation
* Modifications Copyright (C) 2022 Bell Canada.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,13 +29,13 @@ class DataMapUtilsSpec extends Specification {
def noChildren = []
def dataNode = buildDataNode(
- "/parent",[parentLeaf:'parentLeafValue', parentLeafList:['parentLeafListEntry1','parentLeafListEntry2']],[
- buildDataNode('/parent/child-list[@id=1]',[listElementLeaf:'listElement1leafValue'],noChildren),
- buildDataNode('/parent/child-list[@id=2]',[listElementLeaf:'listElement2leafValue'],noChildren),
- buildDataNode('/parent/child-object',[childLeaf:'childLeafValue'],
- [buildDataNode('/parent/child-object/grand-child-object',[grandChildLeaf:'grandChildLeafValue'],noChildren)]
- ),
- ])
+ "/parent",[parentLeaf:'parentLeafValue', parentLeafList:['parentLeafListEntry1','parentLeafListEntry2']],[
+ buildDataNode('/parent/child-list[@id=1]',[listElementLeaf:'listElement1leafValue'],noChildren),
+ buildDataNode('/parent/child-list[@id=2]',[listElementLeaf:'listElement2leafValue'],noChildren),
+ buildDataNode('/parent/child-object',[childLeaf:'childLeafValue'],
+ [buildDataNode('/parent/child-object/grand-child-object',[grandChildLeaf:'grandChildLeafValue'],noChildren)]
+ ),
+ ])
static def buildDataNode(xpath, leaves, children) {
return new DataNodeBuilder().withXpath(xpath).withLeaves(leaves).withChildDataNodes(children).build()
@@ -81,4 +81,16 @@ class DataMapUtilsSpec extends Specification {
and: 'leaves for grandchild element is populated under its node identifier'
parentNode.'child-object'.'grand-child-object'.grandChildLeaf == 'grandChildLeafValue'
}
+
+ def 'Adding prefix to data node identifier.'() {
+ when: 'a valid xPath is passed to the addPrefixToXpath method'
+ def result = new DataMapUtils().getNodeIdentifierWithPrefix(xPath,'sampleModuleName')
+ then: 'the correct modified node identifier is given'
+ assert result == expectedNodeIdentifier
+ where: 'the following parameters are used'
+ scenario | xPath | expectedNodeIdentifier
+ 'container xpath' | '/bookstore' | 'sampleModuleName:bookstore'
+ 'xpath contains list attribute' | '/bookstore/categories[@code=1]' | 'sampleModuleName:categories'
+ }
}
+
diff --git a/csit/plans/cps/testplan.txt b/csit/plans/cps/testplan.txt
index d4615e701..c0cf4512d 100644
--- a/csit/plans/cps/testplan.txt
+++ b/csit/plans/cps/testplan.txt
@@ -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
diff --git a/csit/tests/public-properties-query/public-properties-query.robot b/csit/tests/cm-handle-query/cm-handle-query.robot
index 3a640871b..3adc25362 100644
--- a/csit/tests/public-properties-query/public-properties-query.robot
+++ b/csit/tests/cm-handle-query/cm-handle-query.robot
@@ -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]>
diff --git a/csit/tests/cps-data/cps-data.robot b/csit/tests/cps-data/cps-data.robot
index 55667c3c1..844b5d53f 100644
--- a/csit/tests/cps-data/cps-data.robot
+++ b/csit/tests/cps-data/cps-data.robot
@@ -1,6 +1,7 @@
# ============LICENSE_START=======================================================
# Copyright (c) 2021 Pantheon.tech.
# Modifications Copyright (C) 2022 Bell Canada.
+# Modifications 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.
@@ -46,7 +47,7 @@ Get Data Node by XPath
${params}= Create Dictionary xpath=/test-tree/branch[@name='Left']/nest
${headers}= Create Dictionary Authorization=${auth}
${response}= Get On Session CPS_URL ${uri} params=${params} headers=${headers} expected_status=200
- ${responseJson}= Set Variable ${response.json()['nest']}
+ ${responseJson}= Set Variable ${response.json()['test-tree:nest']}
Should Be Equal As Strings ${responseJson['name']} Small
diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml
index f2f477fe1..9edea3526 100755
--- a/docker-compose/docker-compose.yml
+++ b/docker-compose/docker-compose.yml
@@ -112,6 +112,7 @@ services:
KAFKA_BOOTSTRAP_SERVER: kafka:9092
notification.data-updated.enabled: 'true'
NOTIFICATION_DATASPACE_FILTER_PATTERNS: '.*'
+ TIMERS_ADVISED-MODULES-SYNC_SLEEP-TIME-MS: 2000
restart: unless-stopped
depends_on:
- dbpostgresql