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";
54 private static final String AUTHORIZATION = "Authorization";
56 private static final Resource GENERIC_VNF = new Resource("generic-vnf");
58 public static class Resource {
59 private String resourceName;
60 private String collectionName;
62 private Resource(String resource) {
63 this.resourceName = resource;
64 this.collectionName = resource + "s";
67 private String getResourceName() {
68 return this.resourceName;
71 private String getCollectionName() {
72 return this.collectionName;
76 private static final String JSON_ATT_RELATED_TO = "related-to";
77 private static final String JSON_ATT_RELATED_LINK = "related-link";
79 private static final String EMPTY_JSON_STRING = "{}";
81 private static final String DEPTH = "?depth=2";
82 private static Logger logger = LoggerFactory.getLogger(RestUtil.class);
85 * Validates the URL parameter.
87 * @throws DiscoveryException if there is missing parameter
89 public static void validateURL(String serviceInstanceId) throws DiscoveryException {
91 if (serviceInstanceId == null || serviceInstanceId.isEmpty()) {
92 throw new DiscoveryException(INVALID_URL, Status.BAD_REQUEST);
96 private static String generateServiceInstanceURL(String siPath, String serviceInstanceId) {
97 return MessageFormat.format(siPath, serviceInstanceId);
102 * Trigger external API call to AAI to retrieve Service Instance data (i.e. genericVNF and VNFC)
108 * @param aaiBasicAuthorization
109 * @param aaiServiceInstancePath
110 * @param aaiResourceList
111 * @param transactionId
112 * @param serviceInstanceId
115 * @throws DiscoveryException
117 public static JSONObject retrieveAAIModelData(RestClient aaiClient, String baseURL, String aaiBasicAuthorization, String aaiServiceInstancePath, String aaiResourceList,
118 String transactionId, String serviceInstanceId, ONAPLogAdapter adapter) throws DiscoveryException {
120 // Follow two variables for transform purpose
121 String url = baseURL + generateServiceInstanceURL(aaiServiceInstancePath, serviceInstanceId);
122 // Response from service instance API call
123 JSONObject serviceInstancePayload = new JSONObject(
124 getResource(aaiClient, url, aaiBasicAuthorization, transactionId));
125 // Handle the case if the service instance is not found in AAI
126 if (serviceInstancePayload == null || serviceInstancePayload.length() == 0) {
127 logger.info("Service Instance " + serviceInstanceId + " is not found from AAI");
128 // Only return the empty Json on the root level. i.e service instance
129 throw new DiscoveryException(SERVICE_INSTANCE_NOT_FOUND, Status.NOT_FOUND);
132 HashMap<String, List<String>> relationMap = extractServiceRelationShips(serviceInstancePayload);
133 logger.info("The number of the relationships for service instance id {} is: {}", serviceInstanceId,
136 JSONObject response = processVNFRelationMap(aaiClient, aaiResourceList, baseURL, aaiBasicAuthorization, transactionId, relationMap, serviceInstancePayload);
144 * @param transactionId
146 * @throws DiscoveryException
148 private static JSONObject processVNFRelationMap(RestClient aaiClient, String aaiResourceList, String baseURL, String aaiBasicAuthorization, String transactionId,
149 HashMap<String, List<String>> relationMap, JSONObject serviceInstancePayload) throws DiscoveryException {
150 List<JSONObject> vnfLst = new ArrayList<JSONObject>(); // List of the VNF JSON along with related resources
152 JSONObject response = serviceInstancePayload;
154 List<Resource> resourceTypes = getResourceTypes(aaiResourceList);
156 if (relationMap.get(GENERIC_VNF.getResourceName()) != null) {
157 List<JSONObject> vnfList = processResourceList(aaiClient, baseURL, aaiBasicAuthorization, transactionId, GENERIC_VNF.getResourceName(),
158 relationMap.get(GENERIC_VNF.getResourceName()));
159 // Logic to Create the Generic VNF JSON and extract further relationships
160 for (JSONObject vnfPayload : vnfList) {
161 for (Resource resourceType : resourceTypes) {
162 List<String> vnfcLinkLst = extractRelatedLink(vnfPayload, resourceType.getResourceName());
163 if (vnfcLinkLst != null && !vnfcLinkLst.isEmpty()) {
164 logger.info("The number of the API call for vnfc is:" + vnfcLinkLst.size());
165 List<JSONObject> vnfcList = processResourceList(aaiClient, baseURL, aaiBasicAuthorization, transactionId,
166 resourceType.getResourceName(), vnfcLinkLst);
167 if (vnfcList != null) {
168 vnfPayload.put(resourceType.getCollectionName(), vnfcList);
171 logger.info("No " + resourceType.getResourceName() + " found for vnf-id:" + vnfPayload.getString("vnf-id"));
174 // Add final vnf payload to list
175 vnfLst.add(vnfPayload);
178 logger.info("No " + GENERIC_VNF.getResourceName() + " found for :" + serviceInstancePayload.getString("service-instance-id"));
181 // Add generic vnf with related resource payload to response
182 if (vnfLst != null && !vnfLst.isEmpty()) {
183 response.put(GENERIC_VNF.getCollectionName(), vnfLst);
193 * @param transactionId
194 * @param resourceType
195 * @param resourceList
197 * @throws DiscoveryException
199 private static List<JSONObject> processResourceList(RestClient aaiClient, String aaiBaseURL, String aaiBasicAuthorization, String transactionId,
200 String resourceType, List<String> resourceList) throws DiscoveryException {
201 List<JSONObject> resourcePayloadList = new ArrayList<JSONObject>();
202 for (String resourceLink : resourceList) {
203 String resourceURL = aaiBaseURL + resourceLink;
204 // With latest AAI development, in order to retrieve the both generic VNF + vf_module, we can use
205 // one API call but with depth=2
206 if (resourceType.equals(GENERIC_VNF.getResourceName())) {
207 resourceURL += DEPTH;
210 // Response from generic VNF API call
211 JSONObject resourcePayload = new JSONObject(
212 getResource(aaiClient, resourceURL, aaiBasicAuthorization, transactionId));
213 if (resourcePayload == null || resourcePayload.length() == 0) {
214 logger.info("Resource with url " + resourceLink + " is not found from AAI");
216 resourcePayloadList.add(resourcePayload);
219 return resourcePayloadList;
224 * @param serviceInstancePayload
227 * @throws DiscoveryException
229 private static HashMap<String, List<String>> extractServiceRelationShips(JSONObject payload)
230 throws DiscoveryException {
232 JSONArray relationships = null;
233 HashMap<String, List<String>> relationMap = new HashMap<String, List<String>>();
234 logger.info("Fetching Service Instance Relationships");
236 JSONObject relationshipList = payload.getJSONObject("relationship-list");
237 if (relationshipList != null) {
238 relationships = relationshipList.getJSONArray("relationship");
240 } catch (Exception e) {
241 logger.error(e.getMessage());
242 throw new DiscoveryException(SERVICE_RELATIONSHIP_PARSE_ERROR, Status.INTERNAL_SERVER_ERROR,
246 if (relationships != null && relationships.length() > 0) {
247 for (int i = 0; i < relationships.length(); i++) {
248 JSONObject obj = relationships.optJSONObject(i);
249 String relatedToObj = obj.getString(JSON_ATT_RELATED_TO);
250 String relatedLinkObj = obj.getString(JSON_ATT_RELATED_LINK);
252 if (relatedToObj == null) {
253 logger.info("Related-To Object found null");
256 List<String> relatedLinkList = relationMap.get(relatedToObj);
257 if (relatedLinkList == null) {
258 relatedLinkList = new ArrayList<>();
259 relationMap.put(relatedToObj, relatedLinkList);
261 relatedLinkList.add(relatedLinkObj);
270 * @param aaiBasicAuthorization
273 * @throws DiscoveryException
275 private static String getResource(RestClient client, String url, String aaiBasicAuthorization, String transId)
276 throws DiscoveryException {
277 OperationResult result = client.get(url, buildHeaders(aaiBasicAuthorization, transId), MediaType.valueOf(MediaType.APPLICATION_JSON));
279 if (result.getResultCode() == 200) {
280 String jsonString = result.getResult();
282 } else if (result.getResultCode() == 404) {
283 // Resource not found, generate empty JSON format
284 logger.info("Resource for " + url + " is not found " + "return empty Json format");
285 return EMPTY_JSON_STRING;
287 throw new DiscoveryException(FETCH_RESOURCE_FAILED, Status.INTERNAL_SERVER_ERROR, result.getFailureCause());
292 * Extract the related-Link from Json payload. For example
294 * "related-to": "vnfc",
295 * "related-link": "/aai/v11/network/vnfcs/vnfc/zrdm5aepdg01vmg003",
296 * "relationship-data": [
298 * "relationship-key": "vnfc.vnfc-name",
299 * "relationship-value": "zrdm5aepdg01vmg003"
304 private static List<String> extractRelatedLink(JSONObject payload, String catalog) throws DiscoveryException {
305 List<String> relatedLinkList = new ArrayList<String>();
306 JSONArray relationships = null;
307 logger.info("Fetching relationships for resource type: " + catalog);
309 JSONObject relationshipLst = payload.getJSONObject("relationship-list");
310 if (relationshipLst != null) {
311 relationships = relationshipLst.getJSONArray("relationship");
314 } catch (Exception e) {
315 logger.error(e.getMessage());
316 throw new DiscoveryException(RELATIONSHIP_LINK_PARSE_ERROR, Status.INTERNAL_SERVER_ERROR, e.getMessage());
319 if (relationships != null && relationships.length() > 0) {
320 for (int i = 0; i < relationships.length(); i++) {
321 Object relatedToObj = null;
322 Object relatedLinkObj = null;
324 JSONObject obj = relationships.optJSONObject(i);
325 relatedToObj = obj.get(JSON_ATT_RELATED_TO);
327 if (relatedToObj.toString().equals(catalog)) {
328 relatedLinkObj = obj.get(JSON_ATT_RELATED_LINK);
329 if (relatedLinkObj != null) {
330 relatedLinkList.add(relatedLinkObj.toString());
336 if (relatedLinkList != null) {
338 "Number of relationships found for resource type: " + catalog + " are: " + relatedLinkList.size());
340 return relatedLinkList;
345 private static Map<String, List<String>> buildHeaders(String aaiBasicAuthorization, String transactionId) {
346 MultivaluedMap<String, String> headers = new MultivaluedMapImpl();
347 headers.put(TRANSACTION_ID, Collections.singletonList(transactionId));
348 headers.put(FROM_APP_ID, Collections.singletonList(APP_NAME));
349 headers.put(AUTHORIZATION, Collections.singletonList(aaiBasicAuthorization));
353 private static List<Resource> getResourceTypes(String aaiResourceList) {
354 List<Resource> resources = new ArrayList<Resource>();
355 String noSpaceAaiResourceList = aaiResourceList.replaceAll("\\s", "");
356 String[] resourceList = noSpaceAaiResourceList.split(",");
357 for (int i = 0; i < resourceList.length; i++) {
358 resources.add(new Resource(resourceList[i]));