2  *  ============LICENSE_START=======================================================
 
   3  *  Copyright (C) 2022 Nordix Foundation
 
   4  *  ================================================================================
 
   5  *  Licensed under the Apache License, Version 2.0 (the "License");
 
   6  *  you may not use this file except in compliance with the License.
 
   7  *  You may obtain a copy of the License at
 
   9  *        http://www.apache.org/licenses/LICENSE-2.0
 
  11  *  Unless required by applicable law or agreed to in writing, software
 
  12  *  distributed under the License is distributed on an "AS IS" BASIS,
 
  13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  14  *  See the License for the specific language governing permissions and
 
  15  *  limitations under the License.
 
  17  *  SPDX-License-Identifier: Apache-2.0
 
  18  *  ============LICENSE_END=========================================================
 
  21 package org.onap.cps.ncmp.api.impl;
 
  23 import static org.onap.cps.ncmp.api.impl.utils.RestQueryParametersValidator.validateCpsPathConditionProperties;
 
  24 import static org.onap.cps.ncmp.api.impl.utils.RestQueryParametersValidator.validateModuleNameConditionProperties;
 
  25 import static org.onap.cps.ncmp.api.impl.utils.YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle;
 
  26 import static org.onap.cps.spi.FetchDescendantsOption.FETCH_DIRECT_CHILDREN_ONLY;
 
  27 import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
 
  29 import java.util.ArrayList;
 
  30 import java.util.Collection;
 
  31 import java.util.Collections;
 
  32 import java.util.HashMap;
 
  33 import java.util.HashSet;
 
  34 import java.util.List;
 
  37 import java.util.function.Function;
 
  38 import java.util.stream.Collectors;
 
  39 import lombok.RequiredArgsConstructor;
 
  40 import lombok.extern.slf4j.Slf4j;
 
  41 import org.onap.cps.cpspath.parser.PathParsingException;
 
  42 import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService;
 
  43 import org.onap.cps.ncmp.api.impl.utils.CmHandleQueryConditions;
 
  44 import org.onap.cps.ncmp.api.impl.utils.InventoryQueryConditions;
 
  45 import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
 
  46 import org.onap.cps.ncmp.api.inventory.CmHandleQueries;
 
  47 import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
 
  48 import org.onap.cps.ncmp.api.inventory.enums.PropertyType;
 
  49 import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters;
 
  50 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
 
  51 import org.onap.cps.spi.exceptions.DataValidationException;
 
  52 import org.onap.cps.spi.model.Anchor;
 
  53 import org.onap.cps.spi.model.ConditionProperties;
 
  54 import org.onap.cps.spi.model.DataNode;
 
  55 import org.springframework.stereotype.Service;
 
  59 @RequiredArgsConstructor
 
  60 public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCmHandlerQueryService {
 
  62     private static final Map<String, NcmpServiceCmHandle> NO_QUERY_TO_EXECUTE = null;
 
  63     private final CmHandleQueries cmHandleQueries;
 
  64     private final InventoryPersistence inventoryPersistence;
 
  67      * Query and return cm handles that match the given query parameters.
 
  69      * @param cmHandleQueryServiceParameters the cm handle query parameters
 
  70      * @return collection of cm handles
 
  73     public Set<NcmpServiceCmHandle> queryCmHandles(
 
  74             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
 
  76         if (cmHandleQueryServiceParameters.getCmHandleQueryParameters().isEmpty()) {
 
  77             return getAllCmHandles();
 
  80         final Map<String, NcmpServiceCmHandle> combinedQueryResult = executeInventoryQueries(
 
  81                 cmHandleQueryServiceParameters);
 
  83         return new HashSet<>(combineWithModuleNameQuery(cmHandleQueryServiceParameters, combinedQueryResult).values());
 
  87      * Query and return cm handles that match the given query parameters.
 
  89      * @param cmHandleQueryServiceParameters the cm handle query parameters
 
  90      * @return collection of cm handle ids
 
  93     public Set<String> queryCmHandleIds(
 
  94             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
 
  96         if (cmHandleQueryServiceParameters.getCmHandleQueryParameters().isEmpty()) {
 
  97             return getAllCmHandleIds();
 
 100         final Map<String, NcmpServiceCmHandle> combinedQueryResult = executeInventoryQueries(
 
 101                 cmHandleQueryServiceParameters);
 
 103         final Collection<String> moduleNamesForQuery =
 
 104                 getModuleNamesForQuery(cmHandleQueryServiceParameters.getCmHandleQueryParameters());
 
 105         if (moduleNamesForQuery.isEmpty()) {
 
 106             return combinedQueryResult.keySet();
 
 108         final Set<String> moduleNameQueryResult = getNamesOfAnchorsWithGivenModules(moduleNamesForQuery);
 
 110         if (combinedQueryResult == NO_QUERY_TO_EXECUTE) {
 
 111             return moduleNameQueryResult;
 
 114         moduleNameQueryResult.retainAll(combinedQueryResult.keySet());
 
 115         return moduleNameQueryResult;
 
 119     public Set<String> queryCmHandleIdsForInventory(
 
 120             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
 
 122         if (cmHandleQueryServiceParameters.getCmHandleQueryParameters().isEmpty()) {
 
 123             return getAllCmHandleIds();
 
 126         final Map<String, NcmpServiceCmHandle> publicPropertiesQueryResult = queryCmHandlesByPublicProperties(
 
 127                 cmHandleQueryServiceParameters);
 
 128         if (publicPropertiesQueryResult != null && publicPropertiesQueryResult.isEmpty()) {
 
 129             return Collections.emptySet();
 
 132         final Map<String, NcmpServiceCmHandle> privatePropertiesQueryResult = queryCmHandlesByPrivateProperties(
 
 133                 cmHandleQueryServiceParameters);
 
 134         if (privatePropertiesQueryResult != null && privatePropertiesQueryResult.isEmpty()) {
 
 135             return Collections.emptySet();
 
 138         final Map<String, NcmpServiceCmHandle> dmiPropertiesQueryResult = queryCmHandlesByDmiPlugin(
 
 139                 cmHandleQueryServiceParameters);
 
 140         if (dmiPropertiesQueryResult != null && dmiPropertiesQueryResult.isEmpty()) {
 
 141             return Collections.emptySet();
 
 144         final Map<String, NcmpServiceCmHandle> combinedResult =
 
 145               combineQueryResults(publicPropertiesQueryResult, privatePropertiesQueryResult, dmiPropertiesQueryResult);
 
 147         return combinedResult.keySet();
 
 150     private Map<String, NcmpServiceCmHandle> queryCmHandlesByDmiPlugin(
 
 151             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
 
 152         final Map<String, String> dmiPropertyQueryPairs =
 
 153                 getPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters(),
 
 154                         InventoryQueryConditions.CM_HANDLE_WITH_DMI_PLUGIN.getName());
 
 155         if (dmiPropertyQueryPairs.isEmpty()) {
 
 156             return NO_QUERY_TO_EXECUTE;
 
 159         final String dmiPluginIdentifierValue = dmiPropertyQueryPairs.get(
 
 160                 PropertyType.DMI_PLUGIN.getYangContainerName());
 
 162         final Set<NcmpServiceCmHandle> cmHandlesByDmiPluginIdentifier = cmHandleQueries
 
 163                 .getCmHandlesByDmiPluginIdentifier(dmiPluginIdentifierValue);
 
 165         return cmHandlesByDmiPluginIdentifier.stream()
 
 166                 .collect(Collectors.toMap(NcmpServiceCmHandle::getCmHandleId, cmH -> cmH));
 
 169     private Map<String, NcmpServiceCmHandle> queryCmHandlesByPrivateProperties(
 
 170             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
 
 172         final Map<String, String> privatePropertyQueryPairs =
 
 173                 getPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters(),
 
 174                         InventoryQueryConditions.HAS_ALL_ADDITIONAL_PROPERTIES.getName());
 
 176         return privatePropertyQueryPairs.isEmpty()
 
 177                 ? NO_QUERY_TO_EXECUTE
 
 178                 : cmHandleQueries.queryCmHandleAdditionalProperties(privatePropertyQueryPairs);
 
 181     private Map<String, NcmpServiceCmHandle> queryCmHandlesByPublicProperties(
 
 182             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
 
 184         final Map<String, String> publicPropertyQueryPairs =
 
 185                 getPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters(),
 
 186                         CmHandleQueryConditions.HAS_ALL_PROPERTIES.getConditionName());
 
 188         return publicPropertyQueryPairs.isEmpty()
 
 189                 ? NO_QUERY_TO_EXECUTE
 
 190                 : cmHandleQueries.queryCmHandlePublicProperties(publicPropertyQueryPairs);
 
 193     private Map<String, NcmpServiceCmHandle> combineQueryResults(
 
 194             final Map<String, NcmpServiceCmHandle> publicPropertiesQueryResult,
 
 195             final Map<String, NcmpServiceCmHandle> privatePropertiesQueryResult,
 
 196             final Map<String, NcmpServiceCmHandle> dmiPropertiesQueryResult) {
 
 198         final Map<String, NcmpServiceCmHandle> propertiesCombinedResult = cmHandleQueries
 
 199                 .combineCmHandleQueries(publicPropertiesQueryResult, privatePropertiesQueryResult);
 
 200         return cmHandleQueries
 
 201                 .combineCmHandleQueries(propertiesCombinedResult, dmiPropertiesQueryResult);
 
 204     private Map<String, NcmpServiceCmHandle> combineWithModuleNameQuery(
 
 205             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters,
 
 206             final Map<String, NcmpServiceCmHandle> previousQueryResult) {
 
 207         final Collection<String> moduleNamesForQuery =
 
 208                 getModuleNamesForQuery(cmHandleQueryServiceParameters.getCmHandleQueryParameters());
 
 209         if (moduleNamesForQuery.isEmpty()) {
 
 210             return previousQueryResult;
 
 212         final Collection<String> cmHandleIdsByModuleName = getNamesOfAnchorsWithGivenModules(moduleNamesForQuery);
 
 213         if (cmHandleIdsByModuleName.isEmpty()) {
 
 214             return Collections.emptyMap();
 
 216         final Map<String, NcmpServiceCmHandle> queryResult = new HashMap<>(cmHandleIdsByModuleName.size());
 
 217         if (previousQueryResult == NO_QUERY_TO_EXECUTE) {
 
 218             cmHandleIdsByModuleName.forEach(cmHandleId ->
 
 219                     queryResult.put(cmHandleId, createNcmpServiceCmHandle(
 
 220                             inventoryPersistence.getDataNode("/dmi-registry/cm-handles[@id='" + cmHandleId + "']")))
 
 224         previousQueryResult.keySet().retainAll(cmHandleIdsByModuleName);
 
 225         queryResult.putAll(previousQueryResult);
 
 229     private Map<String, NcmpServiceCmHandle> executeInventoryQueries(
 
 230             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
 
 231         final Map<String, String> cpsPath = getCpsPath(cmHandleQueryServiceParameters.getCmHandleQueryParameters());
 
 232         if (!validateCpsPathConditionProperties(cpsPath)) {
 
 233             return Collections.emptyMap();
 
 235         final Map<String, NcmpServiceCmHandle> cpsPathQueryResult;
 
 236         if (cpsPath.isEmpty()) {
 
 237             cpsPathQueryResult = NO_QUERY_TO_EXECUTE;
 
 240                 cpsPathQueryResult = cmHandleQueries.queryCmHandleDataNodesByCpsPath(
 
 241                                 cpsPath.get("cpsPath"), INCLUDE_ALL_DESCENDANTS)
 
 242                         .stream().map(this::createNcmpServiceCmHandle)
 
 243                         .collect(Collectors.toMap(NcmpServiceCmHandle::getCmHandleId,
 
 244                                 Function.identity()));
 
 245             } catch (final PathParsingException pathParsingException) {
 
 246                 throw new DataValidationException(pathParsingException.getMessage(), pathParsingException.getDetails(),
 
 247                         pathParsingException);
 
 249             if (cpsPathQueryResult.isEmpty()) {
 
 250                 return Collections.emptyMap();
 
 254         final Map<String, String> publicPropertyQueryPairs =
 
 255                 getPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters(),
 
 256                         CmHandleQueryConditions.HAS_ALL_PROPERTIES.getConditionName());
 
 257         final Map<String, NcmpServiceCmHandle> propertiesQueryResult = publicPropertyQueryPairs.isEmpty()
 
 258                 ? NO_QUERY_TO_EXECUTE : cmHandleQueries.queryCmHandlePublicProperties(publicPropertyQueryPairs);
 
 260         return cmHandleQueries.combineCmHandleQueries(cpsPathQueryResult, propertiesQueryResult);
 
 263     private Set<String> getNamesOfAnchorsWithGivenModules(final Collection<String> moduleNamesForQuery) {
 
 264         final Collection<Anchor> anchors = inventoryPersistence.queryAnchors(moduleNamesForQuery);
 
 265         return anchors.parallelStream().map(Anchor::getName).collect(Collectors.toSet());
 
 268     private Collection<String> getModuleNamesForQuery(final List<ConditionProperties> conditionProperties) {
 
 269         final List<String> result = new ArrayList<>();
 
 270         getConditions(conditionProperties, CmHandleQueryConditions.HAS_ALL_MODULES.getConditionName())
 
 271             .parallelStream().forEach(
 
 272                 conditionProperty -> {
 
 273                     validateModuleNameConditionProperties(conditionProperty);
 
 274                     result.add(conditionProperty.get("moduleName"));
 
 280     private Map<String, String> getCpsPath(final List<ConditionProperties> conditionProperties) {
 
 281         final Map<String, String> result = new HashMap<>();
 
 282         getConditions(conditionProperties, CmHandleQueryConditions.WITH_CPS_PATH.getConditionName()).forEach(
 
 287     private Map<String, String> getPropertyPairs(final List<ConditionProperties> conditionProperties,
 
 288                                                        final String queryProperty) {
 
 289         final Map<String, String> result = new HashMap<>();
 
 290         getConditions(conditionProperties, queryProperty).forEach(result::putAll);
 
 294     private List<Map<String, String>> getConditions(final List<ConditionProperties> conditionProperties,
 
 296         for (final ConditionProperties conditionProperty : conditionProperties) {
 
 297             if (conditionProperty.getConditionName().equals(name)) {
 
 298                 return conditionProperty.getConditionParameters();
 
 301         return Collections.emptyList();
 
 304     private Set<NcmpServiceCmHandle> getAllCmHandles() {
 
 305         return inventoryPersistence.getDataNode("/dmi-registry")
 
 306                 .getChildDataNodes().stream().map(this::createNcmpServiceCmHandle).collect(Collectors.toSet());
 
 309     private Set<String> getAllCmHandleIds() {
 
 310         return inventoryPersistence.getDataNode("/dmi-registry", FETCH_DIRECT_CHILDREN_ONLY)
 
 311                 .getChildDataNodes().stream().map(dataNode -> dataNode.getLeaves().get("id").toString())
 
 312                 .collect(Collectors.toSet());
 
 315     private NcmpServiceCmHandle createNcmpServiceCmHandle(final DataNode dataNode) {
 
 316         return convertYangModelCmHandleToNcmpServiceCmHandle(YangDataConverter
 
 317                 .convertCmHandleToYangModel(dataNode, dataNode.getLeaves().get("id").toString()));