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;
28 import java.text.MessageFormat;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.List;
35 import javax.ws.rs.core.MediaType;
36 import javax.ws.rs.core.MultivaluedMap;
37 import javax.ws.rs.core.Response.Status;
39 import org.json.JSONArray;
40 import org.json.JSONObject;
41 import org.onap.aai.restclient.client.OperationResult;
42 import org.onap.aai.restclient.client.RestClient;
43 import org.onap.logging.ref.slf4j.ONAPLogAdapter;
44 import org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
51 public class RestUtil {
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";
61 VNF("generic-vnf"), VNFC("vnfc"), VSERVER("vserver"), L3NETWORK("l3-network");
63 private final String resourceName;
64 private final String collectionName;
66 private Catalog(String objName) {
67 this.resourceName = objName;
68 this.collectionName = objName + "s"; // make plural
71 public String objName() {
77 private static final String JSON_ATT_RELATED_TO = "related-to";
78 private static final String JSON_ATT_RELATED_LINK = "related-link";
80 private static final String EMPTY_JSON_STRING = "{}";
82 private static final String DEPTH = "?depth=2";
83 private static Logger logger = LoggerFactory.getLogger(RestUtil.class);
86 * Validates the URL parameter.
88 * @throws DiscoveryException if there is missing parameter
90 public static void validateURL(String serviceInstanceId) throws DiscoveryException {
92 if (serviceInstanceId == null || serviceInstanceId.isEmpty()) {
93 throw new DiscoveryException(INVALID_URL, Status.BAD_REQUEST);
97 private static String generateServiceInstanceURL(String siPath, String serviceInstanceId) {
98 return MessageFormat.format(siPath, serviceInstanceId);
103 * Trigger external API call to AAI to retrieve Service Instance data (i.e. genericVNF and VNFC)
109 * @param aaiServiceInstancePath
110 * @param transactionId
111 * @param serviceInstanceId
112 * @param modelVersionId
113 * @param modelInvariantId
115 * @throws DiscoveryException
117 public static JSONObject retrieveAAIModelData(RestClient aaiClient, String baseURL, String aaiServiceInstancePath,
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, 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, baseURL, transactionId, relationMap, serviceInstancePayload);
144 * @param transactionId
146 * @throws DiscoveryException
148 private static JSONObject processVNFRelationMap(RestClient aaiClient, String baseURL, 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;
155 if (relationMap.get(Catalog.VNF.resourceName) != null) {
156 List<JSONObject> vnfList = processResourceList(aaiClient, baseURL, transactionId, Catalog.VNF.resourceName,
157 relationMap.get(Catalog.VNF.resourceName));
158 // Logic to Create the Generic VNF JSON and extract further relationships
159 for (JSONObject vnfPayload : vnfList) {
160 List<String> vnfcLinkLst = extractRelatedLink(vnfPayload, Catalog.VNFC.resourceName);
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 Catalog.VNFC.resourceName, vnfcLinkLst);
165 if (vnfcList != null) {
166 vnfPayload.put(Catalog.VNFC.collectionName, vnfcList);
169 logger.info("No vnfc found for vnf-id:" + vnfPayload.getString("vnf-id"));
172 List<String> networkLinkLst = extractRelatedLink(vnfPayload, Catalog.L3NETWORK.resourceName);
173 if (networkLinkLst != null && !networkLinkLst.isEmpty()) {
174 logger.info("The number of the API call for l3-network is:" + networkLinkLst.size());
175 List<JSONObject> networkList = processResourceList(aaiClient, baseURL, transactionId,
176 Catalog.L3NETWORK.resourceName, networkLinkLst);
177 if (networkList != null) {
178 vnfPayload.put(Catalog.L3NETWORK.collectionName, networkList);
181 logger.info("No l3-network found for vnf-id:" + vnfPayload.getString("vnf-id"));
183 List<String> vserverLinkLst = extractRelatedLink(vnfPayload, Catalog.VSERVER.resourceName);
184 if (vserverLinkLst != null && !vserverLinkLst.isEmpty()) {
185 logger.info("The number of the API call for vserver is:" + vserverLinkLst.size());
186 List<JSONObject> vserverList = processResourceList(aaiClient, baseURL, transactionId,
187 Catalog.VSERVER.resourceName, vserverLinkLst);
188 if (vserverList != null) {
189 vnfPayload.put(Catalog.VSERVER.collectionName, vserverList);
192 logger.info("No vserver found for vnf-id:" + vnfPayload.getString("vnf-id"));
195 // Add final vnf payload to list
196 vnfLst.add(vnfPayload);
199 logger.info("No generic vnf found for :" + serviceInstancePayload.getString("service-instance-id"));
202 // Add generic vnf with related resource payload to response
203 if (vnfLst != null && !vnfLst.isEmpty()) {
204 response.put(Catalog.VNF.collectionName, vnfLst);
215 * @param transactionId
216 * @param resourceType
217 * @param resourceList
219 * @throws DiscoveryException
221 private static List<JSONObject> processResourceList(RestClient aaiClient, String aaiBaseURL, String transactionId,
222 String resourceType, List<String> resourceList) throws DiscoveryException {
223 List<JSONObject> resourcePayloadList = new ArrayList<JSONObject>();
224 for (String resourceLink : resourceList) {
225 String resourceURL = aaiBaseURL + resourceLink;
226 // With latest AAI development, in order to retrieve the both generic VNF + vf_module, we can use
227 // one API call but with depth=2
228 if (resourceType.equals(Catalog.VNF.resourceName)) {
229 resourceURL += DEPTH;
232 // Response from generic VNF API call
233 JSONObject resourcePayload = new JSONObject(
234 getResource(aaiClient, resourceURL, transactionId));
235 if (resourcePayload == null || resourcePayload.length() == 0) {
236 logger.info("Resource with url " + resourceLink + " is not found from AAI");
238 resourcePayloadList.add(resourcePayload);
241 return resourcePayloadList;
246 * @param serviceInstancePayload
249 * @throws DiscoveryException
251 private static HashMap<String, List<String>> extractServiceRelationShips(JSONObject payload)
252 throws DiscoveryException {
254 JSONArray relationships = null;
255 HashMap<String, List<String>> relationMap = new HashMap<String, List<String>>();
256 logger.info("Fetching Service Instance Relationships");
258 JSONObject relationshipList = payload.getJSONObject("relationship-list");
259 if (relationshipList != null) {
260 relationships = relationshipList.getJSONArray("relationship");
262 } catch (Exception e) {
263 logger.error(e.getMessage());
264 throw new DiscoveryException(SERVICE_RELATIONSHIP_PARSE_ERROR, Status.INTERNAL_SERVER_ERROR,
268 if (relationships != null && relationships.length() > 0) {
269 for (int i = 0; i < relationships.length(); i++) {
270 JSONObject obj = relationships.optJSONObject(i);
271 String relatedToObj = obj.getString(JSON_ATT_RELATED_TO);
272 String relatedLinkObj = obj.getString(JSON_ATT_RELATED_LINK);
274 if (relatedToObj == null) {
275 logger.info("Related-To Object found null");
278 List<String> relatedLinkList = relationMap.get(relatedToObj);
279 if (relatedLinkList == null) {
280 relatedLinkList = new ArrayList<>();
281 relationMap.put(relatedToObj, relatedLinkList);
283 relatedLinkList.add(relatedLinkObj);
295 * @throws DiscoveryException
297 private static String getResource(RestClient client, String url, String transId)
298 throws DiscoveryException {
299 OperationResult result = client.get(url, buildHeaders(transId), MediaType.valueOf(MediaType.APPLICATION_JSON));
301 if (result.getResultCode() == 200) {
302 String jsonString = result.getResult();
304 } else if (result.getResultCode() == 404) {
305 // Resource not found, generate empty JSON format
306 logger.info("Resource for " + url + " is not found " + "return empty Json format");
307 return EMPTY_JSON_STRING;
309 throw new DiscoveryException(FETCH_RESOURCE_FAILED, Status.INTERNAL_SERVER_ERROR, result.getFailureCause());
314 * Extract the related-Link from Json payload. For example
316 * "related-to": "vnfc",
317 * "related-link": "/aai/v11/network/vnfcs/vnfc/zrdm5aepdg01vmg003",
318 * "relationship-data": [
320 * "relationship-key": "vnfc.vnfc-name",
321 * "relationship-value": "zrdm5aepdg01vmg003"
326 private static List<String> extractRelatedLink(JSONObject payload, String catalog) throws DiscoveryException {
327 List<String> relatedLinkList = new ArrayList<String>();
328 JSONArray relationships = null;
329 logger.info("Fetching relationships for resource type: " + catalog);
331 JSONObject relationshipLst = payload.getJSONObject("relationship-list");
332 if (relationshipLst != null) {
333 relationships = relationshipLst.getJSONArray("relationship");
336 } catch (Exception e) {
337 logger.error(e.getMessage());
338 throw new DiscoveryException(RELATIONSHIP_LINK_PARSE_ERROR, Status.INTERNAL_SERVER_ERROR, e.getMessage());
341 if (relationships != null && relationships.length() > 0) {
342 for (int i = 0; i < relationships.length(); i++) {
343 Object relatedToObj = null;
344 Object relatedLinkObj = null;
346 JSONObject obj = relationships.optJSONObject(i);
347 relatedToObj = obj.get(JSON_ATT_RELATED_TO);
349 if (relatedToObj.toString().equals(catalog)) {
350 relatedLinkObj = obj.get(JSON_ATT_RELATED_LINK);
351 if (relatedLinkObj != null) {
352 relatedLinkList.add(relatedLinkObj.toString());
358 if (relatedLinkList != null) {
360 "Number of relationships found for resource type: " + catalog + " are: " + relatedLinkList.size());
362 return relatedLinkList;
367 private static Map<String, List<String>> buildHeaders(String transactionId) {
368 MultivaluedMap<String, String> headers = new MultivaluedMapImpl();
369 headers.put(TRANSACTION_ID, Collections.singletonList(transactionId));
370 headers.put(FROM_APP_ID, Collections.singletonList(APP_NAME));