d62d5d5d4e437e28bf76c35d0236abacb4faa59f
[vid.git] / vid-app-common / src / main / java / org / onap / vid / services / AAIServiceTree.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * VID
4  * ================================================================================
5  * Copyright (C) 2017 - 2019 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 com.fasterxml.jackson.databind.JsonNode;
24 import com.google.common.collect.ImmutableList;
25 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
26 import org.onap.vid.aai.AaiClientInterface;
27 import org.onap.vid.aai.util.AAITreeConverter;
28 import org.onap.vid.asdc.AsdcCatalogException;
29 import org.onap.vid.asdc.parser.ServiceModelInflator;
30 import org.onap.vid.exceptions.GenericUncheckedException;
31 import org.onap.vid.model.ServiceModel;
32 import org.onap.vid.model.aaiTree.AAITreeNode;
33 import org.onap.vid.model.aaiTree.NodeType;
34 import org.onap.vid.model.aaiTree.ServiceInstance;
35 import org.onap.vid.utils.Tree;
36 import org.springframework.http.HttpMethod;
37 import org.springframework.stereotype.Component;
38
39 import javax.inject.Inject;
40 import javax.ws.rs.core.Response;
41 import java.util.*;
42 import java.util.concurrent.ConcurrentSkipListSet;
43 import java.util.concurrent.ExecutorService;
44 import java.util.stream.Collectors;
45 import java.util.stream.Stream;
46
47 import static java.util.Comparator.comparing;
48 import static java.util.stream.Collectors.toSet;
49 import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
50 import static org.onap.vid.utils.KotlinUtilsKt.JACKSON_OBJECT_MAPPER;
51
52 @Component
53 public class AAIServiceTree {
54
55     private final AAITreeNodeBuilder aaiTreeNodeBuilder;
56
57     private final AAITreeConverter aaiTreeConverter;
58
59     private final AaiClientInterface aaiClient;
60
61     private final VidService sdcService;
62
63     private final ServiceModelInflator serviceModelInflator;
64
65     private final ExecutorService executorService;
66
67     private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(AAIServiceTree.class);
68
69     public static final Tree<AaiRelationship> AAI_TREE_PATHS =
70             new Tree<>(new AaiRelationship(NodeType.SERVICE_INSTANCE));
71
72     static {
73         AAI_TREE_PATHS.addPath(toAaiRelationshipList(NodeType.GENERIC_VNF, NodeType.VOLUME_GROUP));
74         AAI_TREE_PATHS.addPath(toAaiRelationshipList(NodeType.GENERIC_VNF, NodeType.VF_MODULE));
75         AAI_TREE_PATHS.addPath(toAaiRelationshipList(NodeType.GENERIC_VNF, NodeType.NETWORK, NodeType.VPN_BINDING));
76         AAI_TREE_PATHS.addPath(toAaiRelationshipList(NodeType.NETWORK, NodeType.VPN_BINDING));
77         AAI_TREE_PATHS.addPath(toAaiRelationshipList(NodeType.INSTANCE_GROUP, NodeType.GENERIC_VNF));
78         AAI_TREE_PATHS.addPath(toAaiRelationshipList(NodeType.COLLECTION_RESOURCE, NodeType.INSTANCE_GROUP));
79         AAI_TREE_PATHS.addPath(toAaiRelationshipList(NodeType.CONFIGURATION, NodeType.NETWORK, NodeType.VPN_BINDING));
80         AAI_TREE_PATHS.addPath(toAaiRelationshipList(NodeType.CONFIGURATION, NodeType.VPN_BINDING));
81     }
82
83     public static List<AAIServiceTree.AaiRelationship> toAaiRelationshipList(NodeType... types) {
84         return Stream.of(types).map(AAIServiceTree.AaiRelationship::new).collect(Collectors.toList());
85     }
86
87     @Inject
88     public AAIServiceTree(AaiClientInterface aaiClient, AAITreeNodeBuilder aaiTreeNodeBuilder,
89                           AAITreeConverter aaiTreeConverter, VidService sdcService,
90                           ServiceModelInflator serviceModelInflator, ExecutorService executorService) {
91         this.aaiClient = aaiClient;
92         this.aaiTreeNodeBuilder = aaiTreeNodeBuilder;
93         this.aaiTreeConverter = aaiTreeConverter;
94         this.sdcService = sdcService;
95         this.serviceModelInflator = serviceModelInflator;
96         this.executorService = executorService;
97     }
98
99     List<AAITreeNode> buildAAITreeForUniqueResource(String getUrl, NodeType nodeType) {
100         return buildAAITreeForUniqueResourceFromCustomQuery(getUrl, null, HttpMethod.GET, nodeType);
101     }
102
103     List<AAITreeNode> buildAAITreeForUniqueResourceFromCustomQuery(String url, String payload, HttpMethod method, NodeType nodeType) {
104         Tree<AAIServiceTree.AaiRelationship> pathsToSearch = new Tree<>(new AAIServiceTree.AaiRelationship(nodeType));
105         return buildAAITree(url, payload, method, pathsToSearch, false);
106     }
107
108     public List<AAITreeNode> buildAAITree(String url, String payload, HttpMethod method, Tree<AaiRelationship> pathsToSearch, boolean enrichWithModelVersion) {
109
110         ConcurrentSkipListSet<AAITreeNode> nodesAccumulator = createNodesAccumulator();
111
112         List<AAITreeNode> aaiTreeNodes = fetchAAITree(url, payload, method, pathsToSearch, nodesAccumulator);
113
114         if (enrichWithModelVersion) {
115             enrichNodesWithModelVersionAndModelName(nodesAccumulator);
116         }
117
118         return aaiTreeNodes;
119     }
120
121     public ServiceInstance getServiceInstanceTopology(String globalCustomerId, String serviceType, String serviceInstanceId) {
122
123         String getURL = "business/customers/customer/" +
124                 globalCustomerId + "/service-subscriptions/service-subscription/" +
125                 serviceType + "/service-instances/service-instance/" + serviceInstanceId;
126
127         //Used later to get the nodes UUID
128         ConcurrentSkipListSet<AAITreeNode> nodesAccumulator = createNodesAccumulator();
129
130         AAITreeNode aaiTree = fetchAAITree(getURL, null, HttpMethod.GET, AAI_TREE_PATHS, nodesAccumulator).get(0);
131
132         //Populate nodes with model-name & model-version (from aai)
133         enrichNodesWithModelVersionAndModelName(nodesAccumulator);
134
135         final ServiceModel serviceModel = getServiceModel(aaiTree.getModelVersionId());
136
137         //Populate nodes with model-customization-name (from sdc model)
138         enrichNodesWithModelCustomizationName(nodesAccumulator, serviceModel);
139
140         return aaiTreeConverter.convertTreeToUIModel(aaiTree, globalCustomerId, serviceType, getInstantiationType(serviceModel), getInstanceRole(serviceModel), getInstanceType(serviceModel));
141     }
142
143     private String getInstanceType(ServiceModel serviceModel){
144         if (serviceModel != null && serviceModel.getService() != null) {
145             return serviceModel.getService().getServiceType();
146         }
147         return "";
148     }
149
150     private String getInstanceRole(ServiceModel serviceModel) {
151         if (serviceModel != null && serviceModel.getService() != null) {
152             return serviceModel.getService().getServiceRole();
153         }
154         return "";
155     }
156
157     private List<AAITreeNode> fetchAAITree(String url, String payload, HttpMethod method, Tree<AaiRelationship> pathsToSearch,
158                                            ConcurrentSkipListSet<AAITreeNode> nodesAccumulator) {
159         return aaiTreeNodeBuilder.buildNode(NodeType.fromString(pathsToSearch.getRootValue().type),
160                 url, payload, method, defaultIfNull(nodesAccumulator, createNodesAccumulator()),
161                 executorService, pathsToSearch);
162     }
163
164     private ConcurrentSkipListSet<AAITreeNode> createNodesAccumulator() {
165         return new ConcurrentSkipListSet<>(comparing(AAITreeNode::getUniqueNodeKey));
166     }
167
168     private String getInstantiationType(ServiceModel serviceModel) {
169         if (serviceModel.getService() != null && serviceModel.getService().getInstantiationType() != null) {
170             return serviceModel.getService().getInstantiationType();
171         } else {
172             return null;
173         }
174     }
175
176     private ServiceModel getServiceModel(String modelVersionId) {
177         try {
178             final ServiceModel serviceModel = sdcService.getService(modelVersionId);
179             if (serviceModel == null) {
180                 throw new GenericUncheckedException("Model version '" + modelVersionId + "' not found");
181             }
182             return serviceModel;
183         } catch (AsdcCatalogException e) {
184             throw new GenericUncheckedException("Exception while loading model version '" + modelVersionId + "'", e);
185         }
186
187     }
188
189     void enrichNodesWithModelCustomizationName(Collection<AAITreeNode> nodes, ServiceModel serviceModel) {
190         final Map<String, ServiceModelInflator.Names> customizationNameByVersionId = serviceModelInflator.toNamesByVersionId(serviceModel);
191
192         nodes.forEach(node -> {
193             final ServiceModelInflator.Names names = customizationNameByVersionId.get(node.getModelVersionId());
194             if (names != null) {
195                 node.setKeyInModel(names.getModelKey());
196                 node.setModelCustomizationName(names.getModelCustomizationName());
197             }
198         });
199     }
200
201
202     private void enrichNodesWithModelVersionAndModelName(Collection<AAITreeNode> nodes) {
203
204         Collection<String> invariantIDs = getModelInvariantIds(nodes);
205
206         Map<String, String> modelVersionByModelVersionId = new HashMap<>();
207         Map<String, String> modelNameByModelVersionId = new HashMap<>();
208
209         JsonNode models = getModels(aaiClient, invariantIDs);
210         for (JsonNode model: models) {
211             JsonNode modelVersions = model.get("model-vers").get("model-ver");
212             for (JsonNode modelVersion: modelVersions) {
213                 final String modelVersionId = modelVersion.get("model-version-id").asText();
214                 modelVersionByModelVersionId.put(modelVersionId, modelVersion.get("model-version").asText());
215                 modelNameByModelVersionId.put(modelVersionId, modelVersion.get("model-name").asText());
216             }
217         }
218
219         nodes.forEach(node -> {
220             node.setModelVersion(modelVersionByModelVersionId.get(node.getModelVersionId()));
221             node.setModelName(modelNameByModelVersionId.get(node.getModelVersionId()));
222         });
223
224     }
225
226     private JsonNode getModels(AaiClientInterface aaiClient, Collection<String> invariantIDs) {
227         Response response = aaiClient.getVersionByInvariantId(ImmutableList.copyOf(invariantIDs));
228         try {
229             JsonNode responseJson = JACKSON_OBJECT_MAPPER.readTree(response.readEntity(String.class));
230             return responseJson.get("model");
231         } catch (Exception e) {
232             LOGGER.error(EELFLoggerDelegate.errorLogger, "Failed to getVersionByInvariantId from A&AI", e);
233         }
234         return JACKSON_OBJECT_MAPPER.createObjectNode();
235     }
236
237     private Set<String> getModelInvariantIds(Collection<AAITreeNode> nodes) {
238         return nodes.stream()
239                 .map(AAITreeNode::getModelInvariantId)
240                 .filter(Objects::nonNull)
241                 .collect(toSet());
242     }
243
244     public static class AaiRelationship {
245
246         public final String type;
247
248         public AaiRelationship(String type) {
249             this.type = type;
250         }
251
252         public AaiRelationship(NodeType nodeType) {
253             this.type = nodeType.getType();
254         }
255
256         @Override
257         public boolean equals(Object o) {
258             if (this == o) return true;
259             if (!(o instanceof AaiRelationship)) return false;
260             AaiRelationship that = (AaiRelationship) o;
261             return Objects.equals(type, that.type);
262         }
263
264         @Override
265         public int hashCode() {
266             return Objects.hash(type);
267         }
268     }
269 }