Update the dependencies to use project version
[aai/sparky-be.git] / src / main / java / org / onap / aai / sparky / search / VnfSearchService.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017 Amdocs
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *       http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  *
21  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22  */
23 package org.onap.aai.sparky.search;
24
25 import java.io.IOException;
26 import java.io.PrintWriter;
27 import java.util.ArrayList;
28 import java.util.Date;
29 import java.util.List;
30 import java.util.Map;
31
32 import javax.json.Json;
33 import javax.json.JsonObject;
34 import javax.json.JsonObjectBuilder;
35 import javax.servlet.http.HttpServletResponse;
36 import javax.ws.rs.core.MediaType;
37
38 import org.json.JSONArray;
39 import org.json.JSONObject;
40 import org.onap.aai.sparky.dal.elasticsearch.HashQueryResponse;
41 import org.onap.aai.sparky.dal.elasticsearch.SearchAdapter;
42 import org.onap.aai.sparky.dal.elasticsearch.config.ElasticSearchConfig;
43 import org.onap.aai.sparky.dal.rest.OperationResult;
44 import org.onap.aai.sparky.logging.AaiUiMsgs;
45 import org.onap.aai.sparky.suggestivesearch.SuggestionEntity;
46 import org.onap.aai.sparky.util.NodeUtils;
47 import org.onap.aai.sparky.viewandinspect.config.TierSupportUiConstants;
48 import org.onap.aai.sparky.viewandinspect.entity.QuerySearchEntity;
49 import org.onap.aai.cl.api.Logger;
50 import org.onap.aai.cl.eelf.LoggerFactory;
51
52
53 /**
54  * From the given HTTP request, create vnf-search query for document store, and process document
55  * store response.
56  */
57
58 public class VnfSearchService {
59
60   private static final String APP_JSON = MediaType.APPLICATION_JSON;
61
62   private static ElasticSearchConfig esConfig = null;
63
64   private static final Logger LOG = LoggerFactory.getInstance().getLogger(VnfSearchService.class);
65
66   private static SearchAdapter search = null;
67   private static final String ES_SUGGEST_API = TierSupportUiConstants.ES_SUGGEST_API;
68   private static final String ES_COUNT_API = TierSupportUiConstants.ES_COUNT_API;
69   private static final String ES_SEARCH_API = TierSupportUiConstants.ES_SEARCH_API;
70
71   private static final String ENTITY_TYPE = "generic-vnf";
72
73   /**
74    * Get Full URL for search using elastic search configuration.
75    *
76    * @param api the api
77    * @return the full url
78    */
79   private static String getFullUrl(String indexName, String api) {
80
81     final String host = esConfig.getIpAddress();
82     final String port = esConfig.getHttpPort();
83     return String.format("http://%s:%s/%s/%s", host, port, indexName, api);
84   }
85
86   /**
87    * Process operation result.
88    *
89    * @param api the api
90    * @param response the response
91    * @param opResult the op result
92    * @throws IOException Signals that an I/O exception has occurred.
93    */
94   private static void buildVnfQuerySearchResponse(String apiKey, HttpServletResponse response,
95       OperationResult opResult) throws IOException {
96     int resonseCode = opResult.getResultCode();
97     String result = opResult.getResult();
98
99     if (resonseCode > 300) {
100       setServletResponse(true, resonseCode, response, result);
101       return;
102     }
103
104     if (result != null) {
105       JSONObject finalOutputToFe = new JSONObject();
106       JSONObject responseJson = new JSONObject(result);
107
108       if (apiKey.equalsIgnoreCase(ES_SUGGEST_API)) { // process suggestion results
109         try {
110           String suggestionsKey = "vnfs";
111           int total = 0;
112           JSONArray suggestionsArray = new JSONArray();
113           JSONArray suggestions = responseJson.getJSONArray(suggestionsKey);
114           if (suggestions.length() > 0) {
115             suggestionsArray = suggestions.getJSONObject(0).getJSONArray("options");
116             for (int i = 0; i < suggestionsArray.length(); i++) {
117               suggestionsArray.getJSONObject(i).remove("score"); // FE doesn't like this noise:
118                                                                  // 'score'
119             }
120
121             total = suggestionsArray.length();
122           }
123           finalOutputToFe.put("totalFound", total);
124           finalOutputToFe.put("suggestions", suggestionsArray);
125         } catch (Exception e) {
126           LOG.error(AaiUiMsgs.ERROR_GENERIC,
127               "Error parsing response from suggestions index. Response: " + result);
128         }
129       } else if (apiKey.equalsIgnoreCase(ES_COUNT_API)) {
130         try {
131           String shardsKey = "_shards";
132           responseJson.remove(shardsKey);
133           finalOutputToFe = responseJson;
134         } catch (Exception e) {
135           LOG.error(AaiUiMsgs.ERROR_GENERIC,
136               "Error fetching total count response from aggregation index. Response: " + result);
137         }
138       } else if (apiKey.equalsIgnoreCase(ES_SEARCH_API)) {
139         try {
140           JSONArray bucketsArray = (responseJson.getJSONObject("aggregations")
141               .getJSONObject("default").getJSONArray("buckets"));
142           int count = 0;
143           for (int i = 0; i < bucketsArray.length(); i++) {
144             count += bucketsArray.getJSONObject(i).getInt("doc_count");
145           }
146           JSONObject content = new JSONObject();
147           content.put("totalChartHits", count);
148           content.put("buckets", bucketsArray);
149           finalOutputToFe.put("groupby_aggregation", content);
150         } catch (Exception e) {
151           LOG.error(AaiUiMsgs.ERROR_GENERIC,
152               "Error fetching group-by query response from aggregation index. Response: " + result);
153         }
154       }
155
156       setServletResponse(false, resonseCode, response, finalOutputToFe.toString());
157     }
158   }
159
160   /**
161    * Sets the servlet response.
162    *
163    * @param isError the is error
164    * @param responseCode the response code
165    * @param response the response
166    * @param postPayload the post payload
167    * @throws IOException Signals that an I/O exception has occurred.
168    */
169   public static void setServletResponse(boolean isError, int responseCode,
170       HttpServletResponse response, String postPayload) throws IOException {
171
172     if (isError) {
173       LOG.error(AaiUiMsgs.ERROR_PARSING_JSON_PAYLOAD_VERBOSE, postPayload);
174     }
175
176     response.setStatus(responseCode);
177
178     if (postPayload != null) {
179       response.setContentType(APP_JSON);
180       PrintWriter out = response.getWriter();
181       out.println(postPayload);
182       out.close();
183     }
184   }
185
186   /**
187    * Instantiates a new vnf search service.
188    */
189   public VnfSearchService() {
190     try {
191       if (esConfig == null) {
192         esConfig = ElasticSearchConfig.getConfig();
193       }
194
195       if (search == null) {
196         search = new SearchAdapter();
197       }
198     } catch (Exception exc) {
199       LOG.error(AaiUiMsgs.CONFIGURATION_ERROR, "Search");
200     }
201   }
202
203
204   /**
205    * Gets the suggestions results.
206    *
207    * @param response the response
208    * @param maxResults maximum number of suggestions
209    * @param queryStr query string
210    * @return the suggestions results
211    * @throws IOException Signals that an I/O exception has occurred.
212    */
213   public List<SuggestionEntity> getSuggestionsResults(QuerySearchEntity querySearchEntity,
214       int resultCountLimit) throws IOException {
215     List<SuggestionEntity> returnList = new ArrayList<SuggestionEntity>();
216
217     /* Create suggestions query */
218     JsonObject vnfSearch = VnfSearchQueryBuilder
219         .createSuggestionsQuery(String.valueOf(resultCountLimit), querySearchEntity.getQueryStr());
220
221     /* Parse suggestions response */
222     OperationResult opResult =
223         search.doPost(getFullUrl(esConfig.getAutosuggestIndexname(), ES_SUGGEST_API),
224             vnfSearch.toString(), APP_JSON);
225
226     String result = opResult.getResult();
227
228     if (!opResult.wasSuccessful()) {
229       LOG.error(AaiUiMsgs.ERROR_PARSING_JSON_PAYLOAD_VERBOSE, result);
230       return returnList;
231     }
232
233     JSONObject responseJson = new JSONObject(result);
234     String suggestionsKey = "vnfs";
235     JSONArray suggestionsArray = new JSONArray();
236     JSONArray suggestions = responseJson.getJSONArray(suggestionsKey);
237     if (suggestions.length() > 0) {
238       suggestionsArray = suggestions.getJSONObject(0).getJSONArray("options");
239       for (int i = 0; i < suggestionsArray.length(); i++) {
240         JSONObject querySuggestion = suggestionsArray.getJSONObject(i);
241         if (querySuggestion != null) {
242           SuggestionEntity responseSuggestion = new SuggestionEntity();
243           responseSuggestion.setText(querySuggestion.getString("text"));
244           responseSuggestion.setRoute("vnfSearch"); // TODO -> Read route from
245                                                     // suggestive-search.properties instead of hard
246                                                     // coding
247           responseSuggestion
248               .setHashId(NodeUtils.generateUniqueShaDigest(querySuggestion.getString("text")));
249           returnList.add(responseSuggestion);
250         }
251       }
252     }
253     return returnList;
254   }
255
256
257   /**
258    * This method sets server response if lookup in ES has 0 count TODO: Change the response code to
259    * appropriate when FE-BE contract is finalized
260    * 
261    * @param response
262    */
263   public void setZeroCountResponse(HttpServletResponse response) throws IOException {
264     JSONObject payload = new JSONObject();
265     payload.put("count", 0);
266     setServletResponse(false, 200, response, payload.toString());
267   }
268
269   /**
270    * This method sets server response if lookup in ES for an aggregation has 0 results TODO: Change
271    * the response code to appropriate when FE-BE contract is finalized
272    * 
273    * @param response
274    */
275   public void setEmptyAggResponse(HttpServletResponse response) throws IOException {
276     JSONObject aggPayload = new JSONObject();
277     aggPayload.put("totalChartHits", 0);
278     aggPayload.put("buckets", new JSONArray());
279     JSONObject payload = new JSONObject();
280     payload.append("groupby_aggregation", aggPayload);
281     setServletResponse(false, 200, response, payload.toString());
282   }
283
284   public HashQueryResponse getJSONPayloadFromHash(String hashId) {
285
286     HashQueryResponse hashQueryResponse = new HashQueryResponse();
287     JsonObjectBuilder hashSearch = Json.createObjectBuilder();
288     VnfSearchQueryBuilder.buildSingleTermCountQuery(hashSearch, "_id", hashId);
289     String hashSearchQuery = hashSearch.build().toString();
290     OperationResult opResult = search.doPost(
291         getFullUrl(esConfig.getAutosuggestIndexname(), ES_SEARCH_API), hashSearchQuery, APP_JSON);
292     hashQueryResponse.setOpResult(opResult);
293
294     if (opResult != null && opResult.wasSuccessful()) {
295       String result = opResult.getResult();
296       if (result != null) {
297         JSONObject responseJson = new JSONObject(result);
298         JSONArray hits = responseJson.getJSONObject("hits").getJSONArray("hits");
299         if (hits != null && hits.length() > 0) {
300           hashQueryResponse.setJsonPayload(hits.getJSONObject(0).getJSONObject("_source")
301               .getJSONObject("entity_suggest").toString());
302         }
303       }
304     }
305     return hashQueryResponse;
306   }
307
308   public void getEntityCountResults(HttpServletResponse response, Map<String, String> attributes)
309       throws IOException {
310     // Create entity counts query
311     JsonObject vnfSearch = VnfSearchQueryBuilder.createEntityCountsQuery(attributes);
312
313     // Parse response for entity counts query
314     OperationResult opResult = search.doPost(
315         getFullUrl(TierSupportUiConstants.getAggregationIndexName(ENTITY_TYPE), ES_COUNT_API),
316         vnfSearch.toString(), APP_JSON);
317     buildVnfQuerySearchResponse(ES_COUNT_API, response, opResult);
318   }
319
320   public void getSummaryByEntityType(HttpServletResponse response, Map<String, String> attributes,
321       String groupByKey) throws IOException {
322     // Create query for summary by entity type
323     JsonObject vnfSearch =
324         VnfSearchQueryBuilder.createSummaryByEntityTypeQuery(attributes, groupByKey);
325
326     // Parse response for summary by entity type query
327     OperationResult opResult = search.doPost(
328         getFullUrl(TierSupportUiConstants.getAggregationIndexName(ENTITY_TYPE), ES_SEARCH_API),
329         vnfSearch.toString(), APP_JSON);
330     buildVnfQuerySearchResponse(ES_SEARCH_API, response, opResult);
331   }
332
333   public SearchAdapter getSearch() {
334     return search;
335   }
336
337   public void setSearch(SearchAdapter search) {
338     VnfSearchService.search = search;
339   }
340
341   public static ElasticSearchConfig getEsConfig() {
342     return esConfig;
343   }
344
345   public static void setEsConfig(ElasticSearchConfig esConfig) {
346     VnfSearchService.esConfig = esConfig;
347   }
348 }