2  *  ============LICENSE_START=======================================================
 
   3  *  Copyright (C) 2022-2025 OpenInfra Foundation Europe. All rights reserved.
 
   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.impl.inventory;
 
  23 import static org.onap.cps.api.parameters.FetchDescendantsOption.DIRECT_CHILDREN_ONLY;
 
  24 import static org.onap.cps.ncmp.impl.inventory.CmHandleQueryParametersValidator.validateCpsPathConditionProperties;
 
  25 import static org.onap.cps.ncmp.impl.inventory.CmHandleQueryParametersValidator.validateModuleNameConditionProperties;
 
  26 import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT;
 
  27 import static org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions.HAS_ALL_MODULES;
 
  28 import static org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions.HAS_ALL_PROPERTIES;
 
  29 import static org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions.WITH_CPS_PATH;
 
  30 import static org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions.WITH_TRUST_LEVEL;
 
  31 import static org.onap.cps.ncmp.impl.utils.YangDataConverter.toNcmpServiceCmHandle;
 
  33 import java.util.ArrayList;
 
  34 import java.util.Collection;
 
  35 import java.util.Collections;
 
  36 import java.util.HashMap;
 
  37 import java.util.List;
 
  39 import java.util.function.BiFunction;
 
  40 import java.util.stream.Collectors;
 
  41 import lombok.RequiredArgsConstructor;
 
  42 import org.onap.cps.api.exceptions.DataValidationException;
 
  43 import org.onap.cps.api.model.ConditionProperties;
 
  44 import org.onap.cps.api.model.DataNode;
 
  45 import org.onap.cps.cpspath.parser.PathParsingException;
 
  46 import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters;
 
  47 import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
 
  48 import org.onap.cps.ncmp.impl.inventory.models.InventoryQueryConditions;
 
  49 import org.onap.cps.ncmp.impl.inventory.models.PropertyType;
 
  50 import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
 
  51 import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelManager;
 
  52 import org.onap.cps.ncmp.impl.utils.YangDataConverter;
 
  53 import org.springframework.stereotype.Service;
 
  54 import reactor.core.publisher.Flux;
 
  57 @RequiredArgsConstructor
 
  58 public class ParameterizedCmHandleQueryServiceImpl implements ParameterizedCmHandleQueryService {
 
  60     private static final int FLUX_BUFFER_SIZE = 1000;
 
  61     private static final Collection<String> NO_QUERY_TO_EXECUTE = null;
 
  62     private final CmHandleQueryService cmHandleQueryService;
 
  63     private final InventoryPersistence inventoryPersistence;
 
  64     private final TrustLevelManager trustLevelManager;
 
  67     public Collection<String> queryCmHandleReferenceIds(
 
  68             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters,
 
  69             final boolean outputAlternateId) {
 
  70         return executeQueries(cmHandleQueryServiceParameters, outputAlternateId,
 
  71                 this::executeCpsPathQuery,
 
  72                 this::queryCmHandlesByPublicProperties,
 
  73                 this::executeModuleNameQuery,
 
  74                 this::queryCmHandlesByTrustLevel);
 
  78     public Collection<String> queryCmHandleIdsForInventory(
 
  79             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters,
 
  80             final boolean outputAlternateId) {
 
  81         return executeQueries(cmHandleQueryServiceParameters, outputAlternateId,
 
  82                 this::executeCpsPathQuery,
 
  83                 this::queryCmHandlesByPublicProperties,
 
  84                 this::queryCmHandlesByPrivateProperties,
 
  85                 this::queryCmHandlesByDmiPlugin);
 
  89     public Flux<NcmpServiceCmHandle> queryCmHandles(final CmHandleQueryServiceParameters queryParameters) {
 
  90         final Collection<String> cmHandleIds = queryCmHandleReferenceIds(queryParameters, false);
 
  91         return getNcmpServiceCmHandles(cmHandleIds);
 
  95     public Collection<NcmpServiceCmHandle> getAllCmHandlesWithoutProperties() {
 
  96         return toNcmpServiceCmHandles(inventoryPersistence.getDataNode(NCMP_DMI_REGISTRY_PARENT, DIRECT_CHILDREN_ONLY));
 
  99     private Collection<NcmpServiceCmHandle> toNcmpServiceCmHandles(final Collection<DataNode> dataNodes) {
 
 100         final DataNode dataNode = dataNodes.iterator().next();
 
 101         return dataNode.getChildDataNodes().stream().map(this::createNcmpServiceCmHandle).collect(Collectors.toSet());
 
 104     private Collection<String> queryCmHandlesByDmiPlugin(
 
 105             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters, final boolean outputAlternateId) {
 
 106         final Map<String, String> dmiPropertyQueryPairs =
 
 107                 getPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters(),
 
 108                         InventoryQueryConditions.CM_HANDLE_WITH_DMI_PLUGIN.getName());
 
 109         if (dmiPropertyQueryPairs.isEmpty()) {
 
 110             return NO_QUERY_TO_EXECUTE;
 
 113         final String dmiPluginIdentifierValue = dmiPropertyQueryPairs
 
 114                 .get(PropertyType.DMI_PLUGIN.getYangContainerName());
 
 116         return cmHandleQueryService.getCmHandleReferencesByDmiPluginIdentifier(
 
 117                 dmiPluginIdentifierValue, outputAlternateId);
 
 121     private Collection<String> queryCmHandlesByPrivateProperties(
 
 122             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters, final boolean outputAlternateId) {
 
 124         final Map<String, String> privatePropertyQueryPairs =
 
 125                 getPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters(),
 
 126                         InventoryQueryConditions.HAS_ALL_ADDITIONAL_PROPERTIES.getName());
 
 128         if (privatePropertyQueryPairs.isEmpty()) {
 
 129             return NO_QUERY_TO_EXECUTE;
 
 131         return cmHandleQueryService.queryCmHandleAdditionalProperties(privatePropertyQueryPairs, outputAlternateId);
 
 134     private Collection<String> queryCmHandlesByPublicProperties(
 
 135             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters, final boolean outputAlternateId) {
 
 137         final Map<String, String> publicPropertyQueryPairs =
 
 138                 getPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters(),
 
 139                         HAS_ALL_PROPERTIES.getConditionName());
 
 141         if (publicPropertyQueryPairs.isEmpty()) {
 
 142             return NO_QUERY_TO_EXECUTE;
 
 144         return cmHandleQueryService.queryCmHandlePublicProperties(publicPropertyQueryPairs, outputAlternateId);
 
 147     private Collection<String> queryCmHandlesByTrustLevel(final CmHandleQueryServiceParameters
 
 148                                                                   cmHandleQueryServiceParameters,
 
 149                                                           final boolean outputAlternateId) {
 
 151         final Map<String, String> trustLevelPropertyQueryPairs =
 
 152                 getPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters(),
 
 153                         WITH_TRUST_LEVEL.getConditionName());
 
 155         if (trustLevelPropertyQueryPairs.isEmpty()) {
 
 156             return NO_QUERY_TO_EXECUTE;
 
 158         return cmHandleQueryService.queryCmHandlesByTrustLevel(trustLevelPropertyQueryPairs, outputAlternateId);
 
 161     private Collection<String> executeModuleNameQuery(
 
 162             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters, final boolean outputAlternateId) {
 
 163         final Collection<String> moduleNamesForQuery =
 
 164                 getModuleNamesForQuery(cmHandleQueryServiceParameters.getCmHandleQueryParameters());
 
 165         if (moduleNamesForQuery.isEmpty()) {
 
 166             return NO_QUERY_TO_EXECUTE;
 
 168         return inventoryPersistence.getCmHandleReferencesWithGivenModules(moduleNamesForQuery, outputAlternateId);
 
 171     private Collection<String> executeCpsPathQuery(
 
 172             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters, final boolean outputAlternateId) {
 
 173         final Map<String, String> cpsPathCondition
 
 174                 = getCpsPathCondition(cmHandleQueryServiceParameters.getCmHandleQueryParameters());
 
 175         if (!validateCpsPathConditionProperties(cpsPathCondition)) {
 
 176             return Collections.emptySet();
 
 178         final Collection<String> cpsPathQueryResult;
 
 179         if (cpsPathCondition.isEmpty()) {
 
 180             return NO_QUERY_TO_EXECUTE;
 
 183             cpsPathQueryResult = cmHandleQueryService.getCmHandleReferencesByCpsPath(cpsPathCondition.get("cpsPath"),
 
 185         } catch (final PathParsingException pathParsingException) {
 
 186             throw new DataValidationException(pathParsingException.getMessage(), pathParsingException.getDetails(),
 
 187                     pathParsingException);
 
 189         return cpsPathQueryResult;
 
 192     private Collection<String> getModuleNamesForQuery(final List<ConditionProperties> conditionProperties) {
 
 193         final List<String> result = new ArrayList<>();
 
 194         getConditions(conditionProperties, HAS_ALL_MODULES.getConditionName()).forEach(
 
 195                 conditionProperty -> {
 
 196                     validateModuleNameConditionProperties(conditionProperty);
 
 197                     result.add(conditionProperty.get("moduleName"));
 
 202     private Map<String, String> getCpsPathCondition(final List<ConditionProperties> conditionProperties) {
 
 203         final Map<String, String> result = new HashMap<>();
 
 204         getConditions(conditionProperties, WITH_CPS_PATH.getConditionName()).forEach(result::putAll);
 
 208     private Map<String, String> getPropertyPairs(final List<ConditionProperties> conditionProperties,
 
 209                                                  final String queryProperty) {
 
 210         final Map<String, String> result = new HashMap<>();
 
 211         getConditions(conditionProperties, queryProperty).forEach(result::putAll);
 
 215     private List<Map<String, String>> getConditions(final List<ConditionProperties> conditionProperties,
 
 217         for (final ConditionProperties conditionProperty : conditionProperties) {
 
 218             if (conditionProperty.getConditionName().equals(name)) {
 
 219                 return conditionProperty.getConditionParameters();
 
 222         return Collections.emptyList();
 
 225     private Collection<String> getAllCmHandleReferences(final boolean outputAlternateId) {
 
 226         return cmHandleQueryService.getAllCmHandleReferences(outputAlternateId);
 
 229     private Flux<NcmpServiceCmHandle> getNcmpServiceCmHandles(final Collection<String> cmHandleIds) {
 
 230         return Flux.fromIterable(cmHandleIds)
 
 231                 .buffer(FLUX_BUFFER_SIZE)
 
 232                 .map(this::getNcmpServiceCmHandleBatch)
 
 233                 .flatMap(Flux::fromIterable);
 
 236     private Collection<NcmpServiceCmHandle> getNcmpServiceCmHandleBatch(final Collection<String> cmHandleIds) {
 
 237         final Collection<YangModelCmHandle> yangModelcmHandles
 
 238                 = inventoryPersistence.getYangModelCmHandles(cmHandleIds);
 
 240         final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles = new ArrayList<>(yangModelcmHandles.size());
 
 242         yangModelcmHandles.forEach(yangModelcmHandle ->
 
 243                 ncmpServiceCmHandles.add(YangDataConverter.toNcmpServiceCmHandle(yangModelcmHandle))
 
 245         trustLevelManager.applyEffectiveTrustLevels(ncmpServiceCmHandles);
 
 246         return ncmpServiceCmHandles;
 
 249     private NcmpServiceCmHandle createNcmpServiceCmHandle(final DataNode dataNode) {
 
 250         return toNcmpServiceCmHandle(YangDataConverter.toYangModelCmHandle(dataNode));
 
 253     private Collection<String> executeQueries(final CmHandleQueryServiceParameters cmHandleQueryServiceParameters,
 
 254                                               final boolean outputAlternateId,
 
 255                                               final BiFunction<CmHandleQueryServiceParameters, Boolean,
 
 256                                                       Collection<String>>... queryFunctions) {
 
 257         if (cmHandleQueryServiceParameters.getCmHandleQueryParameters().isEmpty()) {
 
 258             return getAllCmHandleReferences(outputAlternateId);
 
 260         Collection<String> combinedQueryResult = NO_QUERY_TO_EXECUTE;
 
 261         for (final BiFunction<CmHandleQueryServiceParameters, Boolean,
 
 262                 Collection<String>> queryFunction : queryFunctions) {
 
 263             final Collection<String> queryResult = queryFunction.apply(cmHandleQueryServiceParameters,
 
 265             if (noEntriesFoundCanStopQuerying(queryResult)) {
 
 266                 return Collections.emptySet();
 
 268             combinedQueryResult = combineCmHandleQueryResults(combinedQueryResult, queryResult);
 
 270         return combinedQueryResult;
 
 273     private boolean noEntriesFoundCanStopQuerying(final Collection<String> queryResult) {
 
 274         return queryResult != NO_QUERY_TO_EXECUTE && queryResult.isEmpty();
 
 277     private Collection<String> combineCmHandleQueryResults(final Collection<String> firstQuery,
 
 278                                                            final Collection<String> secondQuery) {
 
 279         if (firstQuery == NO_QUERY_TO_EXECUTE && secondQuery == NO_QUERY_TO_EXECUTE) {
 
 280             return NO_QUERY_TO_EXECUTE;
 
 281         } else if (firstQuery == NO_QUERY_TO_EXECUTE) {
 
 283         } else if (secondQuery == NO_QUERY_TO_EXECUTE) {
 
 286             firstQuery.retainAll(secondQuery);
 
 291     private Collection<String> collectCmHandleReferencesFromDataNodes(final Collection<DataNode> dataNodes,
 
 292                                                                       final boolean outputAlternateId) {
 
 293         if (outputAlternateId) {
 
 294             return dataNodes.stream().map(dataNode ->
 
 295                     (String) dataNode.getLeaves().get("alternate-id")).collect(Collectors.toSet());
 
 297             return dataNodes.stream().map(dataNode ->
 
 298                     (String) dataNode.getLeaves().get("id")).collect(Collectors.toSet());