2 * ============LICENSE_START===================================================
3 * Copyright (c) 2018 Amdocs
4 * ============================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 * ============LICENSE_END=====================================================
18 package org.onap.sdnc.apps.pomba.servicedecomposition.util;
20 import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.FETCH_RESOURCE_FAILED;
21 import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.INVALID_URL;
22 import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.SERVICE_INSTANCE_NOT_FOUND;
24 import java.text.MessageFormat;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.List;
31 import javax.ws.rs.core.MediaType;
32 import javax.ws.rs.core.MultivaluedHashMap;
33 import javax.ws.rs.core.MultivaluedMap;
34 import javax.ws.rs.core.Response.Status;
36 import org.json.JSONArray;
37 import org.json.JSONObject;
38 import org.onap.aai.restclient.client.OperationResult;
39 import org.onap.aai.restclient.client.RestClient;
40 import org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
47 public class RestUtil {
50 private static final String RELATIONSHIP_KEY = "relationship";
51 private static final String RELATIONSHIP_LIST_KEY = "relationship-list";
52 // Parameters for Query AAI Model Data API
54 private static final String TRANSACTION_ID = "X-TransactionId";
55 private static final String FROM_APP_ID = "X-FromAppId";
56 private static final String APP_NAME = "aaiCtxBuilder";
57 private static final String AUTHORIZATION = "Authorization";
59 private static final Resource GENERIC_VNF = new Resource("generic-vnf");
60 private static final Resource VF_MODULE = new Resource("vf-module");
61 private static final Resource L3_NETWORK = new Resource("l3-network");
63 public static class Resource {
64 private String resourceName;
65 private String collectionName;
67 private Resource(String resource) {
68 this.resourceName = resource;
69 this.collectionName = resource + "s";
72 private String getResourceName() {
73 return this.resourceName;
76 private String getCollectionName() {
77 return this.collectionName;
81 public String toString() {
82 return "Resource [resourceName=" + resourceName + ", collectionName=" + collectionName + "]";
86 private static final String JSON_ATT_RELATED_TO = "related-to";
87 private static final String JSON_ATT_RELATED_LINK = "related-link";
89 private static final String EMPTY_JSON_STRING = "{}";
91 private static final String DEPTH = "?depth=2";
92 private static Logger logger = LoggerFactory.getLogger(RestUtil.class);
95 throw new IllegalStateException("Utility class");
99 * Validates the URL parameter.
101 * @throws DiscoveryException if there is missing parameter
103 public static void validateURL(String serviceInstanceId) throws DiscoveryException {
105 if (serviceInstanceId == null || serviceInstanceId.isEmpty()) {
106 throw new DiscoveryException(INVALID_URL, Status.BAD_REQUEST);
110 private static String generateServiceInstanceURL(String siPath, String serviceInstanceId) {
111 return MessageFormat.format(siPath, serviceInstanceId);
117 * @param aaiBasicAuthorization
118 * @param aaiServiceInstancePath
119 * @param aaiResourceList
120 * @param transactionId
121 * @param serviceInstanceId
124 * @throws DiscoveryException
126 public static JSONObject retrieveAAIModelData(RestClient aaiClient, String baseURL, String aaiBasicAuthorization, String aaiServiceInstancePath, String aaiResourceList,
127 String transactionId, String serviceInstanceId) throws DiscoveryException {
129 // Follow two variables for transform purpose
130 String url = baseURL + generateServiceInstanceURL(aaiServiceInstancePath, serviceInstanceId);
131 // Response from service instance API call
132 JSONObject serviceInstancePayload = new JSONObject(
133 getResource(aaiClient, url, aaiBasicAuthorization, transactionId));
134 // Handle the case if the service instance is not found in AAI
135 if (serviceInstancePayload.length() == 0) {
136 logger.info("Service Instance {} is not found from AAI", serviceInstanceId);
137 // Only return the empty Json on the root level. i.e service instance
138 throw new DiscoveryException(SERVICE_INSTANCE_NOT_FOUND, Status.NOT_FOUND);
141 Map<String, List<String>> relationMap = extractRelationships(serviceInstancePayload);
142 logger.info("The number of the relationship types for service instance id {} is: {}", serviceInstanceId,
145 JSONObject response = processVNFRelationMap(aaiClient, aaiResourceList, baseURL, aaiBasicAuthorization, transactionId, relationMap, serviceInstancePayload);
147 if (relationMap.containsKey(L3_NETWORK.getResourceName())) {
148 List<String> l3NetworkRelatedLinks = relationMap.get(L3_NETWORK.getResourceName());
149 List<JSONObject> l3networkPayload = processResourceList(aaiClient, baseURL, aaiBasicAuthorization, transactionId,
150 L3_NETWORK.getResourceName(), l3NetworkRelatedLinks);
152 response.put(L3_NETWORK.getCollectionName(), l3networkPayload);
162 * @param transactionId
164 * @throws DiscoveryException
166 private static JSONObject processVNFRelationMap(RestClient aaiClient, String aaiResourceList, String baseURL, String aaiBasicAuthorization, String transactionId,
167 Map<String, List<String>> relationMap, JSONObject serviceInstancePayload) throws DiscoveryException {
168 List<JSONObject> vnfLst = new ArrayList<>(); // List of the VNF JSON along with related resources
170 JSONObject response = serviceInstancePayload;
172 List<Resource> resourceTypes = getResourceTypes(aaiResourceList);
174 if (relationMap.get(GENERIC_VNF.getResourceName()) != null) {
175 List<JSONObject> vnfList = processResourceList(aaiClient, baseURL, aaiBasicAuthorization, transactionId,
176 GENERIC_VNF.getResourceName(), relationMap.get(GENERIC_VNF.getResourceName()));
177 // Logic to Create the Generic VNF JSON and extract further relationships
178 for (JSONObject vnfPayload : vnfList) {
179 Map<String, List<String>> vnfRelationMap = extractRelationships(vnfPayload);
180 String vnfId = vnfPayload.optString("vnf-id");
182 for (Resource resourceType : resourceTypes) {
183 List<String> vnfcLinkLst = vnfRelationMap.get(resourceType.getResourceName());
184 if (vnfcLinkLst == null || vnfcLinkLst.isEmpty()) {
185 logger.info("No relationships found for generic-vnf '{}', resource type '{}'", vnfId,
186 resourceType.getResourceName());
190 logger.info("Number of relationships found for generic-vnf '{}', resource type '{}' are: {}", vnfId,
191 resourceType.getResourceName(), vnfcLinkLst.size());
192 List<JSONObject> vnfcList = processResourceList(aaiClient, baseURL, aaiBasicAuthorization,
193 transactionId, resourceType.getResourceName(), vnfcLinkLst);
194 vnfPayload.put(resourceType.getCollectionName(), vnfcList);
197 // Process vf-module looking for l3-network:
198 processVfModuleList(aaiClient, baseURL, aaiBasicAuthorization, transactionId, vnfPayload);
199 // Add final vnf payload to list
200 vnfLst.add(vnfPayload);
203 logger.info("No {} found for service-instance-id: {}", GENERIC_VNF.getResourceName(),
204 serviceInstancePayload.optString("service-instance-id"));
207 // Add generic vnf with related resource payload to response
208 if (!vnfLst.isEmpty()) {
209 response.put(GENERIC_VNF.getCollectionName(), vnfLst);
215 private static void processVfModuleList(RestClient aaiClient, String baseURL, String aaiBasicAuthorization, String transactionId,
216 JSONObject vnfPayload) throws DiscoveryException {
218 if (!vnfPayload.has(VF_MODULE.getCollectionName())) {
222 JSONObject vfmoduleCollection = vnfPayload.getJSONObject(VF_MODULE.getCollectionName());
224 if (!vfmoduleCollection.has(VF_MODULE.getResourceName())) {
228 JSONArray vfModuleList = vfmoduleCollection.getJSONArray(VF_MODULE.getResourceName());
230 for (int i = 0; i < vfModuleList.length(); i++) {
231 JSONObject vfModulePayload = vfModuleList.optJSONObject(i);
232 if (vfModulePayload == null) {
233 logger.error("VF Module not found for vnf-id {}", vnfPayload.opt("vnf-id"));
236 processVfModule(aaiClient, baseURL, aaiBasicAuthorization, transactionId, vfModulePayload);
240 private static void processVfModule(RestClient aaiClient, String baseURL, String aaiBasicAuthorization,
241 String transactionId, JSONObject vfModulePayload) throws DiscoveryException {
243 Map<String, List<String>> relationMap = extractRelationships(vfModulePayload);
244 Object vfModuleId = vfModulePayload.opt("vf-module-id");
246 List<String> l3NetworkRelatedLinks = relationMap.get(L3_NETWORK.getResourceName());
247 if (l3NetworkRelatedLinks == null) {
248 logger.info("No relationships found for vf-module '{}', resource type '{}'", vfModuleId, L3_NETWORK.getResourceName());
249 // No L3-network relationships exist.
253 logger.info("Number of relationships found for vf-module '{}', resource type '{}' are: {}", vfModuleId, L3_NETWORK.getResourceName(), l3NetworkRelatedLinks.size());
255 List<JSONObject> l3NetworkObjects = processResourceList(aaiClient, baseURL, aaiBasicAuthorization,
256 transactionId, L3_NETWORK.getResourceName(), l3NetworkRelatedLinks);
258 // Add l3-network with related resource payload to the vfModulePayload:
259 vfModulePayload.put(L3_NETWORK.getCollectionName(), l3NetworkObjects);
265 * @param transactionId
266 * @param resourceType
267 * @param resourceList
269 * @throws DiscoveryException
271 private static List<JSONObject> processResourceList(RestClient aaiClient, String aaiBaseURL, String aaiBasicAuthorization, String transactionId,
272 String resourceType, List<String> resourceList) throws DiscoveryException {
273 List<JSONObject> resourcePayloadList = new ArrayList<>();
274 for (String resourceLink : resourceList) {
275 String resourceURL = aaiBaseURL + resourceLink;
276 // With latest AAI development, in order to retrieve the both generic VNF + vf_module, we can use
277 // one API call but with depth=2
278 if (resourceType.equals(GENERIC_VNF.getResourceName())) {
279 resourceURL += DEPTH;
282 // Response from generic VNF API call
283 JSONObject resourcePayload = new JSONObject(
284 getResource(aaiClient, resourceURL, aaiBasicAuthorization, transactionId));
285 if (resourcePayload.length() == 0) {
286 logger.info("Resource with url {} is not found from AAI", resourceLink);
288 resourcePayloadList.add(resourcePayload);
291 return resourcePayloadList;
295 * Extract the related-Link from Json payload. For example
298 * "related-to": "vnfc",
299 * "related-link": "/aai/v11/network/vnfcs/vnfc/zrdm5aepdg01vmg003",
300 * "relationship-data": [
302 * "relationship-key": "vnfc.vnfc-name",
303 * "relationship-value": "zrdm5aepdg01vmg003"
308 * @param payload input pay load json.
309 * @return Map of "related-to" to list of "related-link" strings.
311 private static Map<String, List<String>> extractRelationships(JSONObject payload) {
313 Map<String, List<String>> relationMap = new HashMap<>();
315 if (!payload.has(RELATIONSHIP_LIST_KEY)) {
319 JSONObject relationshipList = payload.getJSONObject(RELATIONSHIP_LIST_KEY);
321 if (!relationshipList.has(RELATIONSHIP_KEY)) {
325 JSONArray relationships = relationshipList.getJSONArray(RELATIONSHIP_KEY);
327 for (int i = 0; i < relationships.length(); i++) {
328 JSONObject obj = relationships.optJSONObject(i);
329 String relatedToObj = obj.optString(JSON_ATT_RELATED_TO);
331 if (relatedToObj == null) {
332 logger.error("Related-To Object is null");
335 List<String> relatedLinkList = relationMap.get(relatedToObj);
336 if (relatedLinkList == null) {
337 relatedLinkList = new ArrayList<>();
338 relationMap.put(relatedToObj, relatedLinkList);
340 String relatedLinkObj = obj.getString(JSON_ATT_RELATED_LINK);
341 relatedLinkList.add(relatedLinkObj);
350 * @param aaiBasicAuthorization
353 * @throws DiscoveryException
355 private static String getResource(RestClient client, String url, String aaiBasicAuthorization, String transId)
356 throws DiscoveryException {
357 OperationResult result = client.get(url, buildHeaders(aaiBasicAuthorization, transId), MediaType.valueOf(MediaType.APPLICATION_JSON));
359 if (result.wasSuccessful()) {
360 return result.getResult();
361 } else if (result.getResultCode() == 404) {
362 // Resource not found, generate empty JSON format
363 logger.info("Resource for {} is not found, return empty Json format", url);
364 return EMPTY_JSON_STRING;
366 throw new DiscoveryException(FETCH_RESOURCE_FAILED, Status.INTERNAL_SERVER_ERROR, result.getFailureCause());
370 private static Map<String, List<String>> buildHeaders(String aaiBasicAuthorization, String transactionId) {
371 MultivaluedMap<String, String> headers = new MultivaluedHashMap<>();
372 headers.put(TRANSACTION_ID, Collections.singletonList(transactionId));
373 headers.put(FROM_APP_ID, Collections.singletonList(APP_NAME));
374 headers.put(AUTHORIZATION, Collections.singletonList(aaiBasicAuthorization));
378 private static List<Resource> getResourceTypes(String aaiResourceList) {
379 List<Resource> resources = new ArrayList<>();
380 String noSpaceAaiResourceList = aaiResourceList.replaceAll("\\s", "");
381 String[] resourceList = noSpaceAaiResourceList.split(",");
382 for (int i = 0; i < resourceList.length; i++) {
383 resources.add(new Resource(resourceList[i]));