2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.vid.services;
23 import com.fasterxml.jackson.databind.JsonNode;
24 import com.fasterxml.jackson.databind.ObjectMapper;
25 import com.google.common.collect.ImmutableList;
26 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
27 import org.onap.vid.aai.AaiClientInterface;
28 import org.onap.vid.aai.util.AAITreeConverter;
29 import org.onap.vid.asdc.AsdcCatalogException;
30 import org.onap.vid.asdc.parser.ServiceModelInflator;
31 import org.onap.vid.exceptions.GenericUncheckedException;
32 import org.onap.vid.model.ServiceModel;
33 import org.onap.vid.model.aaiTree.AAITreeNode;
34 import org.onap.vid.model.aaiTree.ServiceInstance;
35 import org.onap.vid.utils.Tree;
36 import org.springframework.stereotype.Component;
38 import javax.inject.Inject;
39 import javax.ws.rs.core.Response;
41 import java.util.concurrent.*;
42 import java.util.concurrent.atomic.AtomicInteger;
44 import static java.lang.Thread.sleep;
45 import static java.util.Comparator.comparing;
46 import static java.util.stream.Collectors.toSet;
47 import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
48 import static org.onap.vid.services.AAITreeNodeBuilder.*;
51 public class AAIServiceTree {
53 private final AAITreeNodeBuilder aaiTreeNodeBuilder;
55 private final AAITreeConverter aaiTreeConverter;
57 private final AaiClientInterface aaiClient;
59 private final VidService sdcService;
61 private final ServiceModelInflator serviceModelInflator;
63 private final ObjectMapper mapper = new ObjectMapper();
65 private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(AAIServiceTree.class);
67 public static final Tree<AaiRelationship> AAI_TREE_PATHS =
68 new Tree<>(new AaiRelationship(SERVICE_INSTANCE));
71 AAI_TREE_PATHS.addPath(toAaiRelationshipList(GENERIC_VNF, VG));
72 AAI_TREE_PATHS.addPath(toAaiRelationshipList(NETWORK));
73 AAI_TREE_PATHS.addPath(toAaiRelationshipList(GENERIC_VNF, NETWORK));
74 AAI_TREE_PATHS.addPath(toAaiRelationshipList(INSTANCE_GROUP));
78 public AAIServiceTree(AaiClientInterface aaiClient, AAITreeNodeBuilder aaiTreeNodeBuilder,
79 AAITreeConverter aaiTreeConverter, VidService sdcService,
80 ServiceModelInflator serviceModelInflator) {
81 this.aaiClient = aaiClient;
82 this.aaiTreeNodeBuilder = aaiTreeNodeBuilder;
83 this.aaiTreeConverter = aaiTreeConverter;
84 this.sdcService = sdcService;
85 this.serviceModelInflator = serviceModelInflator;
88 public List<AAITreeNode> buildAAITree(String getUrl, Tree<AaiRelationship> pathsToSearch) {
90 ConcurrentSkipListSet<AAITreeNode> nodesAccumulator = createNodesAccumulator();
92 List<AAITreeNode> aaiTreeNodes = fetchAAITree(getUrl, pathsToSearch, nodesAccumulator, true);
94 enrichNodesWithModelVersionAndModelName(nodesAccumulator);
99 public ServiceInstance getServiceInstanceTopology(String globalCustomerId, String serviceType, String serviceInstanceId) {
101 String getURL = "business/customers/customer/" +
102 globalCustomerId + "/service-subscriptions/service-subscription/" +
103 serviceType + "/service-instances/service-instance/" + serviceInstanceId;
105 //Used later to get the nodes UUID
106 ConcurrentSkipListSet<AAITreeNode> nodesAccumulator = createNodesAccumulator();
108 AAITreeNode aaiTree = fetchAAITree(getURL, AAI_TREE_PATHS, nodesAccumulator, false).get(0);
110 //Populate nodes with model-name & model-version (from aai)
111 enrichNodesWithModelVersionAndModelName(nodesAccumulator);
113 final ServiceModel serviceModel = getServiceModel(aaiTree.getModelVersionId());
115 //Populate nodes with model-customization-name (from sdc model)
116 enrichNodesWithModelCustomizationName(nodesAccumulator, serviceModel);
118 return aaiTreeConverter.convertTreeToUIModel(aaiTree, globalCustomerId, serviceType, getInstantiationType(serviceModel));
121 private List<AAITreeNode> fetchAAITree(String getUrl, Tree<AaiRelationship> pathsToSearch,
122 ConcurrentSkipListSet<AAITreeNode> nodesAccumulator, boolean partialTreeOnTimeout) {
123 ThreadPoolExecutor threadPool = getThreadPool();
125 List<AAITreeNode> aaiTree = aaiTreeNodeBuilder.buildNode(SERVICE_INSTANCE,
126 getUrl, defaultIfNull(nodesAccumulator, createNodesAccumulator()),
127 threadPool, new ConcurrentLinkedQueue<>(),
128 new AtomicInteger(0), pathsToSearch);
130 boolean timeoutOccurred = waitForTreeFetch(threadPool);
132 if (timeoutOccurred) {
133 if (!partialTreeOnTimeout) {
134 throw new GenericUncheckedException("Timeout on fetchAAITree. Fetched " + nodesAccumulator.size() + " nodes for url: " + getUrl);
136 LOGGER.warn(EELFLoggerDelegate.errorLogger, "Timeout on fetchAAITree for url: " + getUrl);
142 private ConcurrentSkipListSet<AAITreeNode> createNodesAccumulator() {
143 return new ConcurrentSkipListSet<>(comparing(AAITreeNode::getUniqueNodeKey));
146 private String getInstantiationType(ServiceModel serviceModel) {
147 if (serviceModel.getService() != null && serviceModel.getService().getInstantiationType() != null) {
148 return serviceModel.getService().getInstantiationType();
154 private ServiceModel getServiceModel(String modelVersionId) {
156 final ServiceModel serviceModel = sdcService.getService(modelVersionId);
157 if (serviceModel == null) {
158 throw new GenericUncheckedException("Model version '" + modelVersionId + "' not found");
161 } catch (AsdcCatalogException e) {
162 throw new GenericUncheckedException("Exception while loading model version '" + modelVersionId + "'", e);
167 void enrichNodesWithModelCustomizationName(Collection<AAITreeNode> nodes, ServiceModel serviceModel) {
168 final Map<String, ServiceModelInflator.Names> customizationNameByVersionId = serviceModelInflator.toNamesByVersionId(serviceModel);
170 nodes.forEach(node -> {
171 final ServiceModelInflator.Names names = customizationNameByVersionId.get(node.getModelVersionId());
173 node.setKeyInModel(names.getModelKey());
174 node.setModelCustomizationName(names.getModelCustomizationName());
180 private void enrichNodesWithModelVersionAndModelName(Collection<AAITreeNode> nodes) {
182 Collection<String> invariantIDs = getModelInvariantIds(nodes);
184 Map<String, String> modelVersionByModelVersionId = new HashMap<>();
185 Map<String, String> modelNameByModelVersionId = new HashMap<>();
187 JsonNode models = getModels(aaiClient, invariantIDs);
188 for (JsonNode model: models) {
189 JsonNode modelVersions = model.get("model-vers").get("model-ver");
190 for (JsonNode modelVersion: modelVersions) {
191 final String modelVersionId = modelVersion.get("model-version-id").asText();
192 modelVersionByModelVersionId.put(modelVersionId, modelVersion.get("model-version").asText());
193 modelNameByModelVersionId.put(modelVersionId, modelVersion.get("model-name").asText());
197 nodes.forEach(node -> {
198 node.setModelVersion(modelVersionByModelVersionId.get(node.getModelVersionId()));
199 node.setModelName(modelNameByModelVersionId.get(node.getModelVersionId()));
204 private JsonNode getModels(AaiClientInterface aaiClient, Collection<String> invariantIDs) {
205 Response response = aaiClient.getVersionByInvariantId(ImmutableList.copyOf(invariantIDs));
207 JsonNode responseJson = mapper.readTree(response.readEntity(String.class));
208 return responseJson.get("model");
209 } catch (Exception e) {
210 LOGGER.error(EELFLoggerDelegate.errorLogger, "Failed to getVersionByInvariantId from A&AI", e);
212 return mapper.createObjectNode();
215 private Set<String> getModelInvariantIds(Collection<AAITreeNode> nodes) {
216 return nodes.stream()
217 .map(AAITreeNode::getModelInvariantId)
218 .filter(Objects::nonNull)
222 private boolean waitForTreeFetch(ThreadPoolExecutor threadPool) {
225 //Stop fetching information if it takes more than 1 minute
226 while (threadPool.getActiveCount() != 0 &&
231 } catch (InterruptedException e) {
232 Thread.currentThread().interrupt();
233 throw new GenericUncheckedException(e);
235 threadPool.shutdown();
239 private ThreadPoolExecutor getThreadPool() {
240 //Use at least one thread, and never more than 75% of the available thread.
241 int cores = Math.max((int)(Runtime.getRuntime().availableProcessors() * 0.75), 1);
242 BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
243 return new ThreadPoolExecutor(1, cores, 10, TimeUnit.SECONDS, queue);
246 public static class AaiRelationship {
248 public final String type;
250 public AaiRelationship(String type) {
255 public boolean equals(Object o) {
256 if (this == o) return true;
257 if (!(o instanceof AaiRelationship)) return false;
258 AaiRelationship that = (AaiRelationship) o;
259 return Objects.equals(type, that.type);
263 public int hashCode() {
264 return Objects.hash(type);