d95068b2bc81392dd7a549c14db74701136f943d
[policy/models.git] / models-interactions / model-impl / aai / src / main / java / org / onap / policy / aai / AaiManager.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * aai
4  * ================================================================================
5  * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2019 Nordix Foundation.
7  * Modifications Copyright (C) 2019 Samsung Electronics Co., Ltd.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.aai;
24
25 import com.google.gson.JsonSyntaxException;
26 import java.io.UnsupportedEncodingException;
27 import java.net.URLEncoder;
28 import java.nio.charset.StandardCharsets;
29 import java.util.HashMap;
30 import java.util.Map;
31 import java.util.UUID;
32 import java.util.stream.Collectors;
33 import org.json.JSONArray;
34 import org.json.JSONObject;
35 import org.onap.policy.aai.util.Serialization;
36 import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
37 import org.onap.policy.common.endpoints.utils.NetLoggerUtil;
38 import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType;
39 import org.onap.policy.common.utils.coder.CoderException;
40 import org.onap.policy.common.utils.coder.StandardCoder;
41 import org.onap.policy.rest.RestManager;
42 import org.onap.policy.rest.RestManager.Pair;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 /**
47  * This class handles communication towards and responses from A&AI for this module.
48  */
49 public final class AaiManager {
50
51     /** The Constant logger. */
52     private static final Logger logger = LoggerFactory.getLogger(AaiManager.class);
53
54     private static final String APPLICATION_JSON = "application/json";
55
56     private static final StandardCoder CODER = new StandardCoder();
57
58     /** The rest manager. */
59     // The REST manager used for processing REST calls for this AAI manager
60     private final RestManager restManager;
61
62     /** custom query and other AAI resource URLs. */
63     private static final String CQ_URL = "/aai/v16/query?format=resource";
64     private static final String TENANT_URL =
65             "/aai/v16/search/nodes-query?search-node-type=vserver&filter=vserver-name:EQUALS:";
66     private static final String PREFIX = "/aai/v16";
67     private static final String PNF_URL = PREFIX + "/network/pnfs/pnf/";
68     private static final String AAI_DEPTH_SUFFIX = "?depth=0";
69
70     /**
71      * Constructor, create the AAI manager with the specified REST manager.
72      *
73      * @param restManager the rest manager to use for REST calls
74      */
75     public AaiManager(final RestManager restManager) {
76         this.restManager = restManager;
77     }
78
79     /**
80      * Creates the custom query payload from a tenant query response.
81      *
82      * @param getResponse response from the tenant query
83      * @return String Payload
84      */
85     private String createCustomQueryPayload(String getResponse) {
86
87         if (getResponse == null) {
88             return null;
89         } else {
90             JSONObject responseObj = new JSONObject(getResponse);
91             JSONArray resultsArray;
92             if (responseObj.has("result-data")) {
93                 resultsArray = (JSONArray) responseObj.get("result-data");
94             } else {
95                 return null;
96             }
97             String resourceLink = resultsArray.getJSONObject(0).getString("resource-link");
98             String start = resourceLink.replace(PREFIX, "");
99             String query = "query/closed-loop";
100             JSONObject payload = new JSONObject();
101             payload.put("start", start);
102             payload.put("query", query);
103             return payload.toString();
104
105         }
106     }
107
108     /**
109      * This method is used to get the information for custom query.
110      *
111      * @param url url of the get method
112      * @param username Aai username
113      * @param password Aai password
114      * @param requestId request ID
115      * @param vserver Id of the vserver
116      * @return String
117      */
118     private String getCustomQueryRequestPayload(String url, String username, String password, UUID requestId,
119             String vserver) {
120
121         String urlGet = url + TENANT_URL;
122
123         String getResponse = getStringQuery(urlGet, username, password, requestId, vserver);
124         return createCustomQueryPayload(getResponse);
125     }
126
127     /**
128      * Calls Aai and returns a custom query response for a vserver.
129      *
130      * @param url Aai url
131      * @param username Aai Username
132      * @param password Aai Password
133      * @param requestId request ID
134      * @param vserver Vserver
135      * @return AaiCqResponse response from Aai for custom query
136      */
137     public AaiCqResponse getCustomQueryResponse(String url, String username, String password, UUID requestId,
138             String vserver) {
139
140         final Map<String, String> headers = createHeaders(requestId);
141
142         logger.debug("RestManager.put before");
143         String requestJson = getCustomQueryRequestPayload(url, username, password, requestId, vserver);
144         NetLoggerUtil.log(EventType.OUT, CommInfrastructure.REST, url, requestJson);
145
146         url = url + CQ_URL;
147
148         Pair<Integer, String> httpDetails =
149                 this.restManager.put(url, username, password, headers, APPLICATION_JSON, requestJson);
150         logger.debug("RestManager.put after");
151
152         if (httpDetails == null) {
153             logger.info("AAI POST Null Response to {}", url);
154             return null;
155         }
156
157         int httpResponseCode = httpDetails.first;
158
159         logger.info(url);
160         logger.info("{}", httpResponseCode);
161         logger.info(httpDetails.second);
162
163         if (httpDetails.second != null) {
164             String resp = httpDetails.second;
165             return new AaiCqResponse(resp);
166         }
167         return null;
168     }
169
170     /**
171      * Returns the string response of a get query.
172      *
173      * @param url Aai URL
174      * @param username Aai Username
175      * @param password Aai Password
176      * @param requestId AaiRequestId
177      * @param key Aai Key
178      * @return String returns the string from the get query
179      */
180     private String getStringQuery(final String url, final String username, final String password, final UUID requestId,
181             final String key) {
182
183         Map<String, String> headers = createHeaders(requestId);
184
185         String urlGet = url + key;
186
187         int attemptsLeft = 3;
188
189         while (attemptsLeft-- > 0) {
190             NetLoggerUtil.getNetworkLogger().info("[OUT|{}|{}|]", CommInfrastructure.REST, urlGet);
191             Pair<Integer, String> httpDetailsGet = restManager.get(urlGet, username, password, headers);
192             if (httpDetailsGet == null) {
193                 logger.info("AAI GET Null Response to {}", urlGet);
194                 return null;
195             }
196
197             int httpResponseCode = httpDetailsGet.first;
198
199             logger.info(urlGet);
200             logger.info("{}", httpResponseCode);
201             logger.info(httpDetailsGet.second);
202
203             if (httpResponseCode == 200) {
204                 String responseGet = httpDetailsGet.second;
205                 if (responseGet != null) {
206                     return responseGet;
207                 }
208             }
209             try {
210                 Thread.sleep(1000);
211             } catch (InterruptedException e) {
212                 Thread.currentThread().interrupt();
213             }
214
215         }
216
217         return null;
218     }
219
220     /**
221      * Post a query to A&AI.
222      *
223      * @param url the A&AI URL
224      * @param username the user name for authentication
225      * @param password the password for authentication
226      * @param request the request to issue towards A&AI
227      * @param requestId the UUID of the request
228      * @return the response from A&AI
229      */
230     public AaiNqResponse postQuery(String url, String username, String password, AaiNqRequest request, UUID requestId) {
231
232         final Map<String, String> headers = createHeaders(requestId);
233
234         url = url + "/aai/search/named-query";
235
236         logger.debug("RestManager.post before");
237         String requestJson = Serialization.gsonPretty.toJson(request);
238         NetLoggerUtil.log(EventType.OUT, CommInfrastructure.REST, url, requestJson);
239         Pair<Integer, String> httpDetails =
240                 restManager.post(url, username, password, headers, APPLICATION_JSON, requestJson);
241         logger.debug("RestManager.post after");
242
243         if (httpDetails == null) {
244             logger.info("AAI POST Null Response to {}", url);
245             return null;
246         }
247
248         int httpResponseCode = httpDetails.first;
249
250         logger.info(url);
251         logger.info("{}", httpResponseCode);
252         logger.info(httpDetails.second);
253
254         if (httpDetails.second != null) {
255             return composeResponse(httpDetails, url, AaiNqResponse.class);
256         }
257         return null;
258     }
259
260     /**
261      * Perform a GET request for a particular virtual server towards A&AI.
262      *
263      * @param urlGet the A&AI URL
264      * @param username the user name for authentication
265      * @param password the password for authentication
266      * @param requestId the UUID of the request
267      * @param key the key of the virtual server
268      * @return the response for the virtual server from A&AI
269      */
270     public AaiGetVserverResponse getQueryByVserverName(String urlGet, String username, String password, UUID requestId,
271             String key) {
272         return getQuery(urlGet, username, password, requestId, key, AaiGetVserverResponse.class);
273     }
274
275     /**
276      * Perform a GET request for a particular VNF by VNF ID towards A&AI.
277      *
278      * @param urlGet the A&AI URL
279      * @param username the user name for authentication
280      * @param password the password for authentication
281      * @param requestId the UUID of the request
282      * @param key the ID of the VNF
283      * @return the response for the virtual server from A&AI
284      */
285     public AaiGetVnfResponse getQueryByVnfId(String urlGet, String username, String password, UUID requestId,
286             String key) {
287         return getQuery(urlGet, username, password, requestId, key, AaiGetVnfResponse.class);
288     }
289
290     /**
291      * Perform a GET request for a particular VNF by VNF name towards A&AI.
292      *
293      * @param urlGet the A&AI URL
294      * @param username the user name for authentication
295      * @param password the password for authentication
296      * @param requestId the UUID of the request
297      * @param key the name of the VNF
298      * @return the response for the virtual server from A&AI
299      */
300     public AaiGetVnfResponse getQueryByVnfName(String urlGet, String username, String password, UUID requestId,
301             String key) {
302         return getQuery(urlGet, username, password, requestId, key, AaiGetVnfResponse.class);
303     }
304
305     /**
306      * Perform a GET query for a particular entity towards A&AI.
307      *
308      * @param <T> the generic type for the response
309      * @param url the A&AI URL
310      * @param username the user name for authentication
311      * @param password the password for authentication
312      * @param requestId the UUID of the request
313      * @param key the name of the VNF
314      * @param classOfResponse the class of the response to return
315      * @return the response for the virtual server from A&AI
316      */
317     private <T> T getQuery(final String url, final String username, final String password, final UUID requestId,
318             final String key, final Class<T> classOfResponse) {
319
320         Map<String, String> headers = createHeaders(requestId);
321
322         String urlGet = url + key;
323
324         int attemptsLeft = 3;
325
326         while (attemptsLeft-- > 0) {
327             NetLoggerUtil.getNetworkLogger().info("[OUT|{}|{}|]", CommInfrastructure.REST, urlGet);
328             Pair<Integer, String> httpDetailsGet = restManager.get(urlGet, username, password, headers);
329             if (httpDetailsGet == null) {
330                 logger.info("AAI GET Null Response to {}", urlGet);
331                 return null;
332             }
333
334             int httpResponseCode = httpDetailsGet.first;
335
336             logger.info(urlGet);
337             logger.info("{}", httpResponseCode);
338             logger.info(httpDetailsGet.second);
339
340             if (httpResponseCode == 200) {
341                 T responseGet = composeResponse(httpDetailsGet, urlGet, classOfResponse);
342                 if (responseGet != null) {
343                     return responseGet;
344                 }
345             }
346             try {
347                 Thread.sleep(1000);
348             } catch (InterruptedException e) {
349                 Thread.currentThread().interrupt();
350             }
351
352         }
353
354         return null;
355     }
356
357     /**
358      * Create the headers for the HTTP request.
359      *
360      * @param requestId the request ID to insert in the headers
361      * @return the HTTP headers
362      */
363     private Map<String, String> createHeaders(final UUID requestId) {
364         Map<String, String> headers = new HashMap<>();
365
366         headers.put("X-FromAppId", "POLICY");
367         headers.put("X-TransactionId", requestId.toString());
368         headers.put("Accept", APPLICATION_JSON);
369
370         return headers;
371     }
372
373     /**
374      * This method uses Google's GSON to create a response object from a JSON string.
375      *
376      * @param <T> the generic type
377      * @param httpDetails the HTTP response
378      * @param url the URL from which the response came
379      * @param classOfResponse The response class
380      * @return an instance of the response class
381      * @throws JsonSyntaxException on GSON errors instantiating the response
382      */
383     private <T> T composeResponse(final Pair<Integer, String> httpDetails, final String url,
384             final Class<T> classOfResponse) {
385         try {
386             T response = Serialization.gsonPretty.fromJson(httpDetails.second, classOfResponse);
387             NetLoggerUtil.log(EventType.IN, CommInfrastructure.REST, url, httpDetails.second);
388             return response;
389         } catch (JsonSyntaxException e) {
390             logger.error("postQuery threw: ", e);
391             return null;
392         }
393     }
394
395     /**
396      * Perform a GET request for a particular PNF by PNF ID towards A&AI.
397      *
398      * @param url the A&AI URL
399      * @param username the user name for authentication
400      * @param password the password for authentication
401      * @param requestId the UUID of the request
402      * @param pnfName the AAI unique identifier for PNF object
403      * @return HashMap of PNF properties
404      */
405     public Map<String, String> getPnf(String url, String username, String password, UUID requestId, String pnfName) {
406         String urlGet;
407         try {
408             urlGet = url + PNF_URL;
409             pnfName = URLEncoder.encode(pnfName, StandardCharsets.UTF_8.toString()) + AAI_DEPTH_SUFFIX;
410         } catch (UnsupportedEncodingException e) {
411             logger.error("Failed to encode the pnfName: {} using UTF-8 encoding. {}", pnfName, e);
412             return null;
413         }
414         String responseGet = getStringQuery(urlGet, username, password, requestId, pnfName);
415         if (responseGet == null) {
416             logger.error("Null response from AAI for the url: {}.", urlGet);
417             return null;
418         }
419         try {
420             Map<String, String> pnfParams = CODER.decode(responseGet, HashMap.class);
421             // Map to AAI node.attribute notation
422             return pnfParams.entrySet().stream()
423                            .collect(Collectors.toMap(e -> "pnf." + e.getKey(), Map.Entry::getValue));
424         } catch (CoderException e) {
425             logger.error("Failed to fetch PNF from AAI");
426             return null;
427         }
428     }
429 }