1 package org.onap.vid.services;
3 import com.fasterxml.jackson.databind.JsonNode;
4 import com.fasterxml.jackson.databind.ObjectMapper;
5 import com.google.common.collect.ImmutableList;
6 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
7 import org.onap.vid.aai.AaiClientInterface;
8 import org.onap.vid.aai.util.AAITreeConverter;
9 import org.onap.vid.asdc.AsdcCatalogException;
10 import org.onap.vid.asdc.parser.ServiceModelInflator;
11 import org.onap.vid.exceptions.GenericUncheckedException;
12 import org.onap.vid.model.ServiceModel;
13 import org.onap.vid.model.aaiTree.AAITreeNode;
14 import org.onap.vid.model.aaiTree.ServiceInstance;
15 import org.onap.vid.utils.Tree;
16 import org.springframework.stereotype.Component;
18 import javax.inject.Inject;
19 import javax.ws.rs.core.Response;
21 import java.util.concurrent.*;
22 import java.util.concurrent.atomic.AtomicInteger;
24 import static java.lang.Thread.sleep;
25 import static java.util.Comparator.comparing;
26 import static java.util.stream.Collectors.toSet;
27 import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
28 import static org.onap.vid.services.AAITreeNodeBuilder.*;
31 public class AAIServiceTree {
33 private final AAITreeNodeBuilder aaiTreeNodeBuilder;
35 private final AAITreeConverter aaiTreeConverter;
37 private final AaiClientInterface aaiClient;
39 private final VidService sdcService;
41 private final ServiceModelInflator serviceModelInflator;
43 private final ObjectMapper mapper = new ObjectMapper();
45 private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(AAIServiceTree.class);
47 public static final Tree<AaiRelationship> AAI_TREE_PATHS =
48 new Tree<>(new AaiRelationship(SERVICE_INSTANCE));
51 AAI_TREE_PATHS.addPath(toAaiRelationshipList(GENERIC_VNF, VG));
52 AAI_TREE_PATHS.addPath(toAaiRelationshipList(NETWORK));
53 AAI_TREE_PATHS.addPath(toAaiRelationshipList(GENERIC_VNF, NETWORK));
54 AAI_TREE_PATHS.addPath(toAaiRelationshipList(INSTANCE_GROUP));
58 public AAIServiceTree(AaiClientInterface aaiClient, AAITreeNodeBuilder aaiTreeNodeBuilder,
59 AAITreeConverter aaiTreeConverter, VidService sdcService,
60 ServiceModelInflator serviceModelInflator) {
61 this.aaiClient = aaiClient;
62 this.aaiTreeNodeBuilder = aaiTreeNodeBuilder;
63 this.aaiTreeConverter = aaiTreeConverter;
64 this.sdcService = sdcService;
65 this.serviceModelInflator = serviceModelInflator;
68 public List<AAITreeNode> buildAAITree(String getUrl, Tree<AaiRelationship> pathsToSearch) {
70 ConcurrentSkipListSet<AAITreeNode> nodesAccumulator = createNodesAccumulator();
72 List<AAITreeNode> aaiTreeNodes = fetchAAITree(getUrl, pathsToSearch, nodesAccumulator, true);
74 enrichNodesWithModelVersionAndModelName(nodesAccumulator);
79 public ServiceInstance getServiceInstanceTopology(String globalCustomerId, String serviceType, String serviceInstanceId) {
81 String getURL = "business/customers/customer/" +
82 globalCustomerId + "/service-subscriptions/service-subscription/" +
83 serviceType + "/service-instances/service-instance/" + serviceInstanceId;
85 //Used later to get the nodes UUID
86 ConcurrentSkipListSet<AAITreeNode> nodesAccumulator = createNodesAccumulator();
88 AAITreeNode aaiTree = fetchAAITree(getURL, AAI_TREE_PATHS, nodesAccumulator, false).get(0);
90 //Populate nodes with model-name & model-version (from aai)
91 enrichNodesWithModelVersionAndModelName(nodesAccumulator);
93 final ServiceModel serviceModel = getServiceModel(aaiTree.getModelVersionId());
95 //Populate nodes with model-customization-name (from sdc model)
96 enrichNodesWithModelCustomizationName(nodesAccumulator, serviceModel);
98 return aaiTreeConverter.convertTreeToUIModel(aaiTree, globalCustomerId, serviceType, getInstantiationType(serviceModel));
101 private List<AAITreeNode> fetchAAITree(String getUrl, Tree<AaiRelationship> pathsToSearch,
102 ConcurrentSkipListSet<AAITreeNode> nodesAccumulator, boolean partialTreeOnTimeout) {
103 ThreadPoolExecutor threadPool = getThreadPool();
105 List<AAITreeNode> aaiTree = aaiTreeNodeBuilder.buildNode(SERVICE_INSTANCE,
106 getUrl, defaultIfNull(nodesAccumulator, createNodesAccumulator()),
107 threadPool, new ConcurrentLinkedQueue<>(),
108 new AtomicInteger(0), pathsToSearch);
110 boolean timeoutOccurred = waitForTreeFetch(threadPool);
112 if (timeoutOccurred) {
113 if (!partialTreeOnTimeout) {
114 throw new GenericUncheckedException("Timeout on fetchAAITree. Fetched " + nodesAccumulator.size() + " nodes for url: " + getUrl);
116 LOGGER.warn(EELFLoggerDelegate.errorLogger, "Timeout on fetchAAITree for url: " + getUrl);
122 private ConcurrentSkipListSet<AAITreeNode> createNodesAccumulator() {
123 return new ConcurrentSkipListSet<>(comparing(AAITreeNode::getUniqueNodeKey));
126 private String getInstantiationType(ServiceModel serviceModel) {
127 if (serviceModel.getService() != null && serviceModel.getService().getInstantiationType() != null) {
128 return serviceModel.getService().getInstantiationType();
134 private ServiceModel getServiceModel(String modelVersionId) {
136 final ServiceModel serviceModel = sdcService.getService(modelVersionId);
137 if (serviceModel == null) {
138 throw new GenericUncheckedException("Model version '" + modelVersionId + "' not found");
141 } catch (AsdcCatalogException e) {
142 throw new GenericUncheckedException("Exception while loading model version '" + modelVersionId + "'", e);
147 void enrichNodesWithModelCustomizationName(Collection<AAITreeNode> nodes, ServiceModel serviceModel) {
148 final Map<String, ServiceModelInflator.Names> customizationNameByVersionId = serviceModelInflator.toNamesByVersionId(serviceModel);
150 nodes.forEach(node -> {
151 final ServiceModelInflator.Names names = customizationNameByVersionId.get(node.getModelVersionId());
153 node.setKeyInModel(names.getModelKey());
154 node.setModelCustomizationName(names.getModelCustomizationName());
160 private void enrichNodesWithModelVersionAndModelName(Collection<AAITreeNode> nodes) {
162 Collection<String> invariantIDs = getModelInvariantIds(nodes);
164 Map<String, String> modelVersionByModelVersionId = new HashMap<>();
165 Map<String, String> modelNameByModelVersionId = new HashMap<>();
167 JsonNode models = getModels(aaiClient, invariantIDs);
168 for (JsonNode model: models) {
169 JsonNode modelVersions = model.get("model-vers").get("model-ver");
170 for (JsonNode modelVersion: modelVersions) {
171 final String modelVersionId = modelVersion.get("model-version-id").asText();
172 modelVersionByModelVersionId.put(modelVersionId, modelVersion.get("model-version").asText());
173 modelNameByModelVersionId.put(modelVersionId, modelVersion.get("model-name").asText());
177 nodes.forEach(node -> {
178 node.setModelVersion(modelVersionByModelVersionId.get(node.getModelVersionId()));
179 node.setModelName(modelNameByModelVersionId.get(node.getModelVersionId()));
184 private JsonNode getModels(AaiClientInterface aaiClient, Collection<String> invariantIDs) {
185 Response response = aaiClient.getVersionByInvariantId(ImmutableList.copyOf(invariantIDs));
187 JsonNode responseJson = mapper.readTree(response.readEntity(String.class));
188 return responseJson.get("model");
189 } catch (Exception e) {
190 LOGGER.error(EELFLoggerDelegate.errorLogger, "Failed to getVersionByInvariantId from A&AI", e);
192 return mapper.createObjectNode();
195 private Set<String> getModelInvariantIds(Collection<AAITreeNode> nodes) {
196 return nodes.stream()
197 .map(AAITreeNode::getModelInvariantId)
198 .filter(Objects::nonNull)
202 private boolean waitForTreeFetch(ThreadPoolExecutor threadPool) {
205 //Stop fetching information if it takes more than 1 minute
206 while (threadPool.getActiveCount() != 0 &&
211 } catch (InterruptedException e) {
212 Thread.currentThread().interrupt();
213 throw new GenericUncheckedException(e);
215 threadPool.shutdown();
219 private ThreadPoolExecutor getThreadPool() {
220 //Use at least one thread, and never more than 75% of the available thread.
221 int cores = Math.max((int)(Runtime.getRuntime().availableProcessors() * 0.75), 1);
222 BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
223 return new ThreadPoolExecutor(1, cores, 10, TimeUnit.SECONDS, queue);
226 public static class AaiRelationship {
228 public final String type;
230 public AaiRelationship(String type) {
235 public boolean equals(Object o) {
236 if (this == o) return true;
237 if (!(o instanceof AaiRelationship)) return false;
238 AaiRelationship that = (AaiRelationship) o;
239 return Objects.equals(type, that.type);
243 public int hashCode() {
244 return Objects.hash(type);