Update the dependencies to use project version
[aai/sparky-be.git] / src / main / java / org / onap / aai / sparky / viewandinspect / services / SearchServiceWrapper.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.viewandinspect.services;
24
25 import java.io.BufferedReader;
26 import java.io.IOException;
27 import java.io.PrintWriter;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.HashMap;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Map;
35
36 import javax.servlet.ServletException;
37 import javax.servlet.http.HttpServletRequest;
38 import javax.servlet.http.HttpServletResponse;
39
40 import org.json.JSONException;
41 import org.json.JSONObject;
42 import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
43 import org.onap.aai.sparky.config.oxm.OxmModelLoader;
44 import org.onap.aai.sparky.dal.elasticsearch.HashQueryResponse;
45 import org.onap.aai.sparky.dal.elasticsearch.SearchAdapter;
46 import org.onap.aai.sparky.dal.rest.OperationResult;
47 import org.onap.aai.sparky.dal.sas.config.SearchServiceConfig;
48 import org.onap.aai.sparky.logging.AaiUiMsgs;
49 import org.onap.aai.sparky.search.VnfSearchService;
50 import org.onap.aai.sparky.search.config.SuggestionConfig;
51 import org.onap.aai.sparky.suggestivesearch.SuggestionEntity;
52 import org.onap.aai.sparky.util.NodeUtils;
53 import org.onap.aai.sparky.viewandinspect.entity.QuerySearchEntity;
54 import org.onap.aai.sparky.viewandinspect.entity.SearchResponse;
55 import org.onap.aai.cl.api.Logger;
56 import org.onap.aai.cl.eelf.LoggerFactory;
57
58 import com.fasterxml.jackson.databind.JsonNode;
59 import com.fasterxml.jackson.databind.ObjectMapper;
60 import com.fasterxml.jackson.databind.node.ArrayNode;
61
62 /**
63  * The Class SearchServlet.
64  */
65
66 public class SearchServiceWrapper {
67
68   private static final long serialVersionUID = 1L;
69
70   private static final Logger LOG =
71       LoggerFactory.getInstance().getLogger(SearchServiceWrapper.class);
72
73   private SearchServiceConfig sasConfig = null;
74   private SuggestionConfig suggestionConfig = null;
75   private SearchAdapter search = null;
76   private ObjectMapper mapper;
77   private OxmModelLoader oxmModelLoader;
78   private VnfSearchService vnfSearch = null;
79
80   private static final String SEARCH_STRING = "search";
81   private static final String COUNT_STRING = "count";
82   private static final String QUERY_SEARCH = SEARCH_STRING + "/querysearch";
83   private static final String SUMMARY_BY_ENTITY_TYPE_API = SEARCH_STRING + "/summarybyentitytype";
84   private static final String SUMMARY_BY_ENTITY_TYPE_COUNT_API =
85       SUMMARY_BY_ENTITY_TYPE_API + "/" + COUNT_STRING;
86
87   private static final String VALUE_ANYKEY = "anyKey";
88   private static final String VALUE_QUERY = "query";
89
90   private static final String KEY_HASH_ID = "hashId";
91   private static final String KEY_GROUP_BY = "groupby";
92   private static final String KEY_SEARCH_RESULT = "searchResult";
93   private static final String KEY_HITS = "hits";
94   private static final String KEY_PAYLOAD = "payload";
95   private static final String KEY_DOCUMENT = "document";
96   private static final String KEY_CONTENT = "content";
97   private static final String KEY_SEARCH_TAG_IDS = "searchTagIDs";
98   private static final String KEY_SEARCH_TAGS = "searchTags";
99   private static final String KEY_LINK = "link";
100   private static final String KEY_ENTITY_TYPE = "entityType";
101
102   private static final String VI_SUGGESTION_ROUTE = "viewInspect"; // TODO -> Read route from
103                                                                    // suggestive-search.properties
104                                                                    // instead of hard coding
105
106   private static final String VIUI_SEARCH_TEMPLATE =
107       "{ " + "\"results-start\": 0," + "\"results-size\": %d," + "\"queries\": [{" + "\"must\": {"
108           + "\"match\": {" + "\"field\": \"entityType searchTags crossEntityReferenceValues\","
109           + "\"value\": \"%s\"," + "\"operator\": \"and\", "
110           + "\"analyzer\": \"whitespace_analyzer\"" + "}" + "}" + "}]" + "}";
111
112   /**
113    * Instantiates a new search service wrapper
114    */
115   public SearchServiceWrapper() {
116     this.mapper = new ObjectMapper();
117     vnfSearch = new VnfSearchService();
118
119     try {
120       if (sasConfig == null) {
121         sasConfig = SearchServiceConfig.getConfig();
122       }
123
124       if (suggestionConfig == null) {
125         suggestionConfig = SuggestionConfig.getConfig();
126       }
127
128       if (search == null) {
129         search = new SearchAdapter();
130       }
131
132       if (oxmModelLoader == null) {
133         oxmModelLoader = OxmModelLoader.getInstance();
134
135         if (OxmModelLoader.getInstance().getSearchableEntityDescriptors().isEmpty()) {
136           LOG.error(AaiUiMsgs.ENTITY_NOT_FOUND_IN_OXM, "searchable entity");
137         }
138       }
139     } catch (Exception exc) {
140       new ServletException(
141           "Caught an exception while getting an instance of servlet configuration from SearchServlet.",
142           exc);
143     }
144   }
145
146   public void doGet(HttpServletRequest request, HttpServletResponse response)
147       throws ServletException, IOException {
148     doPost(request, response);
149   }
150
151   public void setSasConfig(SearchServiceConfig sasConfig) {
152     this.sasConfig = sasConfig;
153   }
154
155   public SearchServiceConfig getSasConfig() {
156     return sasConfig;
157   }
158
159   public void setSuggestionConfig(SuggestionConfig suggestionConfig) {
160     this.suggestionConfig = suggestionConfig;
161   }
162
163   public void setSearch(SearchAdapter search) {
164     this.search = search;
165   }
166
167   public SuggestionConfig getSuggestionConfig() {
168     return suggestionConfig;
169   }
170
171   public SearchAdapter getSearch() {
172     return search;
173   }
174
175   public void setOxmModelLoader(OxmModelLoader oxmModelLoader) {
176     this.oxmModelLoader = oxmModelLoader;
177   }
178
179   public OxmModelLoader getOxmModelLoader() {
180     return oxmModelLoader;
181   }
182
183   public VnfSearchService getVnfSearch() {
184     return vnfSearch;
185   }
186
187   public void setVnfSearch(VnfSearchService vnfSearch) {
188     this.vnfSearch = vnfSearch;
189   }
190
191   /**
192    * Get Full URL for search
193    *
194    * @param api the api
195    * @param indexName
196    * @return the full url
197    */
198   private String getSasFullUrl(String indexName, String type, String ipAddress, String port,
199       String version) {
200
201     return String.format("https://%s:%s/services/search-data-service/%s/search/indexes/%s/%s",
202         ipAddress, port, version, indexName, type);
203   }
204
205   /**
206    * Handle search service do query.
207    *
208    * @param app the app
209    * @param request the request
210    * @param response the response
211    * @throws Exception the exception
212    */
213
214   protected JSONObject getRequestParamsFromHeader(HttpServletRequest request) {
215     StringBuffer br = new StringBuffer();
216     String line = null;
217     try {
218       BufferedReader reader = request.getReader();
219       while ((line = reader.readLine()) != null) {
220         br.append(line);
221       }
222     } catch (Exception exc) {
223       LOG.error(AaiUiMsgs.ERROR_READING_HTTP_REQ_PARAMS);
224     }
225
226     String output = br.toString();
227
228     return new JSONObject(output);
229   }
230
231   protected void handleSummaryByEntityTypeCount(HttpServletRequest request,
232       HttpServletResponse response) throws Exception {
233     JSONObject parameters = getRequestParamsFromHeader(request);
234     String hashId = null;
235     if (parameters.has(KEY_HASH_ID)) {
236       hashId = parameters.get(KEY_HASH_ID).toString();
237     } else {
238       vnfSearch.setZeroCountResponse(response);
239       LOG.error(AaiUiMsgs.ERROR_HASH_NOT_FOUND);
240       return;
241     }
242     HashQueryResponse hashQueryResponse = getResponseForQueryByHash(hashId, response);
243     Map<String, String> hashQueryResponsePayloadParams = new HashMap<String, String>();
244     if (hashQueryResponse.getJsonPayload() != null) {
245       hashQueryResponsePayloadParams = getPayloadParams(hashQueryResponse.getJsonPayload());
246       vnfSearch.getEntityCountResults(response, hashQueryResponsePayloadParams);
247     } else {
248       vnfSearch.setZeroCountResponse(response);
249       LOG.error(AaiUiMsgs.ERROR_INVALID_HASH, hashId);
250     }
251   }
252
253   protected Map<String, String> getPayloadParams(String parameters) {
254     Map<String, String> payloadParams = new HashMap<String, String>();
255     try {
256       JSONObject json = new JSONObject(parameters);
257       JSONObject payload = json.getJSONObject(KEY_PAYLOAD);
258       if (payload.length() > 0) {
259         for (String key : JSONObject.getNames(payload)) {
260           payloadParams.put(key, payload.getString(key));
261         }
262       }
263     } catch (JSONException exc) {
264       LOG.error(AaiUiMsgs.ERROR_PARSING_PARAMS, exc);
265     }
266     return payloadParams;
267   }
268
269   protected HashQueryResponse getResponseForQueryByHash(String hashId,
270       HttpServletResponse response) {
271     return vnfSearch.getJSONPayloadFromHash(hashId);
272   }
273
274   protected void handleSummaryByEntityType(HttpServletRequest request, HttpServletResponse response)
275       throws Exception {
276     JSONObject parameters = getRequestParamsFromHeader(request);
277     String hashId = null;
278     if (parameters.has(KEY_HASH_ID)) {
279       hashId = parameters.get(KEY_HASH_ID).toString();
280     } else {
281       vnfSearch.setZeroCountResponse(response);
282       LOG.error(AaiUiMsgs.ERROR_HASH_NOT_FOUND);
283       return;
284     }
285     HashQueryResponse hashQueryResponse = getResponseForQueryByHash(hashId, response);
286     Map<String, String> hashQueryResponsePayloadParams = new HashMap<String, String>();
287     if (hashQueryResponse.getJsonPayload() != null) {
288       hashQueryResponsePayloadParams = getPayloadParams(hashQueryResponse.getJsonPayload());
289       if (parameters.has(KEY_GROUP_BY)) {
290         String groupByKey = parameters.getString(KEY_GROUP_BY);
291         vnfSearch.getSummaryByEntityType(response, hashQueryResponsePayloadParams, groupByKey);
292       }
293     } else {
294       LOG.error(AaiUiMsgs.ERROR_INVALID_HASH, hashId);
295       vnfSearch.setEmptyAggResponse(response);
296     }
297   }
298
299   /**
300    * Gets the value from node.
301    *
302    * @param node the node
303    * @param fieldName the field name
304    * @return the value from node
305    */
306   private String getValueFromNode(JsonNode node, String fieldName) {
307
308     if (node == null || fieldName == null) {
309       return null;
310     }
311
312     JsonNode valueNode = node.get(fieldName);
313
314     if (valueNode != null) {
315       return valueNode.asText();
316     }
317
318     return null;
319
320   }
321
322   /**
323    * Builds the search response.
324    *
325    * @param operationResult the operation result
326    * @param queryStr the query str
327    * @return TODO
328    * @return the search response
329    */
330   private List<SuggestionEntity> generateSuggestionsForSearchResponse(String operationResult,
331       String queryStr) {
332
333
334     if (operationResult == null || operationResult.length() == 0) {
335       return null;
336     }
337
338     ObjectMapper mapper = new ObjectMapper();
339     JsonNode rootNode = null;
340     List<SuggestionEntity> suggestionEntityList = new ArrayList<SuggestionEntity>();
341     try {
342       rootNode = mapper.readTree(operationResult);
343
344       JsonNode hitsNode = rootNode.get(KEY_SEARCH_RESULT);
345
346
347       // Check if there are hits that are coming back
348       if (hitsNode.has(KEY_HITS)) {
349         ArrayNode hitsArray = (ArrayNode) hitsNode.get(KEY_HITS);
350
351         /*
352          * next we iterate over the values in the hit array elements
353          */
354
355         Iterator<JsonNode> nodeIterator = hitsArray.elements();
356         JsonNode entityNode = null;
357         SuggestionEntity suggestionEntity = null;
358         JsonNode sourceNode = null;
359         while (nodeIterator.hasNext()) {
360           entityNode = nodeIterator.next();
361           sourceNode = entityNode.get(KEY_DOCUMENT).get(KEY_CONTENT);
362
363           // do the point transformation as we build the response?
364           suggestionEntity = new SuggestionEntity();
365           suggestionEntity.setRoute(VI_SUGGESTION_ROUTE);
366
367           /*
368            * This is where we probably want to annotate the search tags because we also have access
369            * to the seachTagIds
370            */
371
372           String searchTagIds = getValueFromNode(sourceNode, KEY_SEARCH_TAG_IDS);
373           String searchTags = getValueFromNode(sourceNode, KEY_SEARCH_TAGS);
374           String link = getValueFromNode(sourceNode, KEY_LINK);
375           String entityType = getValueFromNode(sourceNode, KEY_ENTITY_TYPE);
376           if (link != null) {
377             suggestionEntity.setHashId(NodeUtils.generateUniqueShaDigest(link));
378           }
379
380           try {
381             suggestionEntity
382                 .setText(annotateSearchTags(searchTags, searchTagIds, entityType, queryStr));
383           } catch (Exception exc) {
384             LOG.error(AaiUiMsgs.SEARCH_TAG_ANNOTATION_ERROR, searchTags.toString(),
385                 exc.getLocalizedMessage());
386             // at least send back the un-annotated search tags
387             suggestionEntity.setText(searchTags);
388           }
389
390           if (searchTags != null) {
391             suggestionEntityList.add(suggestionEntity);
392           }
393
394         }
395       }
396     } catch (IOException exc) {
397       LOG.warn(AaiUiMsgs.SEARCH_RESPONSE_BUILDING_EXCEPTION, exc.getLocalizedMessage());
398     }
399     return suggestionEntityList;
400   }
401
402   /*
403    */
404
405   /**
406    * Query terms match search tag.
407    *
408    * @param queryTerms the query terms
409    * @param searchTag the search tag
410    * @return true, if successful @return.
411    */
412   private boolean queryTermsMatchSearchTag(String[] queryTerms, String searchTag) {
413
414     if (queryTerms == null || queryTerms.length == 0 || searchTag == null) {
415       return false;
416     }
417
418     for (String queryTerm : queryTerms) {
419       if (searchTag.toLowerCase().contains(queryTerm.toLowerCase())) {
420         return true;
421       }
422     }
423
424     return false;
425
426   }
427
428   /**
429    * The current format of an UI-dropdown-item is like: "search-terms  entityType  att1=attr1_val".
430    * Example, for pserver: search-terms pserver hostname=djmAG-72060,
431    * pserver-name2=example-pserver-name2-val-17254, pserver-id=example-pserver-id-val-17254,
432    * ipv4-oam-address=example-ipv4-oam-address-val-17254 SearchController.js parses the above
433    * format. So if you are modifying the parsing below, please update SearchController.js as well.
434    *
435    * @param searchTags the search tags
436    * @param searchTagIds the search tag ids
437    * @param entityType the entity type
438    * @param queryStr the query str
439    * @return the string
440    */
441
442   private String annotateSearchTags(String searchTags, String searchTagIds, String entityType,
443       String queryStr) {
444
445     if (searchTags == null || searchTagIds == null) {
446       String valueOfSearchTags = String.valueOf(searchTags);
447       String valueOfSearchTagIds = String.valueOf(searchTagIds);
448
449       LOG.error(AaiUiMsgs.SEARCH_TAG_ANNOTATION_ERROR, "See error",
450           "Search tags = " + valueOfSearchTags + " and Seach tag IDs = " + valueOfSearchTagIds);
451       return searchTags;
452     }
453
454     if (entityType == null) {
455       LOG.error(AaiUiMsgs.SEARCH_TAG_ANNOTATION_ERROR, searchTags.toString(), "EntityType is null");
456       return searchTags;
457     }
458
459     if (queryStr == null) {
460       LOG.error(AaiUiMsgs.SEARCH_TAG_ANNOTATION_ERROR, searchTags.toString(),
461           "Query string is null");
462       return searchTags;
463     }
464
465     /*
466      * The ElasticSearch analyzer has already applied the lowercase filter, so we don't have to
467      * covert them again
468      */
469     String[] searchTagsArray = searchTags.split(";");
470     String[] searchTagIdsArray = searchTagIds.split(";");
471
472     // specifically apply lower case to the the query terms to make matching
473     // simpler
474     String[] queryTerms = queryStr.toLowerCase().split(" ");
475
476     OxmEntityDescriptor desc = oxmModelLoader.getSearchableEntityDescriptors().get(entityType);
477
478     if (desc == null) {
479       LOG.error(AaiUiMsgs.ENTITY_NOT_FOUND_IN_OXM, entityType.toString());
480       return searchTags;
481     }
482
483     String primaryKeyName = NodeUtils.concatArray(desc.getPrimaryKeyAttributeName(), "/");
484     String primaryKeyValue = null;
485
486     /*
487      * For each used attribute, get the fieldName for the attribute index and transform the search
488      * tag into t1,t2,t3 => h1=t1, h2=t2, h3=t3;
489      */
490     StringBuilder searchTagsBuilder = new StringBuilder(128);
491     searchTagsBuilder.append(entityType);
492
493     String primaryKeyConjunctionValue = null;
494     boolean queryTermsMatchedSearchTags = false;
495
496     if (searchTagsArray.length == searchTagIdsArray.length) {
497       for (int i = 0; i < searchTagsArray.length; i++) {
498         String searchTagAttributeId = searchTagIdsArray[i];
499         String searchTagAttributeValue = searchTagsArray[i];
500
501         // Find the concat conjunction
502         Map<String, String> pairConjunctionList = suggestionConfig.getPairingList();
503
504         String suggConjunction = null;
505         if (pairConjunctionList.get(searchTagAttributeId) != null) {
506           suggConjunction = pairConjunctionList.get(searchTagAttributeId);
507         } else {
508           suggConjunction = suggestionConfig.getDefaultPairingValue();
509         }
510
511         if (primaryKeyName.equals(searchTagAttributeId)) {
512           primaryKeyValue = searchTagAttributeValue;
513           primaryKeyConjunctionValue = suggConjunction;
514         }
515
516         if (queryTermsMatchSearchTag(queryTerms, searchTagAttributeValue)) {
517           searchTagsBuilder.append(" " + suggConjunction + " " + searchTagAttributeValue);
518           queryTermsMatchedSearchTags = true;
519         }
520       }
521     } else {
522       String errorMessage =
523           "Search tags length did not match search tag ID length for entity type " + entityType;
524       LOG.error(AaiUiMsgs.ENTITY_SYNC_SEARCH_TAG_ANNOTATION_FAILED, errorMessage);
525     }
526
527     /*
528      * if none of the user query terms matched the index entity search tags then we should still tag
529      * the matched entity with a conjunction set to at least it's entity primary key value to
530      * discriminate between the entities of the same type in the search results displayed in the UI
531      * search bar results
532      */
533
534     if (!queryTermsMatchedSearchTags) {
535
536       if (primaryKeyValue != null && primaryKeyConjunctionValue != null) {
537         searchTagsBuilder.append(" " + primaryKeyConjunctionValue + " " + primaryKeyValue);
538       } else {
539         LOG.error(AaiUiMsgs.SEARCH_TAG_ANNOTATION_ERROR, "See error",
540             "Could not annotate user query terms " + queryStr
541                 + " from available entity search tags = " + searchTags);
542         return searchTags;
543       }
544
545     }
546
547     return searchTagsBuilder.toString();
548
549   }
550
551
552   /**
553    * @param queryStr - space separate query search terms
554    * @return - query string with stop-words removed
555    */
556   private String stripStopWordsFromQuery(String queryStr) {
557
558     if (queryStr == null) {
559       return queryStr;
560     }
561
562     Collection<String> stopWords = suggestionConfig.getStopWords();
563     ArrayList<String> queryTerms =
564         new ArrayList<String>(Arrays.asList(queryStr.toLowerCase().split(" ")));
565
566     queryTerms.removeAll(stopWords);
567
568     return String.join(" ", queryTerms);
569   }
570
571   /*
572    * Expected query:
573    * 
574    * POST /search/viuiSearch/
575    * 
576    * { "maxResults" : "10", "searchStr" : "<search bar text>" }
577    */
578
579   /**
580    * Handle view and inspect search.
581    *
582    * @param request the request
583    * @param maxResults Max number of results to return
584    * @param response the response
585    * @return
586    * @throws IOException Signals that an I/O exception has occurred.
587    */
588   protected List<SuggestionEntity> performViewAndInspectQuerySearch(
589       QuerySearchEntity querySearchEntity, int maxResults) throws IOException {
590     List<SuggestionEntity> suggestionEntityList = new ArrayList<SuggestionEntity>();
591
592     /*
593      * Based on the configured stop words, we need to strip any matched stop-words ( case
594      * insensitively ) from the query string, before hitting elastic to prevent the words from being
595      * used against the elastic view-and-inspect index. Another alternative to this approach would
596      * be to define stop words on the elastic search index configuration for the
597      * entity-search-index, but but that may be more complicated / more risky than just a simple bug
598      * fix, but it's something we should think about for the future.
599      */
600
601     try {
602       final String queryStringWithoutStopWords =
603           stripStopWordsFromQuery(querySearchEntity.getQueryStr());
604
605       final String fullUrlStr = getSasFullUrl(sasConfig.getIndexName(), VALUE_QUERY,
606           sasConfig.getIpAddress(), sasConfig.getHttpPort(), sasConfig.getVersion());
607
608       String postBody =
609           String.format(VIUI_SEARCH_TEMPLATE, maxResults, queryStringWithoutStopWords);
610
611       OperationResult opResult = search.doPost(fullUrlStr, postBody, "application/json");
612       if (opResult.getResultCode() == 200) {
613         suggestionEntityList = generateSuggestionsForSearchResponse(opResult.getResult(),
614             querySearchEntity.getQueryStr());
615       }
616     } catch (Exception exc) {
617       LOG.error(AaiUiMsgs.SEARCH_SERVLET_ERROR,
618           "View and inspect query failed with error = " + exc.getMessage());
619     }
620     return suggestionEntityList;
621   }
622
623   protected List<SuggestionEntity> performVnfQuerySearch(QuerySearchEntity querySearchEntity,
624       int resultCountLimit) throws Exception {
625     return vnfSearch.getSuggestionsResults(querySearchEntity, resultCountLimit);
626   }
627
628   protected void handleQuerySearch(HttpServletRequest request, HttpServletResponse response)
629       throws IOException {
630     String payload = NodeUtils.getBody(request);
631     if (payload == null || payload.isEmpty()) {
632       handleSearchServletErrors("Unable to parse payload", null, response);
633     } else {
634       QuerySearchEntity querySearchEntity = mapper.readValue(payload, QuerySearchEntity.class);
635       int maxResultsPerSearch = Integer.valueOf(querySearchEntity.getMaxResults());
636       try {
637         SearchResponse searchResponse = new SearchResponse();
638         List<SuggestionEntity> viewAndInspectsuggestionEntityList =
639             new ArrayList<SuggestionEntity>();
640         List<SuggestionEntity> vnfSuggestionEntityList = new ArrayList<SuggestionEntity>();
641         long processTime = System.currentTimeMillis();
642         for (String searchService : suggestionConfig.getSearchIndexToSearchService().values()) {
643           if (searchService.equals(SearchServiceWrapper.class.getSimpleName())) {
644             viewAndInspectsuggestionEntityList =
645                 performViewAndInspectQuerySearch(querySearchEntity, maxResultsPerSearch);
646           } else if (searchService.equals(VnfSearchService.class.getSimpleName())) {
647             vnfSuggestionEntityList = performVnfQuerySearch(querySearchEntity, maxResultsPerSearch);
648           }
649         }
650
651         int totalAdded = 0;
652         for (int i = 0; i < maxResultsPerSearch; i++) {
653           if (i < viewAndInspectsuggestionEntityList.size() && totalAdded < maxResultsPerSearch) {
654             searchResponse.addSuggestion(viewAndInspectsuggestionEntityList.get(i));
655             totalAdded++;
656           }
657           if (i < vnfSuggestionEntityList.size() && totalAdded < maxResultsPerSearch) {
658             searchResponse.addSuggestion(vnfSuggestionEntityList.get(i));
659             totalAdded++;
660           }
661           if (totalAdded >= maxResultsPerSearch) {
662             break;
663           }
664         }
665         searchResponse.addToTotalFound(totalAdded);
666         String searchResponseJson = NodeUtils.convertObjectToJson(searchResponse, true);
667
668         processTime = System.currentTimeMillis() - processTime;
669         searchResponse.setProcessingTimeInMs(processTime);
670         setServletResponse(response, searchResponseJson);
671       } catch (Exception exc) {
672         LOG.error(AaiUiMsgs.SEARCH_SERVLET_ERROR,
673             "Query search failed with error = " + exc.getMessage());
674       }
675     }
676   }
677
678   public void doPost(HttpServletRequest request, HttpServletResponse response)
679       throws ServletException, IOException {
680
681     String api = null;
682     try {
683
684       // set default response
685       response.setStatus(200);
686
687       if (request.getRequestURI().contains(QUERY_SEARCH)) {
688         api = QUERY_SEARCH;
689         handleQuerySearch(request, response);
690         return;
691       } else if (request.getRequestURI().contains(SUMMARY_BY_ENTITY_TYPE_COUNT_API)) {
692         api = SUMMARY_BY_ENTITY_TYPE_COUNT_API;
693         handleSummaryByEntityTypeCount(request, response);
694         return;
695       } else if (request.getRequestURI().contains(SUMMARY_BY_ENTITY_TYPE_API)) {
696         api = SUMMARY_BY_ENTITY_TYPE_API;
697         handleSummaryByEntityType(request, response);
698         return;
699       } else {
700
701         final String errorMessage = "Ignored request-uri = " + request.getRequestURI();
702         LOG.error(AaiUiMsgs.SEARCH_SERVLET_ERROR, errorMessage);
703         response.setStatus(404);
704         response.setContentType("application/json");
705         PrintWriter out = response.getWriter();
706         out.println(generateJsonErrorResponse(errorMessage));
707         out.close();
708
709
710       }
711     } catch (JSONException je) {
712       handleSearchServletErrors("Caught an exception while parsing json in processing for " + api,
713           je, response);
714     } catch (Exception e1) {
715       handleSearchServletErrors("Caught an exception while communicating with elasticsearch", e1,
716           response);
717     }
718   }
719
720   /**
721    * Generate json error response.
722    *
723    * @param message the message
724    * @return the string
725    */
726   /*
727    * This is the manual approach, however we could also create an object container for the error
728    * then use the Jackson ObjectWrite to dump the object to json instead. If it gets any more
729    * complicated we could do that approach so we don't have to manually trip over the JSON
730    * formatting.
731    */
732   protected String generateJsonErrorResponse(String message) {
733     return String.format("{ \"errorMessage\" : %s }", message);
734   }
735
736   /**
737    * Handle search servlet errors.
738    *
739    * @param errorMsg the error msg
740    * @param exc the exc
741    * @param response the response
742    * @throws IOException Signals that an I/O exception has occurred.
743    */
744   public void handleSearchServletErrors(String errorMsg, Exception exc,
745       HttpServletResponse response) throws IOException {
746
747     String errorLogMsg =
748         (exc == null ? errorMsg : errorMsg + ". Error:" + exc.getLocalizedMessage());
749
750     LOG.error(AaiUiMsgs.SEARCH_SERVLET_ERROR, errorLogMsg);
751
752     response.setContentType("application/json");
753     PrintWriter out = response.getWriter();
754     out.println(generateJsonErrorResponse(errorMsg));
755     out.close();
756   }
757
758
759   /**
760    * Execute query.
761    *
762    * @param response the response
763    * @param requestUrl the request url
764    * @param requestJsonPayload the request json payload
765    * @throws Exception the exception
766    */
767   public void executeQuery(HttpServletResponse response, String requestUrl,
768       String requestJsonPayload) throws Exception {
769
770     OperationResult opResult = search.doPost(requestUrl, requestJsonPayload, "application/json");
771
772     if (opResult != null) {
773
774       response.setStatus(opResult.getResultCode());
775       String finalOutput = opResult.getResult();
776
777       // example: failed to populate drop-down items from formatOutputJson()
778       if (finalOutput != null) {
779         response.setContentType("application/json");
780         PrintWriter out = response.getWriter();
781         out.println(finalOutput);
782         out.close();
783       }
784
785     } else {
786       response.setStatus(500);
787     }
788
789   }
790
791   /**
792    * Sets the servlet response.
793    * 
794    * @param response the response
795    * @param postPayload the post payload
796    *
797    * @throws IOException Signals that an I/O exception has occurred.
798    */
799   private void setServletResponse(HttpServletResponse response, String postPayload)
800       throws IOException {
801
802     if (postPayload != null) {
803       response.setContentType("application/json");
804       PrintWriter out = response.getWriter();
805       out.println(postPayload);
806       out.close();
807     }
808   }
809
810   /**
811    * @return the mapper
812    */
813   public ObjectMapper getMapper() {
814     return mapper;
815   }
816
817   /**
818    * @param mapper the mapper to set
819    */
820   public void setMapper(ObjectMapper mapper) {
821     this.mapper = mapper;
822   }
823
824   /**
825    * @return the serialversionuid
826    */
827   public static long getSerialversionuid() {
828     return serialVersionUID;
829   }
830
831   /**
832    * @return the log
833    */
834   public static Logger getLog() {
835     return LOG;
836   }
837
838   /**
839    * @return the searchString
840    */
841   public static String getSearchString() {
842     return SEARCH_STRING;
843   }
844
845   /**
846    * @return the countString
847    */
848   public static String getCountString() {
849     return COUNT_STRING;
850   }
851
852   /**
853    * @return the querySearch
854    */
855   public static String getQuerySearch() {
856     return QUERY_SEARCH;
857   }
858
859   /**
860    * @return the summaryByEntityTypeApi
861    */
862   public static String getSummaryByEntityTypeApi() {
863     return SUMMARY_BY_ENTITY_TYPE_API;
864   }
865
866   /**
867    * @return the summaryByEntityTypeCountApi
868    */
869   public static String getSummaryByEntityTypeCountApi() {
870     return SUMMARY_BY_ENTITY_TYPE_COUNT_API;
871   }
872
873   /**
874    * @return the valueAnykey
875    */
876   public static String getValueAnykey() {
877     return VALUE_ANYKEY;
878   }
879
880   /**
881    * @return the valueQuery
882    */
883   public static String getValueQuery() {
884     return VALUE_QUERY;
885   }
886
887   /**
888    * @return the keyHashId
889    */
890   public static String getKeyHashId() {
891     return KEY_HASH_ID;
892   }
893
894   /**
895    * @return the keyGroupBy
896    */
897   public static String getKeyGroupBy() {
898     return KEY_GROUP_BY;
899   }
900
901   /**
902    * @return the keySearchResult
903    */
904   public static String getKeySearchResult() {
905     return KEY_SEARCH_RESULT;
906   }
907
908   /**
909    * @return the keyHits
910    */
911   public static String getKeyHits() {
912     return KEY_HITS;
913   }
914
915   /**
916    * @return the keyPayload
917    */
918   public static String getKeyPayload() {
919     return KEY_PAYLOAD;
920   }
921
922   /**
923    * @return the keyDocument
924    */
925   public static String getKeyDocument() {
926     return KEY_DOCUMENT;
927   }
928
929   /**
930    * @return the keyContent
931    */
932   public static String getKeyContent() {
933     return KEY_CONTENT;
934   }
935
936   /**
937    * @return the keySearchTagIds
938    */
939   public static String getKeySearchTagIds() {
940     return KEY_SEARCH_TAG_IDS;
941   }
942
943   /**
944    * @return the keySearchTags
945    */
946   public static String getKeySearchTags() {
947     return KEY_SEARCH_TAGS;
948   }
949
950   /**
951    * @return the keyLink
952    */
953   public static String getKeyLink() {
954     return KEY_LINK;
955   }
956
957   /**
958    * @return the keyEntityType
959    */
960   public static String getKeyEntityType() {
961     return KEY_ENTITY_TYPE;
962   }
963
964   /**
965    * @return the viSuggestionRoute
966    */
967   public static String getViSuggestionRoute() {
968     return VI_SUGGESTION_ROUTE;
969   }
970
971   /**
972    * @return the viuiSearchTemplate
973    */
974   public static String getViuiSearchTemplate() {
975     return VIUI_SEARCH_TEMPLATE;
976   }
977
978
979
980 }