2 * ============LICENSE_START===================================================
3 * SPARKY (AAI UI service)
4 * ============================================================================
5 * Copyright © 2017 AT&T Intellectual Property.
6 * Copyright © 2017 Amdocs
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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=====================================================
22 * ECOMP and OpenECOMP are trademarks
23 * and service marks of AT&T Intellectual Property.
25 package org.onap.aai.sparky.search;
27 import java.util.HashMap;
28 import java.util.List;
30 import java.util.Map.Entry;
32 import java.util.TreeMap;
34 import javax.servlet.http.HttpServletRequest;
36 import org.apache.camel.Exchange;
37 import org.onap.aai.cl.api.Logger;
38 import org.onap.aai.cl.eelf.LoggerFactory;
39 import org.onap.aai.sparky.logging.AaiUiMsgs;
40 import org.onap.aai.sparky.logging.util.ServletUtils;
41 import org.onap.aai.sparky.search.api.SearchProvider;
42 import org.onap.aai.sparky.search.entity.QuerySearchEntity;
43 import org.onap.aai.sparky.search.entity.SearchSuggestion;
44 import org.onap.aai.sparky.search.registry.SearchProviderRegistry;
45 import org.onap.aai.sparky.util.NodeUtils;
47 import com.fasterxml.jackson.databind.ObjectMapper;
49 public class UnifiedSearchProcessor {
51 protected static final String HASH_ID_KEY = "hashId";
53 private static final Logger LOG =
54 LoggerFactory.getInstance().getLogger(UnifiedSearchProcessor.class);
56 protected SearchProviderRegistry searchProviderRegistry;
57 protected ObjectMapper mapper;
58 protected boolean useOrderedSearchProviderKeys;
60 public UnifiedSearchProcessor() {
61 mapper = new ObjectMapper();
62 this.useOrderedSearchProviderKeys = false;
65 public boolean isUseOrderedSearchProviderKeys() {
66 return useOrderedSearchProviderKeys;
69 public void setUseOrderedSearchProviderKeys(boolean useOrderedSearchProviderKeys) {
70 this.useOrderedSearchProviderKeys = useOrderedSearchProviderKeys;
73 public void search(Exchange exchange) {
74 HttpServletRequest request = exchange.getIn().getBody(HttpServletRequest.class);
75 ServletUtils.setUpMdcContext(exchange, request);
77 SearchResponse searchResponse = new SearchResponse();
78 long processTime = System.currentTimeMillis();
83 String payload = exchange.getIn().getBody(String.class);
85 if (payload == null || payload.isEmpty()) {
87 LOG.error(AaiUiMsgs.SEARCH_SERVLET_ERROR, "Request Payload is empty");
88 exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 404);
93 QuerySearchEntity searchRequest = mapper.readValue(payload, QuerySearchEntity.class);
94 int maxResultsPerSearch = Integer.valueOf(searchRequest.getMaxResults());
96 Map<String, List<SearchSuggestion>> searchProviderSuggestions =
97 new HashMap<String, List<SearchSuggestion>>();
99 int totalSuggestionsFromProviders = 0;
100 List<SearchSuggestion> suggestions = null;
101 for (SearchProvider searchProvider : searchProviderRegistry.getSearchProviders()) {
102 suggestions = searchProvider.search(searchRequest);
103 totalSuggestionsFromProviders += suggestions.size();
104 searchProviderSuggestions.put(searchProvider.getClass().getCanonicalName(), suggestions);
108 * Using ordered search provider keys allows us to deterministically calculate how many
109 * results from each provider should be returned. At the moment, this behavior is primarily
110 * only beneficial to test classes. As there is a cost to sorted-collections in the call
111 * processing path, this behavior has been made optional.
114 if (useOrderedSearchProviderKeys) {
115 searchProviderSuggestions =
116 new TreeMap<String, List<SearchSuggestion>>(searchProviderSuggestions);
119 if (totalSuggestionsFromProviders > 0) {
121 int suggestionIndex = 0;
123 Set<Entry<String, List<SearchSuggestion>>> searchProviderResults =
124 searchProviderSuggestions.entrySet();
126 while (totalAdded < maxResultsPerSearch && (totalAdded < totalSuggestionsFromProviders)) {
128 for (Entry<String, List<SearchSuggestion>> searchProviderResultList : searchProviderResults) {
130 if ((suggestionIndex <= (searchProviderResultList.getValue().size() - 1))) {
132 if (totalAdded < maxResultsPerSearch) {
134 .addSuggestion(searchProviderResultList.getValue().get(suggestionIndex));
149 searchResponse.addToTotalFound(totalAdded);
151 processTime = System.currentTimeMillis() - processTime;
152 searchResponse.setProcessingTimeInMs(processTime);
153 String searchResponseJson = NodeUtils.convertObjectToJson(searchResponse, true);
154 exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 200);
155 exchange.getOut().setBody(searchResponseJson);
157 } catch (Exception exc) {
158 LOG.error(AaiUiMsgs.ERROR_PROCESSING_REQUEST, exc);
160 exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 500);
161 exchange.getOut().setBody(
162 ServletUtils.generateJsonErrorResponse("Processing error = " + exc.getMessage()),
167 * Restore the txnId + appId from the current thread local via the MdcContext
170 ServletUtils.getTxnHeaders().forEach((key, value) -> {
171 exchange.getOut().setHeader(key, value);
174 exchange.getOut().setHeader("RequestUrl", request.getRequestURI());
175 exchange.getOut().setHeader("RequestPort", request.getLocalPort());
180 public SearchProviderRegistry getSearchProviderRegistry() {
181 return searchProviderRegistry;
184 public void setSearchProviderRegistry(SearchProviderRegistry searchProviderRegistry) {
185 this.searchProviderRegistry = searchProviderRegistry;