2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017-2018 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
12 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.aai.sparky.search;
23 import java.util.HashMap;
24 import java.util.List;
26 import java.util.Map.Entry;
28 import java.util.TreeMap;
30 import javax.servlet.http.HttpServletRequest;
32 import org.apache.camel.Exchange;
33 import org.onap.aai.cl.api.Logger;
34 import org.onap.aai.cl.eelf.LoggerFactory;
35 import org.onap.aai.sparky.logging.AaiUiMsgs;
36 import org.onap.aai.sparky.logging.util.ServletUtils;
37 import org.onap.aai.sparky.search.api.SearchProvider;
38 import org.onap.aai.sparky.search.entity.QuerySearchEntity;
39 import org.onap.aai.sparky.search.entity.SearchSuggestion;
40 import org.onap.aai.sparky.search.registry.SearchProviderRegistry;
41 import org.onap.aai.sparky.util.NodeUtils;
43 import com.fasterxml.jackson.databind.ObjectMapper;
45 public class UnifiedSearchProcessor {
47 protected static final String HASH_ID_KEY = "hashId";
49 private static final Logger LOG =
50 LoggerFactory.getInstance().getLogger(UnifiedSearchProcessor.class);
52 protected SearchProviderRegistry searchProviderRegistry;
53 protected ObjectMapper mapper;
54 protected boolean useOrderedSearchProviderKeys;
56 public UnifiedSearchProcessor() {
57 mapper = new ObjectMapper();
58 this.useOrderedSearchProviderKeys = false;
61 public boolean isUseOrderedSearchProviderKeys() {
62 return useOrderedSearchProviderKeys;
65 public void setUseOrderedSearchProviderKeys(boolean useOrderedSearchProviderKeys) {
66 this.useOrderedSearchProviderKeys = useOrderedSearchProviderKeys;
69 public void search(Exchange exchange) {
70 HttpServletRequest request = exchange.getIn().getBody(HttpServletRequest.class);
71 ServletUtils.setUpMdcContext(exchange, request);
73 SearchResponse searchResponse = new SearchResponse();
74 long processTime = System.currentTimeMillis();
79 String payload = exchange.getIn().getBody(String.class);
81 if (payload == null || payload.isEmpty()) {
83 LOG.error(AaiUiMsgs.SEARCH_SERVLET_ERROR, "Request Payload is empty");
84 exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 404);
89 QuerySearchEntity searchRequest = mapper.readValue(payload, QuerySearchEntity.class);
90 int maxResultsPerSearch = Integer.valueOf(searchRequest.getMaxResults());
92 Map<String, List<SearchSuggestion>> searchProviderSuggestions =
93 new HashMap<String, List<SearchSuggestion>>();
95 int totalSuggestionsFromProviders = 0;
96 List<SearchSuggestion> suggestions = null;
97 for (SearchProvider searchProvider : searchProviderRegistry.getSearchProviders()) {
98 suggestions = searchProvider.search(searchRequest);
99 totalSuggestionsFromProviders += suggestions.size();
100 searchProviderSuggestions.put(searchProvider.getClass().getCanonicalName(), suggestions);
104 * Using ordered search provider keys allows us to deterministically calculate how many
105 * results from each provider should be returned. At the moment, this behavior is primarily
106 * only beneficial to test classes. As there is a cost to sorted-collections in the call
107 * processing path, this behavior has been made optional.
110 if (useOrderedSearchProviderKeys) {
111 searchProviderSuggestions =
112 new TreeMap<String, List<SearchSuggestion>>(searchProviderSuggestions);
115 if (totalSuggestionsFromProviders > 0) {
117 int suggestionIndex = 0;
119 Set<Entry<String, List<SearchSuggestion>>> searchProviderResults =
120 searchProviderSuggestions.entrySet();
122 while (totalAdded < maxResultsPerSearch && (totalAdded < totalSuggestionsFromProviders)) {
124 for (Entry<String, List<SearchSuggestion>> searchProviderResultList : searchProviderResults) {
126 if ((suggestionIndex <= (searchProviderResultList.getValue().size() - 1))) {
128 if (totalAdded < maxResultsPerSearch) {
130 .addSuggestion(searchProviderResultList.getValue().get(suggestionIndex));
145 searchResponse.addToTotalFound(totalAdded);
147 processTime = System.currentTimeMillis() - processTime;
148 searchResponse.setProcessingTimeInMs(processTime);
149 String searchResponseJson = NodeUtils.convertObjectToJson(searchResponse, true);
150 exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 200);
151 exchange.getOut().setBody(searchResponseJson);
153 } catch (Exception exc) {
154 LOG.error(AaiUiMsgs.ERROR_PROCESSING_REQUEST, exc);
156 exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 500);
157 exchange.getOut().setBody(
158 ServletUtils.generateJsonErrorResponse("Processing error = " + exc.getMessage()),
163 * Restore the txnId + appId from the current thread local via the MdcContext
166 ServletUtils.getTxnHeaders().forEach((key, value) -> {
167 exchange.getOut().setHeader(key, value);
170 exchange.getOut().setHeader("RequestUrl", request.getRequestURI());
171 exchange.getOut().setHeader("RequestPort", request.getLocalPort());
176 public SearchProviderRegistry getSearchProviderRegistry() {
177 return searchProviderRegistry;
180 public void setSearchProviderRegistry(SearchProviderRegistry searchProviderRegistry) {
181 this.searchProviderRegistry = searchProviderRegistry;