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.RELATIONSHIP_LINK_PARSE_ERROR;
23 import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.SERVICE_INSTANCE_NOT_FOUND;
24 import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.SERVICE_RELATIONSHIP_PARSE_ERROR;
26 import com.sun.jersey.core.util.MultivaluedMapImpl;
27 import java.text.MessageFormat;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.List;
33 import javax.ws.rs.core.MediaType;
34 import javax.ws.rs.core.MultivaluedMap;
35 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.logging.ref.slf4j.ONAPLogAdapter;
41 import org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
48 public class RestUtil {
49 // Parameters for Query AAI Model Data API
51 private static final String TRANSACTION_ID = "X-TransactionId";
52 private static final String FROM_APP_ID = "X-FromAppId";
53 private static final String APP_NAME = "aaiCtxBuilder";
55 private static final Resource GENERIC_VNF = new Resource("generic-vnf");
57 public static class Resource {
58 private String resourceName;
59 private String collectionName;
61 private Resource(String resource) {
62 this.resourceName = resource;
63 this.collectionName = resource + "s";
66 private String getResourceName() {
67 return this.resourceName;
70 private String getCollectionName() {
71 return this.collectionName;
75 private static final String JSON_ATT_RELATED_TO = "related-to";
76 private static final String JSON_ATT_RELATED_LINK = "related-link";
78 private static final String EMPTY_JSON_STRING = "{}";
80 private static final String DEPTH = "?depth=2";
81 private static Logger logger = LoggerFactory.getLogger(RestUtil.class);
84 * Validates the URL parameter.
86 * @throws DiscoveryException if there is missing parameter
88 public static void validateURL(String serviceInstanceId) throws DiscoveryException {
90 if (serviceInstanceId == null || serviceInstanceId.isEmpty()) {
91 throw new DiscoveryException(INVALID_URL, Status.BAD_REQUEST);
95 private static String generateServiceInstanceURL(String siPath, String serviceInstanceId) {
96 return MessageFormat.format(siPath, serviceInstanceId);
101 * Trigger external API call to AAI to retrieve Service Instance data (i.e. genericVNF and VNFC)
107 * @param aaiServiceInstancePath
108 * @param transactionId
109 * @param serviceInstanceId
110 * @param modelVersionId
111 * @param modelInvariantId
113 * @throws DiscoveryException
115 public static JSONObject retrieveAAIModelData(RestClient aaiClient, String baseURL, String aaiServiceInstancePath, String aaiResourceList,
116 String transactionId, String serviceInstanceId, ONAPLogAdapter adapter) throws DiscoveryException {
118 // Follow two variables for transform purpose
119 String url = baseURL + generateServiceInstanceURL(aaiServiceInstancePath, serviceInstanceId);
120 // Response from service instance API call
121 JSONObject serviceInstancePayload = new JSONObject(
122 getResource(aaiClient, url, transactionId));
123 // Handle the case if the service instance is not found in AAI
124 if (serviceInstancePayload == null || serviceInstancePayload.length() == 0) {
125 logger.info("Service Instance " + serviceInstanceId + " is not found from AAI");
126 // Only return the empty Json on the root level. i.e service instance
127 throw new DiscoveryException(SERVICE_INSTANCE_NOT_FOUND, Status.NOT_FOUND);
130 HashMap<String, List<String>> relationMap = extractServiceRelationShips(serviceInstancePayload);
131 logger.info("The number of the relationships for service instance id {} is: {}", serviceInstanceId,
134 JSONObject response = processVNFRelationMap(aaiClient, aaiResourceList, baseURL, transactionId, relationMap, serviceInstancePayload);
142 * @param transactionId
144 * @throws DiscoveryException
146 private static JSONObject processVNFRelationMap(RestClient aaiClient, String aaiResourceList, String baseURL, String transactionId,
147 HashMap<String, List<String>> relationMap, JSONObject serviceInstancePayload) throws DiscoveryException {
148 List<JSONObject> vnfLst = new ArrayList<JSONObject>(); // List of the VNF JSON along with related resources
150 JSONObject response = serviceInstancePayload;
152 List<Resource> resourceTypes = getResourceTypes(aaiResourceList);
154 if (relationMap.get(GENERIC_VNF.getResourceName()) != null) {
155 List<JSONObject> vnfList = processResourceList(aaiClient, baseURL, transactionId, GENERIC_VNF.getResourceName(),
156 relationMap.get(GENERIC_VNF.getResourceName()));
157 // Logic to Create the Generic VNF JSON and extract further relationships
158 for (JSONObject vnfPayload : vnfList) {
159 for (Resource resourceType : resourceTypes) {
160 List<String> vnfcLinkLst = extractRelatedLink(vnfPayload, resourceType.getResourceName());
161 if (vnfcLinkLst != null && !vnfcLinkLst.isEmpty()) {
162 logger.info("The number of the API call for vnfc is:" + vnfcLinkLst.size());
163 List<JSONObject> vnfcList = processResourceList(aaiClient, baseURL, transactionId,
164 resourceType.getResourceName(), vnfcLinkLst);
165 if (vnfcList != null) {
166 vnfPayload.put(resourceType.getCollectionName(), vnfcList);
169 logger.info("No " + resourceType.getResourceName() + " found for vnf-id:" + vnfPayload.getString("vnf-id"));
172 // Add final vnf payload to list
173 vnfLst.add(vnfPayload);
176 logger.info("No " + GENERIC_VNF.getResourceName() + " found for :" + serviceInstancePayload.getString("service-instance-id"));
179 // Add generic vnf with related resource payload to response
180 if (vnfLst != null && !vnfLst.isEmpty()) {
181 response.put(GENERIC_VNF.getCollectionName(), vnfLst);
191 * @param transactionId
192 * @param resourceType
193 * @param resourceList
195 * @throws DiscoveryException
197 private static List<JSONObject> processResourceList(RestClient aaiClient, String aaiBaseURL, String transactionId,
198 String resourceType, List<String> resourceList) throws DiscoveryException {
199 List<JSONObject> resourcePayloadList = new ArrayList<JSONObject>();
200 for (String resourceLink : resourceList) {
201 String resourceURL = aaiBaseURL + resourceLink;
202 // With latest AAI development, in order to retrieve the both generic VNF + vf_module, we can use
203 // one API call but with depth=2
204 if (resourceType.equals(GENERIC_VNF.getResourceName())) {
205 resourceURL += DEPTH;
208 // Response from generic VNF API call
209 JSONObject resourcePayload = new JSONObject(
210 getResource(aaiClient, resourceURL, transactionId));
211 if (resourcePayload == null || resourcePayload.length() == 0) {
212 logger.info("Resource with url " + resourceLink + " is not found from AAI");
214 resourcePayloadList.add(resourcePayload);
217 return resourcePayloadList;
222 * @param serviceInstancePayload
225 * @throws DiscoveryException
227 private static HashMap<String, List<String>> extractServiceRelationShips(JSONObject payload)
228 throws DiscoveryException {
230 JSONArray relationships = null;
231 HashMap<String, List<String>> relationMap = new HashMap<String, List<String>>();
232 logger.info("Fetching Service Instance Relationships");
234 JSONObject relationshipList = payload.getJSONObject("relationship-list");
235 if (relationshipList != null) {
236 relationships = relationshipList.getJSONArray("relationship");
238 } catch (Exception e) {
239 logger.error(e.getMessage());
240 throw new DiscoveryException(SERVICE_RELATIONSHIP_PARSE_ERROR, Status.INTERNAL_SERVER_ERROR,
244 if (relationships != null && relationships.length() > 0) {
245 for (int i = 0; i < relationships.length(); i++) {
246 JSONObject obj = relationships.optJSONObject(i);
247 String relatedToObj = obj.getString(JSON_ATT_RELATED_TO);
248 String relatedLinkObj = obj.getString(JSON_ATT_RELATED_LINK);
250 if (relatedToObj == null) {
251 logger.info("Related-To Object found null");
254 List<String> relatedLinkList = relationMap.get(relatedToObj);
255 if (relatedLinkList == null) {
256 relatedLinkList = new ArrayList<>();
257 relationMap.put(relatedToObj, relatedLinkList);
259 relatedLinkList.add(relatedLinkObj);
271 * @throws DiscoveryException
273 private static String getResource(RestClient client, String url, String transId)
274 throws DiscoveryException {
275 OperationResult result = client.get(url, buildHeaders(transId), MediaType.valueOf(MediaType.APPLICATION_JSON));
277 if (result.getResultCode() == 200) {
278 String jsonString = result.getResult();
280 } else if (result.getResultCode() == 404) {
281 // Resource not found, generate empty JSON format
282 logger.info("Resource for " + url + " is not found " + "return empty Json format");
283 return EMPTY_JSON_STRING;
285 throw new DiscoveryException(FETCH_RESOURCE_FAILED, Status.INTERNAL_SERVER_ERROR, result.getFailureCause());
290 * Extract the related-Link from Json payload. For example
292 * "related-to": "vnfc",
293 * "related-link": "/aai/v11/network/vnfcs/vnfc/zrdm5aepdg01vmg003",
294 * "relationship-data": [
296 * "relationship-key": "vnfc.vnfc-name",
297 * "relationship-value": "zrdm5aepdg01vmg003"
302 private static List<String> extractRelatedLink(JSONObject payload, String catalog) throws DiscoveryException {
303 List<String> relatedLinkList = new ArrayList<String>();
304 JSONArray relationships = null;
305 logger.info("Fetching relationships for resource type: " + catalog);
307 JSONObject relationshipLst = payload.getJSONObject("relationship-list");
308 if (relationshipLst != null) {
309 relationships = relationshipLst.getJSONArray("relationship");
312 } catch (Exception e) {
313 logger.error(e.getMessage());
314 throw new DiscoveryException(RELATIONSHIP_LINK_PARSE_ERROR, Status.INTERNAL_SERVER_ERROR, e.getMessage());
317 if (relationships != null && relationships.length() > 0) {
318 for (int i = 0; i < relationships.length(); i++) {
319 Object relatedToObj = null;
320 Object relatedLinkObj = null;
322 JSONObject obj = relationships.optJSONObject(i);
323 relatedToObj = obj.get(JSON_ATT_RELATED_TO);
325 if (relatedToObj.toString().equals(catalog)) {
326 relatedLinkObj = obj.get(JSON_ATT_RELATED_LINK);
327 if (relatedLinkObj != null) {
328 relatedLinkList.add(relatedLinkObj.toString());
334 if (relatedLinkList != null) {
336 "Number of relationships found for resource type: " + catalog + " are: " + relatedLinkList.size());
338 return relatedLinkList;
343 private static Map<String, List<String>> buildHeaders(String transactionId) {
344 MultivaluedMap<String, String> headers = new MultivaluedMapImpl();
345 headers.put(TRANSACTION_ID, Collections.singletonList(transactionId));
346 headers.put(FROM_APP_ID, Collections.singletonList(APP_NAME));
350 private static List<Resource> getResourceTypes(String aaiResourceList) {
351 List<Resource> resources = new ArrayList<Resource>();
352 String[] resourceList = aaiResourceList.split(",");
353 for (int i = 0; i < resourceList.length; i++) {
354 resources.add(new Resource(resourceList[i]));