Performance Improvement: Batch Update DataNodes
[cps.git] / cps-ncmp-service / src / main / java / org / onap / cps / ncmp / api / inventory / InventoryPersistence.java
1 /*
2  *  ============LICENSE_START=======================================================
3  *  Copyright (C) 2022 Nordix Foundation
4  *  Modifications Copyright (C) 2022 Bell Canada
5  *  ================================================================================
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  *
18  *  SPDX-License-Identifier: Apache-2.0
19  *  ============LICENSE_END=========================================================
20  */
21
22 package org.onap.cps.ncmp.api.inventory;
23
24 import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
25 import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NO_TIMESTAMP;
26 import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED;
27 import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
28
29 import java.time.OffsetDateTime;
30 import java.util.Collection;
31 import java.util.HashMap;
32 import java.util.Map;
33 import lombok.RequiredArgsConstructor;
34 import lombok.extern.slf4j.Slf4j;
35 import org.onap.cps.api.CpsDataService;
36 import org.onap.cps.api.CpsModuleService;
37 import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
38 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
39 import org.onap.cps.spi.CpsAdminPersistenceService;
40 import org.onap.cps.spi.CpsDataPersistenceService;
41 import org.onap.cps.spi.FetchDescendantsOption;
42 import org.onap.cps.spi.exceptions.SchemaSetNotFoundException;
43 import org.onap.cps.spi.model.Anchor;
44 import org.onap.cps.spi.model.DataNode;
45 import org.onap.cps.spi.model.ModuleDefinition;
46 import org.onap.cps.spi.model.ModuleReference;
47 import org.onap.cps.utils.CpsValidator;
48 import org.onap.cps.utils.JsonObjectMapper;
49 import org.springframework.stereotype.Component;
50
51 @Slf4j
52 @RequiredArgsConstructor
53 @Component
54 public class InventoryPersistence {
55
56     private static final String NCMP_DATASPACE_NAME = "NCMP-Admin";
57
58     private static final String NCMP_DMI_REGISTRY_ANCHOR = "ncmp-dmi-registry";
59
60     private static final String NCMP_DMI_REGISTRY_PARENT = "/dmi-registry";
61
62     private static final String CM_HANDLE_XPATH_TEMPLATE = "/dmi-registry/cm-handles[@id='" + "%s" + "']";
63
64     private final JsonObjectMapper jsonObjectMapper;
65
66     private final CpsDataService cpsDataService;
67
68     private final CpsModuleService cpsModuleService;
69
70     private final CpsDataPersistenceService cpsDataPersistenceService;
71
72     private final CpsAdminPersistenceService cpsAdminPersistenceService;
73
74     /**
75      * Get the Cm Handle Composite State from the data node.
76      *
77      * @param cmHandleId cm handle id
78      * @return the cm handle composite state
79      */
80     public CompositeState getCmHandleState(final String cmHandleId) {
81         final DataNode stateAsDataNode = cpsDataService.getDataNode(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
82             String.format(CM_HANDLE_XPATH_TEMPLATE, cmHandleId) + "/state",
83             FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
84         return new CompositeStateBuilder().fromDataNode(stateAsDataNode).build();
85     }
86
87     /**
88      * Save the cm handles state.
89      *
90      * @param cmHandleId    cm handle id
91      * @param compositeState composite state
92      */
93     public void saveCmHandleState(final String cmHandleId, final CompositeState compositeState) {
94         final String cmHandleJsonData = String.format("{\"state\":%s}",
95             jsonObjectMapper.asJsonString(compositeState));
96         cpsDataService.updateDataNodeAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
97             String.format(CM_HANDLE_XPATH_TEMPLATE, cmHandleId),
98             cmHandleJsonData, OffsetDateTime.now());
99     }
100
101     /**
102      * Save all cm handles states in batch.
103      *
104      * @param cmHandleStates contains cm handle id and updated state
105      */
106     public void saveCmHandleStates(final Map<String, CompositeState> cmHandleStates) {
107         final Map<String, String> cmHandlesJsonDataMap = new HashMap<>();
108         cmHandleStates.entrySet().stream().forEach(cmHandleEntry ->
109             cmHandlesJsonDataMap.put(String.format(CM_HANDLE_XPATH_TEMPLATE, cmHandleEntry.getKey()),
110                 String.format("{\"state\":%s}",
111                     jsonObjectMapper.asJsonString(cmHandleEntry.getValue()))));
112         cpsDataService.updateDataNodesAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
113             cmHandlesJsonDataMap, OffsetDateTime.now());
114     }
115
116     /**
117      * This method retrieves DMI service name, DMI properties and the state for a given cm handle.
118      * @param cmHandleId the id of the cm handle
119      * @return yang model cm handle
120      */
121     public YangModelCmHandle getYangModelCmHandle(final String cmHandleId) {
122         CpsValidator.validateNameCharacters(cmHandleId);
123         return YangDataConverter.convertCmHandleToYangModel(getCmHandleDataNode(cmHandleId), cmHandleId);
124     }
125
126     /**
127      * Method to return module definitions by cmHandleId.
128      *
129      * @param cmHandleId cm handle ID
130      * @return a collection of module definitions (moduleName, revision and yang resource content)
131      */
132     public Collection<ModuleDefinition> getModuleDefinitionsByCmHandleId(final String cmHandleId) {
133         return cpsModuleService.getModuleDefinitionsByAnchorName(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId);
134     }
135
136     /**
137      * Method to return module references by cmHandleId.
138      *
139      * @param cmHandleId cm handle ID
140      * @return a collection of module references (moduleName and revision)
141      */
142     public Collection<ModuleReference> getYangResourcesModuleReferences(final String cmHandleId) {
143         CpsValidator.validateNameCharacters(cmHandleId);
144         return cpsModuleService.getYangResourcesModuleReferences(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId);
145     }
146
147     /**
148      * Method to save cmHandle.
149      *
150      * @param yangModelCmHandle cmHandle represented as Yang Model
151      */
152     public void saveCmHandle(final YangModelCmHandle yangModelCmHandle) {
153         final String cmHandleJsonData =
154                 String.format("{\"cm-handles\":[%s]}", jsonObjectMapper.asJsonString(yangModelCmHandle));
155         cpsDataService.saveListElements(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT,
156                 cmHandleJsonData, NO_TIMESTAMP);
157     }
158
159     /**
160      * Method to delete a list or a list element.
161      *
162      * @param listElementXpath list element xPath
163      */
164     public void deleteListOrListElement(final String listElementXpath) {
165         cpsDataService.deleteListOrListElement(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
166                 listElementXpath, NO_TIMESTAMP);
167     }
168
169     /**
170      * Method to delete a schema set.
171      *
172      * @param schemaSetName schema set name
173      */
174     public void deleteSchemaSetWithCascade(final String schemaSetName) {
175         try {
176             CpsValidator.validateNameCharacters(schemaSetName);
177             cpsModuleService.deleteSchemaSet(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetName,
178                     CASCADE_DELETE_ALLOWED);
179         } catch (final SchemaSetNotFoundException schemaSetNotFoundException) {
180             log.warn("Schema set {} does not exist or already deleted", schemaSetName);
181         }
182     }
183
184     /**
185      * Get data node via xpath.
186      *
187      * @param xpath xpath
188      * @return data node
189      */
190     public DataNode getDataNode(final String xpath) {
191         return cpsDataPersistenceService.getDataNode(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
192                 xpath, INCLUDE_ALL_DESCENDANTS);
193     }
194
195     /**
196      * Get data node of given cm handle.
197      *
198      * @param cmHandleId cmHandle ID
199      * @return data node
200      */
201     public DataNode getCmHandleDataNode(final String cmHandleId) {
202         return this.getDataNode(String.format(CM_HANDLE_XPATH_TEMPLATE, cmHandleId));
203     }
204
205     /**
206      * Query anchors via module names.
207      *
208      * @param moduleNamesForQuery module names
209      * @return Collection of anchors
210      */
211     public Collection<Anchor> queryAnchors(final Collection<String> moduleNamesForQuery) {
212         return  cpsAdminPersistenceService.queryAnchors(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, moduleNamesForQuery);
213     }
214
215     /**
216      * Method to get all anchors.
217      *
218      * @return Collection of anchors
219      */
220     public Collection<Anchor> getAnchors() {
221         return cpsAdminPersistenceService.getAnchors(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME);
222     }
223
224     /**
225      * Replaces list content by removing all existing elements and inserting the given new elements as data nodes.
226      *
227      * @param parentNodeXpath   parent node xpath
228      * @param dataNodes         datanodes representing the updated data
229      */
230     public void replaceListContent(final String parentNodeXpath, final Collection<DataNode> dataNodes) {
231         cpsDataService.replaceListContent(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
232                 parentNodeXpath, dataNodes, NO_TIMESTAMP);
233     }
234
235     /**
236      * Deletes data node for given anchor and dataspace.
237      *
238      * @param dataNodeXpath data node xpath
239      */
240     public void deleteDataNode(final String dataNodeXpath) {
241         cpsDataService.deleteDataNode(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, dataNodeXpath,
242                 NO_TIMESTAMP);
243     }
244 }