Topology tree: test fetchCustomizationIdsFromToscaModelsWhileNeeded
[vid.git] / vid-app-common / src / main / java / org / onap / vid / services / AAITreeNodesEnricher.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * VID
4  * ================================================================================
5  * Copyright (C) 2017 - 2020 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.vid.services;
22
23 import static java.util.Collections.emptyMap;
24 import static java.util.stream.Collectors.toSet;
25 import static org.apache.commons.lang3.StringUtils.isAllEmpty;
26 import static org.onap.vid.utils.KotlinUtilsKt.JACKSON_OBJECT_MAPPER;
27
28 import com.fasterxml.jackson.databind.JsonNode;
29 import com.google.common.collect.ImmutableList;
30 import java.util.Collection;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.ListIterator;
34 import java.util.Map;
35 import java.util.Objects;
36 import java.util.Set;
37 import java.util.function.Predicate;
38 import javax.inject.Inject;
39 import javax.ws.rs.core.Response;
40 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
41 import org.onap.vid.aai.AaiClientInterface;
42 import org.onap.vid.aai.model.ModelVer;
43 import org.onap.vid.asdc.parser.ServiceModelInflator;
44 import org.onap.vid.asdc.parser.ServiceModelInflator.Names;
45 import org.onap.vid.model.ServiceModel;
46 import org.onap.vid.model.aaiTree.AAITreeNode;
47 import org.onap.vid.model.aaiTree.NodeType;
48 import org.onap.vid.properties.Features;
49 import org.springframework.stereotype.Component;
50 import org.togglz.core.manager.FeatureManager;
51
52 @Component
53 public class AAITreeNodesEnricher {
54
55     private final AaiClientInterface aaiClient;
56
57     private final VidService sdcService;
58
59     private final ServiceModelInflator serviceModelInflator;
60
61     private final FeatureManager featureManager;
62
63     private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(AAITreeNodesEnricher.class);
64
65     @Inject
66     public AAITreeNodesEnricher(
67         AaiClientInterface aaiClient,
68         VidService sdcService,
69         FeatureManager featureManager,
70         ServiceModelInflator serviceModelInflator
71     ) {
72         this.aaiClient = aaiClient;
73         this.sdcService = sdcService;
74         this.featureManager = featureManager;
75         this.serviceModelInflator = serviceModelInflator;
76     }
77
78     void enrichNodesWithModelCustomizationName(Collection<AAITreeNode> nodes, ServiceModel serviceModel) {
79         final Map<String, Names> customizationNameByVersionId = serviceModelInflator.toNamesByVersionId(serviceModel);
80
81         nodes.forEach(node -> {
82             final Names names = customizationNameByVersionId.get(node.getModelVersionId());
83             if (names != null) {
84                 node.setKeyInModel(names.getModelKey());
85                 node.setModelCustomizationName(names.getModelCustomizationName());
86             }
87         });
88     }
89
90     void enrichVfModulesWithModelCustomizationNameFromOtherVersions(Collection<AAITreeNode> nodes, String modelInvariantId) {
91         if (!featureManager.isActive(Features.FLAG_EXP_TOPOLOGY_TREE_VFMODULE_NAMES_FROM_OTHER_TOSCA_VERSIONS)) {
92             return;
93         }
94
95         if (nodes.stream().noneMatch(vfModuleWithMissingData())) {
96             return;
97         }
98
99         final List<ModelVer> allModelVersions = aaiClient.getSortedVersionsByInvariantId(modelInvariantId);
100
101         final ListIterator<ModelVer> modelVersionsIterator = allModelVersions.listIterator();
102         final Map<String, Names> namesByCustomizationId = new HashMap<>();
103
104         nodes.stream().filter(vfModuleWithMissingData()).forEach(node -> {
105             String modelCustomizationId = node.getModelCustomizationId();
106
107             fetchCustomizationIdsFromToscaModelsWhileNeeded(namesByCustomizationId, modelVersionsIterator, modelCustomizationId);
108
109             final Names names = namesByCustomizationId.get(modelCustomizationId);
110             if (names != null) {
111                 node.setKeyInModel(names.getModelKey());
112                 node.setModelCustomizationName(names.getModelCustomizationName());
113             }
114         });
115     }
116
117     private Predicate<AAITreeNode> vfModuleWithMissingData() {
118         final Predicate<AAITreeNode> isVfModule = node -> node.getType() == NodeType.VF_MODULE;
119
120         final Predicate<AAITreeNode> nodeWithMissingData =
121             node -> isAllEmpty(node.getKeyInModel(), node.getModelCustomizationName());
122
123         return isVfModule.and(nodeWithMissingData);
124     }
125
126     /**
127      * Loads inOutMutableNamesByCustomizationId with all customization IDs from the list of modelVersions. Will seize loading
128      * if yieldCustomizationId presents in inOutMutableNamesByCustomizationId.
129      * @param inOutMutableNamesByCustomizationId Mutable Map to fill-up
130      * @param modelVersions Iterable of model-version-ids to load
131      * @param yieldCustomizationId The key to stop loading on
132      */
133     void fetchCustomizationIdsFromToscaModelsWhileNeeded(
134         Map<String, Names> inOutMutableNamesByCustomizationId,
135         ListIterator<ModelVer> modelVersions,
136         String yieldCustomizationId
137     ) {
138         while (modelVersions.hasNext() && !inOutMutableNamesByCustomizationId.containsKey(yieldCustomizationId)) {
139             inOutMutableNamesByCustomizationId.putAll(
140                 fetchAllCustomizationIds(modelVersions.next().getModelVersionId())
141             );
142         }
143     }
144
145     private Map<String, Names> fetchAllCustomizationIds(String modelVersionId) {
146         try {
147             ServiceModel serviceModel = sdcService.getServiceModelOrThrow(modelVersionId);
148             return serviceModelInflator.toNamesByCustomizationId(serviceModel);
149         } catch (Exception e) {
150             // Ignore the failure: SDC may lack the historic model, but this is NOT a reason to fail the whole enrichment
151             LOGGER.debug(EELFLoggerDelegate.debugLogger,
152                 "Could not get model customization ids from SCD where modelVersionId={}", modelVersionId, e);
153             return emptyMap();
154         }
155     }
156
157     public void enrichNodesWithModelVersionAndModelName(Collection<AAITreeNode> nodes) {
158
159         Collection<String> invariantIDs = getModelInvariantIds(nodes);
160
161         Map<String, String> modelVersionByModelVersionId = new HashMap<>();
162         Map<String, String> modelNameByModelVersionId = new HashMap<>();
163
164         JsonNode models = getModels(aaiClient, invariantIDs);
165         if (models!=null) {
166             for (JsonNode model : models) {
167                 JsonNode modelVersions = model.get("model-vers").get("model-ver");
168                 for (JsonNode modelVersion : modelVersions) {
169                     final String modelVersionId = modelVersion.get("model-version-id").asText();
170                     modelVersionByModelVersionId.put(modelVersionId, modelVersion.get("model-version").asText());
171                     modelNameByModelVersionId.put(modelVersionId, modelVersion.get("model-name").asText());
172                 }
173             }
174         }
175
176         nodes.forEach(node -> {
177             node.setModelVersion(modelVersionByModelVersionId.get(node.getModelVersionId()));
178             node.setModelName(modelNameByModelVersionId.get(node.getModelVersionId()));
179         });
180
181     }
182
183     private JsonNode getModels(AaiClientInterface aaiClient, Collection<String> invariantIDs) {
184         Response response = aaiClient.getVersionByInvariantId(ImmutableList.copyOf(invariantIDs));
185         try {
186             JsonNode responseJson = JACKSON_OBJECT_MAPPER.readTree(response.readEntity(String.class));
187             return responseJson.get("model");
188         } catch (Exception e) {
189             LOGGER.error(EELFLoggerDelegate.errorLogger, "Failed to getVersionByInvariantId from A&AI", e);
190         }
191         return JACKSON_OBJECT_MAPPER.createObjectNode();
192     }
193
194     private Set<String> getModelInvariantIds(Collection<AAITreeNode> nodes) {
195         return nodes.stream()
196                 .map(AAITreeNode::getModelInvariantId)
197                 .filter(Objects::nonNull)
198                 .collect(toSet());
199     }
200
201 }