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;
46 public class RestUtil {
47 // Parameters for Query AAI Model Data API
49 private static final String TRANSACTION_ID = "X-TransactionId";
50 private static final String FROM_APP_ID = "X-FromAppId";
51 private static final String APP_NAME = "aaiCtxBuilder";
56 VNF("generic-vnf"), VNFC("vnfc"), VSERVER("vserver"), L3NETWORK("l3-network");
58 private final String resourceName;
59 private final String collectionName;
61 private Catalog(String objName) {
62 this.resourceName = objName;
63 this.collectionName = objName + "s"; // make plural
66 public String objName() {
72 private static final String JSON_ATT_RELATED_TO = "related-to";
73 private static final String JSON_ATT_RELATED_LINK = "related-link";
75 private static final String EMPTY_JSON_STRING = "{}";
77 private static final String DEPTH = "?depth=2";
78 private static Logger logger = LoggerFactory.getLogger(RestUtil.class);
81 * Validates the URL parameter.
83 * @throws DiscoveryException if there is missing parameter
85 public static void validateURL(String serviceInstanceId) throws DiscoveryException {
87 if (serviceInstanceId == null || serviceInstanceId.isEmpty()) {
88 throw new DiscoveryException(INVALID_URL, Status.BAD_REQUEST);
92 private static String generateServiceInstanceURL(String siPath, String serviceInstanceId) {
93 return MessageFormat.format(siPath, serviceInstanceId);
98 * Trigger external API call to AAI to retrieve Service Instance data (i.e. genericVNF and VNFC)
104 * @param aaiServiceInstancePath
105 * @param transactionId
106 * @param serviceInstanceId
107 * @param modelVersionId
108 * @param modelInvariantId
110 * @throws DiscoveryException
112 public static JSONObject retrieveAAIModelData(RestClient aaiClient, String baseURL, String aaiServiceInstancePath,
113 String transactionId, String serviceInstanceId, ONAPLogAdapter adapter) throws DiscoveryException {
115 // Follow two variables for transform purpose
116 String url = baseURL + generateServiceInstanceURL(aaiServiceInstancePath, serviceInstanceId);
117 // Response from service instance API call
118 JSONObject serviceInstancePayload = new JSONObject(
119 getResource(aaiClient, url, transactionId, MediaType.valueOf(MediaType.APPLICATION_XML)));
120 // Handle the case if the service instance is not found in AAI
121 if (serviceInstancePayload == null || serviceInstancePayload.length() == 0) {
122 logger.info("Service Instance " + serviceInstanceId + " is not found from AAI");
123 // Only return the empty Json on the root level. i.e service instance
124 throw new DiscoveryException(SERVICE_INSTANCE_NOT_FOUND, Status.NOT_FOUND);
127 HashMap<String, List<String>> relationMap = extractServiceRelationShips(serviceInstancePayload);
128 logger.info("The number of the relationships for service instance id {} is: {}", serviceInstanceId,
131 JSONObject response = processVNFRelationMap(aaiClient, baseURL, transactionId, relationMap, serviceInstancePayload);
139 * @param transactionId
141 * @throws DiscoveryException
143 private static JSONObject processVNFRelationMap(RestClient aaiClient, String baseURL, String transactionId,
144 HashMap<String, List<String>> relationMap, JSONObject serviceInstancePayload) throws DiscoveryException {
145 List<JSONObject> vnfLst = new ArrayList<JSONObject>(); // List of the VNF JSON along with related resources
147 JSONObject response = serviceInstancePayload;
150 if (relationMap.get(Catalog.VNF.resourceName) != null) {
151 List<JSONObject> vnfList = processResourceList(aaiClient, baseURL, transactionId, Catalog.VNF.resourceName,
152 relationMap.get(Catalog.VNF.resourceName));
153 // Logic to Create the Generic VNF JSON and extract further relationships
154 for (JSONObject vnfPayload : vnfList) {
155 List<String> vnfcLinkLst = extractRelatedLink(vnfPayload, Catalog.VNFC.resourceName);
156 if (vnfcLinkLst != null && vnfcLinkLst.size() != 0) {
157 logger.info("The number of the API call for vnfc is:" + vnfcLinkLst.size());
158 List<JSONObject> vnfcList = processResourceList(aaiClient, baseURL, transactionId,
159 Catalog.VNFC.resourceName, vnfcLinkLst);
160 if (vnfcList != null) {
161 vnfPayload.put(Catalog.VNFC.collectionName, vnfcList);
164 logger.info("No vnfc found for vnf-id:" + vnfPayload.getString("vnf-id"));
167 List<String> networkLinkLst = extractRelatedLink(vnfPayload, Catalog.L3NETWORK.resourceName);
168 if (networkLinkLst != null && networkLinkLst.size() != 0) {
169 logger.info("The number of the API call for l3-network is:" + networkLinkLst.size());
170 List<JSONObject> networkList = processResourceList(aaiClient, baseURL, transactionId,
171 Catalog.L3NETWORK.resourceName, networkLinkLst);
172 if (networkList != null) {
173 vnfPayload.put(Catalog.L3NETWORK.collectionName, networkList);
176 logger.info("No l3-network found for vnf-id:" + vnfPayload.getString("vnf-id"));
178 List<String> vserverLinkLst = extractRelatedLink(vnfPayload, Catalog.VSERVER.resourceName);
179 if (vserverLinkLst != null && vserverLinkLst.size() != 0) {
180 logger.info("The number of the API call for vserver is:" + vserverLinkLst.size());
181 List<JSONObject> vserverList = processResourceList(aaiClient, baseURL, transactionId,
182 Catalog.VSERVER.resourceName, vserverLinkLst);
183 if (vserverList != null) {
184 vnfPayload.put(Catalog.VSERVER.collectionName, vserverList);
187 logger.info("No vserver found for vnf-id:" + vnfPayload.getString("vnf-id"));
190 // Add final vnf payload to list
191 vnfLst.add(vnfPayload);
194 logger.info("No generic vnf found for :" + serviceInstancePayload.getString("service-instance-id"));
197 // Add generic vnf with related resource payload to response
198 if (vnfLst != null && vnfLst.size() != 0) {
199 response.put(Catalog.VNF.collectionName, vnfLst);
210 * @param transactionId
211 * @param resourceType
212 * @param resourceList
214 * @throws DiscoveryException
216 private static List<JSONObject> processResourceList(RestClient aaiClient, String aaiBaseURL, String transactionId,
217 String resourceType, List<String> resourceList) throws DiscoveryException {
218 List<JSONObject> resourcePayloadList = new ArrayList<JSONObject>();
219 for (String resourceLink : resourceList) {
220 String resourceURL = aaiBaseURL + resourceLink;
221 // With latest AAI development, in order to retrieve the both generic VNF + vf_module, we can use
222 // one API call but with depth=2
223 if (resourceType.equals(Catalog.VNF.resourceName)) {
224 resourceURL += DEPTH;
227 // Response from generic VNF API call
228 JSONObject resourcePayload = new JSONObject(
229 getResource(aaiClient, resourceURL, transactionId, MediaType.valueOf(MediaType.APPLICATION_XML)));
230 if (resourcePayload == null || resourcePayload.length() == 0) {
231 logger.info("Resource with url " + resourceLink + " is not found from AAI");
233 resourcePayloadList.add(resourcePayload);
236 return resourcePayloadList;
241 * @param serviceInstancePayload
244 * @throws DiscoveryException
246 private static HashMap<String, List<String>> extractServiceRelationShips(JSONObject payload)
247 throws DiscoveryException {
249 JSONArray relationships = null;
250 HashMap<String, List<String>> relationMap = new HashMap<String, List<String>>();
251 logger.info("Fetching Service Instance Relationships");
253 JSONObject relationshipList = payload.getJSONObject("relationship-list");
254 if (relationshipList != null) {
255 relationships = relationshipList.getJSONArray("relationship");
257 } catch (Exception e) {
258 logger.error(e.getMessage());
259 throw new DiscoveryException(SERVICE_RELATIONSHIP_PARSE_ERROR, Status.INTERNAL_SERVER_ERROR,
263 if (relationships != null && relationships.length() > 0) {
264 for (int i = 0; i < relationships.length(); i++) {
265 JSONObject obj = relationships.optJSONObject(i);
266 String relatedToObj = obj.getString(JSON_ATT_RELATED_TO);
267 String relatedLinkObj = obj.getString(JSON_ATT_RELATED_LINK);
269 if (relatedToObj == null) {
270 logger.info("Related-To Object found null");
273 List<String> relatedLinkList = relationMap.get(relatedToObj.toString());
274 if (relatedLinkList == null) {
275 relatedLinkList = new ArrayList<>();
276 relationMap.put(relatedToObj.toString(), relatedLinkList);
278 relatedLinkList.add(relatedLinkObj.toString());
290 * @throws DiscoveryException
292 private static String getResource(RestClient client, String url, String transId, MediaType mediaType)
293 throws DiscoveryException {
294 OperationResult result = client.get(url, buildHeaders(transId), MediaType.valueOf(MediaType.APPLICATION_JSON));
296 if (result.getResultCode() == 200) {
297 String jsonString = result.getResult();
299 } else if (result.getResultCode() == 404) {
300 // Resource not found, generate empty JSON format
301 logger.info("Resource for " + url + " is not found " + "return empty Json format");
302 return EMPTY_JSON_STRING;
304 throw new DiscoveryException(FETCH_RESOURCE_FAILED, Status.INTERNAL_SERVER_ERROR, result.getFailureCause());
309 * Extract the related-Link from Json payload. For example
311 * "related-to": "vnfc",
312 * "related-link": "/aai/v11/network/vnfcs/vnfc/zrdm5aepdg01vmg003",
313 * "relationship-data": [
315 * "relationship-key": "vnfc.vnfc-name",
316 * "relationship-value": "zrdm5aepdg01vmg003"
321 private static List<String> extractRelatedLink(JSONObject payload, String catalog) throws DiscoveryException {
322 List<String> relatedLinkList = new ArrayList<String>();
323 JSONArray relationships = null;
324 logger.info("Fetching relationships for resource type: " + catalog);
326 JSONObject relationshipLst = payload.getJSONObject("relationship-list");
327 if (relationshipLst != null) {
328 relationships = relationshipLst.getJSONArray("relationship");
331 } catch (Exception e) {
332 logger.error(e.getMessage());
333 throw new DiscoveryException(RELATIONSHIP_LINK_PARSE_ERROR, Status.INTERNAL_SERVER_ERROR, e.getMessage());
336 if (relationships != null && relationships.length() > 0) {
337 for (int i = 0; i < relationships.length(); i++) {
338 Object relatedToObj = null;
339 Object relatedLinkObj = null;
341 JSONObject obj = relationships.optJSONObject(i);
342 relatedToObj = obj.get(JSON_ATT_RELATED_TO);
344 if (relatedToObj.toString().equals(catalog)) {
345 relatedLinkObj = obj.get(JSON_ATT_RELATED_LINK);
346 if (relatedLinkObj != null) {
347 relatedLinkList.add(relatedLinkObj.toString());
353 if (relatedLinkList != null) {
355 "Number of relationships found for resource type: " + catalog + " are: " + relatedLinkList.size());
357 return relatedLinkList;
362 private static Map<String, List<String>> buildHeaders(String transactionId) {
363 MultivaluedMap<String, String> headers = new MultivaluedMapImpl();
364 headers.put(TRANSACTION_ID, Collections.singletonList(transactionId));
365 headers.put(FROM_APP_ID, Collections.singletonList(APP_NAME));