Fix Id-searches endpoint performance degradation
[cps.git] / cps-ncmp-service / src / main / java / org / onap / cps / ncmp / api / impl / NetworkCmProxyCmHandlerQueryServiceImpl.java
1 /*
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
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  *
17  *  SPDX-License-Identifier: Apache-2.0
18  *  ============LICENSE_END=========================================================
19  */
20
21 package org.onap.cps.ncmp.api.impl;
22
23 import static org.onap.cps.ncmp.api.impl.utils.YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle;
24 import static org.onap.cps.spi.FetchDescendantsOption.FETCH_DIRECT_CHILDREN_ONLY;
25 import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
26 import static org.onap.cps.utils.CmHandleQueryRestParametersValidator.validateCpsPathConditionProperties;
27 import static org.onap.cps.utils.CmHandleQueryRestParametersValidator.validateModuleNameConditionProperties;
28
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;
35 import java.util.Map;
36 import java.util.Set;
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.YangDataConverter;
44 import org.onap.cps.ncmp.api.inventory.CmHandleQueries;
45 import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
46 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
47 import org.onap.cps.spi.exceptions.DataValidationException;
48 import org.onap.cps.spi.model.Anchor;
49 import org.onap.cps.spi.model.CmHandleQueryServiceParameters;
50 import org.onap.cps.spi.model.ConditionProperties;
51 import org.onap.cps.spi.model.DataNode;
52 import org.onap.cps.utils.ValidQueryProperties;
53 import org.springframework.stereotype.Service;
54
55 @Service
56 @Slf4j
57 @RequiredArgsConstructor
58 public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCmHandlerQueryService {
59
60     private static final Map<String, NcmpServiceCmHandle> NO_QUERY_TO_EXECUTE = null;
61     private final CmHandleQueries cmHandleQueries;
62     private final InventoryPersistence inventoryPersistence;
63
64     /**
65      * Query and return cm handles that match the given query parameters.
66      *
67      * @param cmHandleQueryServiceParameters the cm handle query parameters
68      * @return collection of cm handles
69      */
70     @Override
71     public Set<NcmpServiceCmHandle> queryCmHandles(
72             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
73
74         if (cmHandleQueryServiceParameters.getCmHandleQueryParameters().isEmpty()) {
75             return getAllCmHandles();
76         }
77
78         final Map<String, NcmpServiceCmHandle> combinedQueryResult = executeInventoryQueries(
79                 cmHandleQueryServiceParameters);
80
81         return new HashSet<>(combineWithModuleNameQuery(cmHandleQueryServiceParameters, combinedQueryResult).values());
82     }
83
84     /**
85      * Query and return cm handles that match the given query parameters.
86      *
87      * @param cmHandleQueryServiceParameters the cm handle query parameters
88      * @return collection of cm handle ids
89      */
90     @Override
91     public Set<String> queryCmHandleIds(
92             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
93
94         if (cmHandleQueryServiceParameters.getCmHandleQueryParameters().isEmpty()) {
95             return getAllCmHandleIds();
96         }
97
98         final Map<String, NcmpServiceCmHandle> combinedQueryResult = executeInventoryQueries(
99                 cmHandleQueryServiceParameters);
100
101         final Collection<String> moduleNamesForQuery =
102                 getModuleNamesForQuery(cmHandleQueryServiceParameters.getCmHandleQueryParameters());
103         if (moduleNamesForQuery.isEmpty()) {
104             return combinedQueryResult.keySet();
105         }
106         final Set<String> moduleNameQueryResult = getNamesOfAnchorsWithGivenModules(moduleNamesForQuery);
107
108         if (combinedQueryResult == NO_QUERY_TO_EXECUTE) {
109             return moduleNameQueryResult;
110         }
111
112         moduleNameQueryResult.retainAll(combinedQueryResult.keySet());
113         return moduleNameQueryResult;
114     }
115
116     private Map<String, NcmpServiceCmHandle> combineWithModuleNameQuery(
117             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters,
118             final Map<String, NcmpServiceCmHandle> previousQueryResult) {
119         final Collection<String> moduleNamesForQuery =
120                 getModuleNamesForQuery(cmHandleQueryServiceParameters.getCmHandleQueryParameters());
121         if (moduleNamesForQuery.isEmpty()) {
122             return previousQueryResult;
123         }
124         final Collection<String> cmHandleIdsByModuleName = getNamesOfAnchorsWithGivenModules(moduleNamesForQuery);
125         if (cmHandleIdsByModuleName.isEmpty()) {
126             return Collections.emptyMap();
127         }
128         final Map<String, NcmpServiceCmHandle> queryResult = new HashMap<>(cmHandleIdsByModuleName.size());
129         if (previousQueryResult == NO_QUERY_TO_EXECUTE) {
130             cmHandleIdsByModuleName.forEach(cmHandleId ->
131                     queryResult.put(cmHandleId, createNcmpServiceCmHandle(
132                             inventoryPersistence.getDataNode("/dmi-registry/cm-handles[@id='" + cmHandleId + "']")))
133             );
134             return queryResult;
135         }
136         previousQueryResult.keySet().retainAll(cmHandleIdsByModuleName);
137         queryResult.putAll(previousQueryResult);
138         return queryResult;
139     }
140
141     private Map<String, NcmpServiceCmHandle> executeInventoryQueries(
142             final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
143         final Map<String, String> cpsPath = getCpsPath(cmHandleQueryServiceParameters.getCmHandleQueryParameters());
144         if (!validateCpsPathConditionProperties(cpsPath)) {
145             return Collections.emptyMap();
146         }
147         final Map<String, NcmpServiceCmHandle> cpsPathQueryResult;
148         if (cpsPath.isEmpty()) {
149             cpsPathQueryResult = NO_QUERY_TO_EXECUTE;
150         } else {
151             try {
152                 cpsPathQueryResult = cmHandleQueries.queryCmHandleDataNodesByCpsPath(
153                                 cpsPath.get("cpsPath"), INCLUDE_ALL_DESCENDANTS)
154                         .stream().map(this::createNcmpServiceCmHandle)
155                         .collect(Collectors.toMap(NcmpServiceCmHandle::getCmHandleId,
156                                 Function.identity()));
157             } catch (final PathParsingException pathParsingException) {
158                 throw new DataValidationException(pathParsingException.getMessage(), pathParsingException.getDetails(),
159                         pathParsingException);
160             }
161             if (cpsPathQueryResult.isEmpty()) {
162                 return Collections.emptyMap();
163             }
164         }
165
166         final Map<String, String> publicPropertyQueryPairs =
167                 getPublicPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters());
168         final Map<String, NcmpServiceCmHandle> propertiesQueryResult = publicPropertyQueryPairs.isEmpty()
169                 ? NO_QUERY_TO_EXECUTE : cmHandleQueries.queryCmHandlePublicProperties(publicPropertyQueryPairs);
170
171         return cmHandleQueries.combineCmHandleQueries(cpsPathQueryResult, propertiesQueryResult);
172     }
173
174     private Set<String> getNamesOfAnchorsWithGivenModules(final Collection<String> moduleNamesForQuery) {
175         final Collection<Anchor> anchors = inventoryPersistence.queryAnchors(moduleNamesForQuery);
176         return anchors.parallelStream().map(Anchor::getName).collect(Collectors.toSet());
177     }
178
179     private Collection<String> getModuleNamesForQuery(final List<ConditionProperties> conditionProperties) {
180         final List<String> result = new ArrayList<>();
181         getConditions(conditionProperties, ValidQueryProperties.HAS_ALL_MODULES.getQueryProperty())
182             .parallelStream().forEach(
183                 conditionProperty -> {
184                     validateModuleNameConditionProperties(conditionProperty);
185                     result.add(conditionProperty.get("moduleName"));
186                 }
187             );
188         return result;
189     }
190
191     private Map<String, String> getCpsPath(final List<ConditionProperties> conditionProperties) {
192         final Map<String, String> result = new HashMap<>();
193         getConditions(conditionProperties, ValidQueryProperties.WITH_CPS_PATH.getQueryProperty()).forEach(
194                 result::putAll);
195         return result;
196     }
197
198     private Map<String, String> getPublicPropertyPairs(final List<ConditionProperties> conditionProperties) {
199         final Map<String, String> result = new HashMap<>();
200         getConditions(conditionProperties,
201                 ValidQueryProperties.HAS_ALL_PROPERTIES.getQueryProperty()).forEach(result::putAll);
202         return result;
203     }
204
205     private List<Map<String, String>> getConditions(final List<ConditionProperties> conditionProperties,
206                                                     final String name) {
207         for (final ConditionProperties conditionProperty : conditionProperties) {
208             if (conditionProperty.getConditionName().equals(name)) {
209                 return conditionProperty.getConditionParameters();
210             }
211         }
212         return Collections.emptyList();
213     }
214
215     private Set<NcmpServiceCmHandle> getAllCmHandles() {
216         return inventoryPersistence.getDataNode("/dmi-registry")
217                 .getChildDataNodes().stream().map(this::createNcmpServiceCmHandle).collect(Collectors.toSet());
218     }
219
220     private Set<String> getAllCmHandleIds() {
221         return inventoryPersistence.getDataNode("/dmi-registry", FETCH_DIRECT_CHILDREN_ONLY)
222                 .getChildDataNodes().stream().map(dataNode -> dataNode.getLeaves().get("id").toString())
223                 .collect(Collectors.toSet());
224     }
225
226     private NcmpServiceCmHandle createNcmpServiceCmHandle(final DataNode dataNode) {
227         return convertYangModelCmHandleToNcmpServiceCmHandle(YangDataConverter
228                 .convertCmHandleToYangModel(dataNode, dataNode.getLeaves().get("id").toString()));
229     }
230 }